/*************************************************************************** FilterPMail.cxx - Pegasus-Mail import ------------------- begin : Sat Jan 6 2001 copyright : (C) 2001 by Holger Schurig (C) 2005 by Danny Kukawka email : holgerschurig@gmx.de danny.kukawka@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include "filter_pmail.hxx" FilterPMail::FilterPMail() : Filter(i18n("Import Folders From Pegasus-Mail"), "Holger Schurig
( rewritten by Danny Kukawka )", i18n("

Select the Pegasus-Mail directory on your system (containing *.CNM, *.PMM and *.MBX files). " "On many systems this is stored in C:\\pmail\\mail or C:\\pmail\\mail\\admin

" "

Note: Since it is possible to recreate the folder structure, the folders " "will be stored under: \"PegasusMail-Import\".

")) {} FilterPMail::~FilterPMail() { } void FilterPMail::import(FilterInfo *info) { inf = info; // Select directory from where I have to import files KFileDialog *kfd; kfd = new KFileDialog( TQDir::homeDirPath(), "", 0, "tdefiledialog", true ); kfd->setMode(KFile::Directory | KFile::LocalOnly); kfd->exec(); chosenDir = kfd->selectedFile(); delete kfd; if (chosenDir.isEmpty()) { info->alert(i18n("No directory selected.")); return; } // Count total number of files to be processed info->addLog(i18n("Counting files...")); dir.setPath (chosenDir); TQStringList files = dir.entryList("*.[cC][nN][mM]; *.[pP][mM][mM]; *.[mM][bB][xX]", TQDir::Files, TQDir::Name); totalFiles = files.count(); currentFile = 0; kdDebug() << "Count is " << totalFiles << endl; if(!(folderParsed = parseFolderMatrix())) { info->addLog(i18n("Cannot parse the folder structure; continuing import without subfolder support.")); } info->addLog(i18n("Importing new mail files ('.cnm')...")); processFiles("*.[cC][nN][mM]", &FilterPMail::importNewMessage); info->addLog(i18n("Importing mail folders ('.pmm')...")); processFiles("*.[pP][mM][mM]", &FilterPMail::importMailFolder); info->addLog(i18n("Importing 'UNIX' mail folders ('.mbx')...")); processFiles("*.[mM][bB][xX]", &FilterPMail::importUnixMailFolder); info->addLog( i18n("Finished importing emails from %1").arg( chosenDir )); info->setCurrent(100); info->setOverall(100); } /** this looks for all files with the filemask 'mask' and calls the 'workFunc' on each of them */ void FilterPMail::processFiles(const TQString& mask, void(FilterPMail::* workFunc)(const TQString&) ) { if (inf->shouldTerminate()) return; TQStringList files = dir.entryList(mask, TQDir::Files, TQDir::Name); //kdDebug() << "Mask is " << mask << " count is " << files.count() << endl; for ( TQStringList::Iterator mailFile = files.begin(); mailFile != files.end(); ++mailFile ) { // Notify current file TQFileInfo mailfileinfo(*mailFile); inf->setFrom(mailfileinfo.fileName()); // Clear the other fields inf->setTo(TQString()); inf->setCurrent(TQString()); inf->setCurrent(-1); // call worker function, increase progressbar (this->*workFunc)(dir.filePath(*mailFile)); ++currentFile; inf->setOverall( (int) ((float) currentFile / totalFiles * 100)); inf->setCurrent( 100 ); if (inf->shouldTerminate()) return; } } /** this function imports one *.CNM message */ void FilterPMail::importNewMessage(const TQString& file) { TQString destFolder("PegasusMail-Import/New Messages"); inf->setTo(destFolder); /* comment by Danny Kukawka: * addMessage() == old function, need more time and check for duplicates * addMessage_fastImport == new function, faster and no check for duplicates */ if(inf->removeDupMsg) addMessage( inf, destFolder, file ); else addMessage_fastImport( inf, destFolder, file ); } /** this function imports one mail folder file (*.PMM) */ void FilterPMail::importMailFolder(const TQString& file) { // Format of a PMM file: // First comes a header with 128 bytes. At the beginning is the name of // the folder. Then there are some unknown bytes (strings). At offset 128 // the first message starts. // // Each message is terminated by a 0x1A byte. The next message follows // immediately. // // The last message is followed by a 0x1A, too. // // 000000 6d 61 69 6c 73 65 72 76 65 72 2d 70 72 6f 6a 65 mailserver-proje // 000010 63 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ct.............. // 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ // 000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ // 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ // 000050 00 00 00 00 00 00 36 30 34 37 35 37 32 45 3a 36 ......6047572E:6 // 000060 46 34 39 3a 46 4f 4c 30 31 33 35 35 00 00 00 00 F49:FOL01355.... // 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ // 000080 52 65 74 75 72 6e 2d 50 61 74 68 3a 20 3c 75 72 Return-Path: alert(i18n("Unable to open %1, skipping").arg(file)); } else { // Get folder name l = f.readBlock((char *) &pmm_head, sizeof(pmm_head)); TQString folder("PegasusMail-Import/"); if(folderParsed) folder.append(getFolderName((TQString)pmm_head.id)); else folder.append(pmm_head.folder); inf->setTo(folder); inf->addLog(i18n("Importing %1").arg("../" + TQString(pmm_head.folder))); TQByteArray input(MAX_LINE); bool first_msg = true; while (!f.atEnd()) { KTempFile tempfile; inf->setCurrent( (int) ( ( (float) f.at() / f.size() ) * 100 ) ); if(!first_msg) { // set the filepos back to last line minus the seperate char (0x1a) f.at(f.at() - l + 1); } // no problem to loose the last line in file. This only contains a seperate char while ( ! f.atEnd() && (l = f.readLine(input.data(),MAX_LINE))) { if (inf->shouldTerminate()){ tempfile.close(); tempfile.unlink(); return; } if(input[0] == 0x1a ) { break; } else { tempfile.file()->writeBlock( input, l ); } } tempfile.close(); if(inf->removeDupMsg) addMessage( inf, folder, tempfile.name() ); else addMessage_fastImport( inf, folder, tempfile.name() ); first_msg = false; tempfile.unlink(); } } f.close(); } /** imports a 'unix' format mail folder (*.MBX) */ void FilterPMail::importUnixMailFolder(const TQString& file) { struct { char folder[58]; char id[31]; } pmg_head; TQFile f; TQString folder("PegasusMail-Import/"), s(file), seperate; TQByteArray line(MAX_LINE); int n = 0, l = 0; /** Get the folder name */ s.replace( TQRegExp("mbx$"), "pmg"); s.replace( TQRegExp("MBX$"), "PMG"); f.setName(s); if (! f.open( IO_ReadOnly ) ) { inf->alert( i18n("Unable to open %1, skipping").arg( s ) ); return; } else { f.readBlock((char *) &pmg_head, sizeof(pmg_head)); f.close(); if(folderParsed) folder.append(getFolderName((TQString)pmg_head.id)); else folder.append(pmg_head.folder); inf->setTo(folder); inf->setTo(folder); } /** Read in the mbox */ f.setName(file); if (! f.open( IO_ReadOnly ) ) { inf->alert( i18n("Unable to open %1, skipping").arg( s ) ); } else { inf->addLog(i18n("Importing %1").arg("../" + TQString(pmg_head.folder))); l = f.readLine( line.data(),MAX_LINE); // read the first line which is unneeded while ( ! f.atEnd() ) { KTempFile tempfile; // we lost the last line, which is the first line of the new message in // this lopp, but this is ok, because this is the seperate line with // "From ???@???" and we can forget them while ( ! f.atEnd() && (l = f.readLine(line.data(),MAX_LINE)) && ((seperate = line.data()).left(5) != "From ")) { tempfile.file()->writeBlock(line.data(), l); if (inf->shouldTerminate()){ tempfile.close(); tempfile.unlink(); return; } } tempfile.close(); if(inf->removeDupMsg) addMessage( inf, folder, tempfile.name() ); else addMessage_fastImport( inf, folder, tempfile.name() ); tempfile.unlink(); n++; inf->setCurrent(i18n("Message %1").arg(n)); inf->setCurrent( (int) ( ( (float) f.at() / f.size() ) * 100 ) ); } } f.close(); } /** Parse the information about folderstructure to folderMatrix */ bool FilterPMail::parseFolderMatrix() { kdDebug() << "Start parsing the foldermatrix." << endl; inf->addLog(i18n("Parsing the folder structure...")); TQFile hierarch(chosenDir + "/hierarch.pm"); if (! hierarch.open( IO_ReadOnly ) ) { inf->alert( i18n("Unable to open %1, skipping").arg( chosenDir + "hierarch.pm" ) ); return false; } else { TQStringList tmpList; TQString tmpRead; while ( !hierarch.atEnd() && hierarch.readLine(tmpRead,100)) { TQString tmpArray[5]; tmpRead.remove(tmpRead.length() -2,2); TQStringList tmpList = TQStringList::split(",", tmpRead, false); int i = 0; for ( TQStringList::Iterator it = tmpList.begin(); it != tmpList.end(); ++it, i++) { TQString _tmp = *it; if(i < 5) tmpArray[i] = _tmp.remove("\""); else { hierarch.close(); return false; } } folderMatrix.append(tmpArray); } } hierarch.close(); return true; } /** get the foldername for a given file ID from folderMatrix */ TQString FilterPMail::getFolderName(TQString ID) { bool found = false; TQString folder; TQString search = ID; while (!found) { for ( FolderStructureIterator it = folderMatrix.begin(); it != folderMatrix.end(); it++) { FolderStructure tmp = *it; TQString _ID = tmp[2]; if(_ID == search) { TQString _type = tmp[0] + tmp[1]; if(( _type == "21")) { found = true; break; } else { folder.prepend((tmp[4] + "/")); search = tmp[3]; } } } } return folder; }