You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/kmailcvt/filter_pmail.cpp

347 lines
12 KiB

/***************************************************************************
FilterPMail.cpp - 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 <config.h>
#include <tdelocale.h>
#include <tdefiledialog.h>
#include <tqregexp.h>
#include <tdetempfile.h>
#include <kdebug.h>
#include "filter_pmail.h"
FilterPMail::FilterPMail() :
Filter(i18n("Import Folders From Pegasus-Mail"),
"Holger Schurig <br>( rewritten by Danny Kukawka )",
i18n("<p>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</p>"
"<p><b>Note:</b> Since it is possible to recreate the folder structure, the folders "
"will be stored under: \"PegasusMail-Import\".</p>"))
{}
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: <ur
// ...
// 000cb0 2d 2d 2d 2d 2d 2d 2d 2d 2d 2b 0d 0a 1a 52 65 74 ---------+...Ret
// 000cc0 75 72 6e 2d 50 61 74 68 3a 20 3c 62 6f 75 6e 63 urn-Path: <bounc
// ...
// 04dc50 46 30 33 38 44 2e 36 31 35 44 37 34 44 30 2d 2d F038D.615D74D0--
// 04dc60 0d 0a 1a
struct {
char folder[86];
char id[42];
} pmm_head;
long l = 0;
TQFile f(file);
if (!f.open(IO_ReadOnly)) {
inf->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;
}