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>
22 #include <ktemporaryfile.h>
25 #include "filter_pmail.h"
27 using namespace MailImporter
;
29 FilterPMail::FilterPMail() :
30 Filter(i18n("Import Folders From Pegasus-Mail"),
31 i18n("Holger Schurig <br>( rewritten by Danny Kukawka )"),
32 i18n("<p>Select the Pegasus-Mail directory on your system (containing *.CNM, *.PMM and *.MBX files). "
33 "On many systems this is stored in C:\\pmail\\mail or C:\\pmail\\mail\\admin</p>"
34 "<p><b>Note:</b> Since it is possible to recreate the folder structure, the folders "
35 "will be stored under: \"PegasusMail-Import\".</p>"))
38 FilterPMail::~FilterPMail()
42 void FilterPMail::import()
44 // Select directory from where I have to import files
45 QPointer
<KFileDialog
> kfd
= new KFileDialog( QDir::homePath(), QString(), 0 );
46 kfd
->setMode(KFile::Directory
| KFile::LocalOnly
);
48 const QString maildir
= kfd
->selectedFile();
50 importMails( maildir
);
55 void FilterPMail::importMails( const QString
&chosenDir
)
57 setMailDir( chosenDir
);
58 if (mailDir().isEmpty()) {
59 filterInfo()->alert(i18n("No directory selected."));
63 // Count total number of files to be processed
64 filterInfo()->addInfoLogEntry(i18n("Counting files..."));
65 dir
.setPath (mailDir());
66 const QStringList files
= dir
.entryList(QStringList()<<QLatin1String("*.[cC][nN][mM]")<<QLatin1String("*.[pP][mM][mM]")<<QLatin1String("*.[mM][bB][xX]"), QDir::Files
, QDir::Name
);
67 totalFiles
= files
.count();
69 kDebug() <<"Count is" << totalFiles
;
71 if(!(folderParsed
= parseFolderMatrix(mailDir()))) {
72 filterInfo()->addErrorLogEntry(i18n("Cannot parse the folder structure; continuing import without subfolder support."));
75 filterInfo()->addInfoLogEntry(i18n("Importing new mail files ('.cnm')..."));
76 processFiles(QLatin1String("*.[cC][nN][mM]"), &FilterPMail::importNewMessage
);
77 filterInfo()->addInfoLogEntry(i18n("Importing mail folders ('.pmm')..."));
78 processFiles(QLatin1String("*.[pP][mM][mM]"), &FilterPMail::importMailFolder
);
79 filterInfo()->addInfoLogEntry(i18n("Importing 'UNIX' mail folders ('.mbx')..."));
80 processFiles(QLatin1String("*.[mM][bB][xX]"), &FilterPMail::importUnixMailFolder
);
82 filterInfo()->addInfoLogEntry( i18n("Finished importing emails from %1", mailDir() ));
83 filterInfo()->setCurrent(100);
84 filterInfo()->setOverall(100);
87 /** this looks for all files with the filemask 'mask' and calls the 'workFunc' on each of them */
88 void FilterPMail::processFiles(const QString
&mask
, void(FilterPMail::* workFunc
)(const QString
&) )
90 if (filterInfo()->shouldTerminate())
93 const QStringList files
= dir
.entryList(QStringList(mask
), QDir::Files
, QDir::Name
);
94 //kDebug() <<"Mask is" << mask <<" count is" << files.count();
95 QStringList::ConstIterator end
= files
.constEnd();
96 for ( QStringList::ConstIterator mailFile
= files
.constBegin(); mailFile
!= end
; ++mailFile
) {
97 // Notify current file
98 QFileInfo
mailfilem_filterInfoo(*mailFile
);
99 filterInfo()->setFrom(mailfilem_filterInfoo
.fileName());
101 // Clear the other fields
102 filterInfo()->setTo(QString());
103 filterInfo()->setCurrent(QString());
104 filterInfo()->setCurrent(-1);
106 // call worker function, increase progressbar
107 (this->*workFunc
)(dir
.filePath(*mailFile
));
109 filterInfo()->setOverall( (int) ((float) currentFile
/ totalFiles
* 100));
110 filterInfo()->setCurrent( 100 );
111 if (filterInfo()->shouldTerminate()) return;
116 /** this function imports one *.CNM message */
117 void FilterPMail::importNewMessage(const QString
&file
)
119 QString
destFolder(QLatin1String("PegasusMail-Import/New Messages"));
120 filterInfo()->setTo(destFolder
);
122 /* comment by Danny Kukawka:
123 * addMessage() == old function, need more time and check for duplicates
124 * addMessage_fastImport == new function, faster and no check for duplicates
126 if(filterInfo()->removeDupMessage())
127 addMessage( destFolder
, file
);
129 addMessage_fastImport( destFolder
, file
);
133 /** this function imports one mail folder file (*.PMM) */
134 void FilterPMail::importMailFolder(const QString
&file
)
136 // Format of a PMM file:
137 // First comes a header with 128 bytes. At the beginning is the name of
138 // the folder. Then there are some unknown bytes (strings). At offset 128
139 // the first message starts.
141 // Each message is terminated by a 0x1A byte. The next message follows
144 // The last message is followed by a 0x1A, too.
146 // 000000 6d 61 69 6c 73 65 72 76 65 72 2d 70 72 6f 6a 65 mailserver-proje
147 // 000010 63 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ct..............
148 // 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
149 // 000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
150 // 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
151 // 000050 00 00 00 00 00 00 36 30 34 37 35 37 32 45 3a 36 ......6047572E:6
152 // 000060 46 34 39 3a 46 4f 4c 30 31 33 35 35 00 00 00 00 F49:FOL01355....
153 // 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
154 // 000080 52 65 74 75 72 6e 2d 50 61 74 68 3a 20 3c 75 72 Return-Path: <ur
156 // 000cb0 2d 2d 2d 2d 2d 2d 2d 2d 2d 2b 0d 0a 1a 52 65 74 ---------+...Ret
157 // 000cc0 75 72 6e 2d 50 61 74 68 3a 20 3c 62 6f 75 6e 63 urn-Path: <bounc
159 // 04dc50 46 30 33 38 44 2e 36 31 35 44 37 34 44 30 2d 2d F038D.615D74D0--
169 if (!f
.open(QIODevice::ReadOnly
)) {
170 filterInfo()->alert(i18n("Unable to open %1, skipping", file
));
173 l
= f
.read((char *) &pmm_head
, sizeof(pmm_head
));
174 QString
folder(i18nc("define folder name when we will import pegasus mail","PegasusMail-Import") + QLatin1Char('/'));
176 folder
.append(getFolderName(QString::fromLatin1(pmm_head
.id
)));
178 folder
.append(QString::fromLatin1(pmm_head
.folder
));
179 filterInfo()->setTo(folder
);
180 filterInfo()->addInfoLogEntry(i18n("Importing %1", QString::fromLatin1("../") + QString::fromLatin1(pmm_head
.folder
)));
182 QByteArray
input(MAX_LINE
,'\0');
183 bool first_msg
= true;
186 KTemporaryFile tempfile
;
188 filterInfo()->setCurrent( (int) ( ( (float) f
.pos() / f
.size() ) * 100 ) );
191 // set the filepos back to last line minus the separate char (0x1a)
192 f
.seek(f
.pos() - l
+ 1);
195 // no problem to loose the last line in file. This only contains a separate char
196 while ( ! f
.atEnd() && (l
= f
.readLine(input
.data(),MAX_LINE
))) {
197 if (filterInfo()->shouldTerminate()){
200 if ( input
.at( 0 ) == 0x1a ) {
203 tempfile
.write( input
, l
);
208 if(filterInfo()->removeDupMessage())
209 addMessage( folder
, tempfile
.fileName() );
211 addMessage_fastImport( folder
, tempfile
.fileName() );
220 /** imports a 'unix' format mail folder (*.MBX) */
221 void FilterPMail::importUnixMailFolder(const QString
&file
)
229 QString
folder(QLatin1String("PegasusMail-Import/")), s(file
), separate
;
230 QByteArray
line(MAX_LINE
,'\0');
233 /** Get the folder name */
234 s
.replace( QRegExp(QLatin1String("mbx$")), QLatin1String("pmg"));
235 s
.replace( QRegExp(QLatin1String("MBX$")), QLatin1String("PMG"));
237 if (! f
.open( QIODevice::ReadOnly
) ) {
238 filterInfo()->alert( i18n("Unable to open %1, skipping", s
) );
241 f
.read((char *) &pmg_head
, sizeof(pmg_head
));
245 folder
.append(getFolderName(QString::fromLatin1(pmg_head
.id
)));
247 folder
.append(QString::fromLatin1(pmg_head
.folder
));
249 filterInfo()->setTo(folder
);
250 filterInfo()->setTo(folder
);
253 /** Read in the mbox */
255 if (! f
.open( QIODevice::ReadOnly
) ) {
256 filterInfo()->alert( i18n("Unable to open %1, skipping", s
) );
258 filterInfo()->addInfoLogEntry(i18n("Importing %1", QLatin1String("../") + QString::fromLatin1(pmg_head
.folder
)));
259 l
= f
.readLine( line
.data(),MAX_LINE
); // read the first line which is unneeded
260 while ( ! f
.atEnd() ) {
261 KTemporaryFile tempfile
;
264 // we lost the last line, which is the first line of the new message in
265 // this lopp, but this is ok, because this is the separate line with
266 // "From ???@???" and we can forget them
267 while ( ! f
.atEnd() && (l
= f
.readLine(line
.data(),MAX_LINE
)) &&((separate
= QString::fromLatin1(line
.data())).left(5) != QLatin1String("From "))) {
268 tempfile
.write(line
.data(), l
);
269 if (filterInfo()->shouldTerminate()){
274 if(filterInfo()->removeDupMessage())
275 addMessage( folder
, tempfile
.fileName() );
277 addMessage_fastImport( folder
, tempfile
.fileName() );
280 filterInfo()->setCurrent(i18n("Message %1", n
));
281 filterInfo()->setCurrent( (int) ( ( (float) f
.pos() / f
.size() ) * 100 ) );
287 /** Parse the m_filterInfoormation about folderstructure to folderMatrix */
288 bool FilterPMail::parseFolderMatrix( const QString
&chosendir
)
290 kDebug() <<"Start parsing the foldermatrix.";
291 filterInfo()->addInfoLogEntry(i18n("Parsing the folder structure..."));
293 QFile
hierarch(chosendir
+ QLatin1String("/hierarch.pm"));
294 if (! hierarch
.open( QIODevice::ReadOnly
) ) {
295 filterInfo()->alert( i18n("Unable to open %1, skipping",chosendir
+ QLatin1String("hierarch.pm") ) );
300 while ( !hierarch
.atEnd() ) {
301 tmpRead
= hierarch
.readLine();
302 if ( tmpRead
.isEmpty() )
305 tmpRead
.remove(tmpRead
.length() -2,2);
306 QStringList tmpList
= QString::fromLatin1(tmpRead
).split(QLatin1Char(','), QString::SkipEmptyParts
);
308 QStringList::ConstIterator
end( tmpList
.constEnd() );
309 for ( QStringList::ConstIterator it
= tmpList
.constBegin(); it
!= end
; ++it
, ++i
) {
311 if(i
< 5) tmpArray
[i
] = _tmp
.remove(QLatin1Char('\"'));
317 folderMatrix
.append(FolderStructure(tmpArray
));
324 /** get the foldername for a given file ID from folderMatrix */
325 QString
FilterPMail::getFolderName(const QString
&ID
)
333 FolderStructureIterator
end( folderMatrix
.end() );
334 for ( FolderStructureIterator it
= folderMatrix
.begin(); it
!= end
; ++it
) {
335 FolderStructure tmp
= *it
;
337 QString _ID
= tmp
[2];
339 QString _type
= tmp
[0] + tmp
[1];
340 if(( _type
== QLatin1String("21"))) {
345 folder
.prepend((tmp
[4] + QLatin1Char('/')));