1
/***************************************************************************
2
FilterPMail.cxx - Pegasus-Mail import
5
copyright : (C) 2001 by Holger Schurig <holgerschurig@gmx.de>
6
(C) 2005 by Danny Kukawka <danny.kukawka@web.de>
7
***************************************************************************/
9
/***************************************************************************
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
***************************************************************************/
19
#include <kfiledialog.h>
21
#include <ktemporaryfile.h>
24
#include "filter_pmail.hxx"
27
FilterPMail::FilterPMail() :
28
Filter(i18n("Import Folders From Pegasus-Mail"),
29
"Holger Schurig <br>( rewritten by Danny Kukawka )",
30
i18n("<p>Select the Pegasus-Mail directory on your system (containing *.CNM, *.PMM and *.MBX files). "
31
"On many systems this is stored in C:\\pmail\\mail or C:\\pmail\\mail\\admin</p>"
32
"<p><b>Note:</b> Since it is possible to recreate the folder structure, the folders "
33
"will be stored under: \"PegasusMail-Import\".</p>"))
36
FilterPMail::~FilterPMail()
40
void FilterPMail::import(FilterInfo *info)
44
// Select directory from where I have to import files
46
kfd = new KFileDialog( QDir::homePath(), "", 0 );
47
kfd->setMode(KFile::Directory | KFile::LocalOnly);
49
chosenDir = kfd->selectedFile();
51
if (chosenDir.isEmpty()) {
52
info->alert(i18n("No directory selected."));
56
// Count total number of files to be processed
57
info->addLog(i18n("Counting files..."));
58
dir.setPath (chosenDir);
59
const QStringList files = dir.entryList(QStringList("*.[cC][nN][mM]")<<"*.[pP][mM][mM]"<<"*.[mM][bB][xX]", QDir::Files, QDir::Name);
60
totalFiles = files.count();
62
kDebug() <<"Count is" << totalFiles;
64
if(!(folderParsed = parseFolderMatrix())) {
65
info->addLog(i18n("Cannot parse the folder structure; continuing import without subfolder support."));
68
info->addLog(i18n("Importing new mail files ('.cnm')..."));
69
processFiles("*.[cC][nN][mM]", &FilterPMail::importNewMessage);
70
info->addLog(i18n("Importing mail folders ('.pmm')..."));
71
processFiles("*.[pP][mM][mM]", &FilterPMail::importMailFolder);
72
info->addLog(i18n("Importing 'UNIX' mail folders ('.mbx')..."));
73
processFiles("*.[mM][bB][xX]", &FilterPMail::importUnixMailFolder);
75
info->addLog( i18n("Finished importing emails from %1", chosenDir ));
76
info->setCurrent(100);
77
info->setOverall(100);
80
/** this looks for all files with the filemask 'mask' and calls the 'workFunc' on each of them */
81
void FilterPMail::processFiles(const QString& mask, void(FilterPMail::* workFunc)(const QString&) )
83
if (inf->shouldTerminate()) return;
85
const QStringList files = dir.entryList(QStringList(mask), QDir::Files, QDir::Name);
86
//kDebug() <<"Mask is" << mask <<" count is" << files.count();
87
for ( QStringList::ConstIterator mailFile = files.constBegin(); mailFile != files.constEnd(); ++mailFile ) {
88
// Notify current file
89
QFileInfo mailfileinfo(*mailFile);
90
inf->setFrom(mailfileinfo.fileName());
92
// Clear the other fields
93
inf->setTo(QString());
94
inf->setCurrent(QString());
97
// call worker function, increase progressbar
98
(this->*workFunc)(dir.filePath(*mailFile));
100
inf->setOverall( (int) ((float) currentFile / totalFiles * 100));
101
inf->setCurrent( 100 );
102
if (inf->shouldTerminate()) return;
107
/** this function imports one *.CNM message */
108
void FilterPMail::importNewMessage(const QString& file)
110
QString destFolder("PegasusMail-Import/New Messages");
111
inf->setTo(destFolder);
113
/* comment by Danny Kukawka:
114
* addMessage() == old function, need more time and check for duplicates
115
* addMessage_fastImport == new function, faster and no check for duplicates
117
if(inf->removeDupMsg)
118
addMessage( inf, destFolder, file );
120
addMessage_fastImport( inf, destFolder, file );
124
/** this function imports one mail folder file (*.PMM) */
125
void FilterPMail::importMailFolder(const QString& file)
127
// Format of a PMM file:
128
// First comes a header with 128 bytes. At the beginning is the name of
129
// the folder. Then there are some unknown bytes (strings). At offset 128
130
// the first message starts.
132
// Each message is terminated by a 0x1A byte. The next message follows
135
// The last message is followed by a 0x1A, too.
137
// 000000 6d 61 69 6c 73 65 72 76 65 72 2d 70 72 6f 6a 65 mailserver-proje
138
// 000010 63 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ct..............
139
// 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
140
// 000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
141
// 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
142
// 000050 00 00 00 00 00 00 36 30 34 37 35 37 32 45 3a 36 ......6047572E:6
143
// 000060 46 34 39 3a 46 4f 4c 30 31 33 35 35 00 00 00 00 F49:FOL01355....
144
// 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
145
// 000080 52 65 74 75 72 6e 2d 50 61 74 68 3a 20 3c 75 72 Return-Path: <ur
147
// 000cb0 2d 2d 2d 2d 2d 2d 2d 2d 2d 2b 0d 0a 1a 52 65 74 ---------+...Ret
148
// 000cc0 75 72 6e 2d 50 61 74 68 3a 20 3c 62 6f 75 6e 63 urn-Path: <bounc
150
// 04dc50 46 30 33 38 44 2e 36 31 35 44 37 34 44 30 2d 2d F038D.615D74D0--
160
if (!f.open(QIODevice::ReadOnly)) {
161
inf->alert(i18n("Unable to open %1, skipping", file));
164
l = f.read((char *) &pmm_head, sizeof(pmm_head));
165
QString folder("PegasusMail-Import/");
167
folder.append(getFolderName((QString)pmm_head.id));
169
folder.append(pmm_head.folder);
171
inf->addLog(i18n("Importing %1", QString("../") + QString(pmm_head.folder)));
173
QByteArray input(MAX_LINE,'\0');
174
bool first_msg = true;
177
KTemporaryFile tempfile;
179
inf->setCurrent( (int) ( ( (float) f.pos() / f.size() ) * 100 ) );
182
// set the filepos back to last line minus the separate char (0x1a)
183
f.seek(f.pos() - l + 1);
186
// no problem to loose the last line in file. This only contains a separate char
187
while ( ! f.atEnd() && (l = f.readLine(input.data(),MAX_LINE))) {
188
if (inf->shouldTerminate()){
191
if ( input.at( 0 ) == 0x1a ) {
194
tempfile.write( input, l );
199
if(inf->removeDupMsg)
200
addMessage( inf, folder, tempfile.fileName() );
202
addMessage_fastImport( inf, folder, tempfile.fileName() );
211
/** imports a 'unix' format mail folder (*.MBX) */
212
void FilterPMail::importUnixMailFolder(const QString& file)
220
QString folder("PegasusMail-Import/"), s(file), separate;
221
QByteArray line(MAX_LINE,'\0');
224
/** Get the folder name */
225
s.replace( QRegExp("mbx$"), "pmg");
226
s.replace( QRegExp("MBX$"), "PMG");
228
if (! f.open( QIODevice::ReadOnly ) ) {
229
inf->alert( i18n("Unable to open %1, skipping", s ) );
232
f.read((char *) &pmg_head, sizeof(pmg_head));
236
folder.append(getFolderName((QString)pmg_head.id));
238
folder.append(pmg_head.folder);
244
/** Read in the mbox */
246
if (! f.open( QIODevice::ReadOnly ) ) {
247
inf->alert( i18n("Unable to open %1, skipping", s ) );
249
inf->addLog(i18n("Importing %1", QString("../") + QString(pmg_head.folder)));
250
l = f.readLine( line.data(),MAX_LINE); // read the first line which is unneeded
251
while ( ! f.atEnd() ) {
252
KTemporaryFile tempfile;
255
// we lost the last line, which is the first line of the new message in
256
// this lopp, but this is ok, because this is the separate line with
257
// "From ???@???" and we can forget them
258
while ( ! f.atEnd() && (l = f.readLine(line.data(),MAX_LINE)) && ((separate = line.data()).left(5) != "From ")) {
259
tempfile.write(line.data(), l);
260
if (inf->shouldTerminate()){
265
if(inf->removeDupMsg)
266
addMessage( inf, folder, tempfile.fileName() );
268
addMessage_fastImport( inf, folder, tempfile.fileName() );
271
inf->setCurrent(i18n("Message %1", n));
272
inf->setCurrent( (int) ( ( (float) f.pos() / f.size() ) * 100 ) );
278
/** Parse the information about folderstructure to folderMatrix */
279
bool FilterPMail::parseFolderMatrix()
281
kDebug() <<"Start parsing the foldermatrix.";
282
inf->addLog(i18n("Parsing the folder structure..."));
284
QFile hierarch(chosenDir + "/hierarch.pm");
285
if (! hierarch.open( QIODevice::ReadOnly ) ) {
286
inf->alert( i18n("Unable to open %1, skipping", chosenDir + "hierarch.pm" ) );
291
while ( !hierarch.atEnd() ) {
292
tmpRead = hierarch.readLine();
293
if ( tmpRead.isEmpty() )
296
tmpRead.remove(tmpRead.length() -2,2);
297
QStringList tmpList = QString(tmpRead).split(',', QString::SkipEmptyParts);
299
for ( QStringList::Iterator it = tmpList.begin(); it != tmpList.end(); ++it, i++) {
301
if(i < 5) tmpArray[i] = _tmp.remove('\"');
307
folderMatrix.append(FolderStructure(tmpArray));
314
/** get the foldername for a given file ID from folderMatrix */
315
QString FilterPMail::getFolderName(QString ID)
323
for ( FolderStructureIterator it = folderMatrix.begin(); it != folderMatrix.end(); ++it) {
324
FolderStructure tmp = *it;
326
QString _ID = tmp[2];
328
QString _type = tmp[0] + tmp[1];
329
if(( _type == "21")) {
334
folder.prepend((tmp[4] + '/'));