13#include "mailimporter_debug.h"
15#include <KLocalizedString>
18#include <QTemporaryFile>
20#define OE4_SIG_1 0x36464d4a
21#define OE4_SIG_2 0x00010003
22#define OE5_SIG_1 0xfe12adcf
23#define OE5_EMAIL_SIG_2 0x6f74fdc5
24#define OE5_FOLDER_SIG_2 0x6f74fdc6
25#define OE5_SIG_3 0x11d1e366
26#define OE5_SIG_4 0xc0004e9a
27#define MBX_MAILMAGIC 0x7F007F00
29using namespace MailImporter;
32 :
Filter(
i18n(
"Import Outlook Express Emails"),
33 i18n(
"Laurence Anderson <br>( Filter enhanced by Danny Kukawka )</p>"),
34 i18n(
"<p><b>Outlook Express 4/5/6 import filter</b></p>"
35 "<p>You will need to locate the folder where the mailbox has been "
36 "stored by searching for .dbx or .mbx files under "
37 "<ul><li><i>C:\\Windows\\Application Data</i> in Windows 9x</li>"
38 "<li><i>Documents and Settings</i> in Windows 2000 or later</li></ul></p>"
39 "<p><b>Note:</b> Since it is possible to recreate the folder structure, the folders from "
40 "Outlook Express 5 and 6 will be stored under: \"OE-Import\" in your local folder.</p>"))
48void FilterOE::import()
58 filterInfo()->alert(
i18n(
"No directory selected."));
66 filterInfo()->alert(
i18n(
"No Outlook Express mailboxes found in directory %1.", mailDir()));
70 totalFiles = files.
count();
76 filterInfo()->setOverall(0);
82 filterInfo()->addInfoLogEntry(
i18n(
"Import folder structure..."));
83 importMailBox(dir.filePath(*mailFile));
84 if (!folderStructure.isEmpty()) {
88 files.
erase(mailFile);
89 currentIsFolderFile =
false;
97 if (filterInfo()->shouldTerminate()) {
100 importMailBox(dir.filePath(*mailFile));
101 filterInfo()->setOverall(100 * ++n / files.
count());
104 filterInfo()->setOverall(100);
105 filterInfo()->setCurrent(100);
106 filterInfo()->addInfoLogEntry(
i18n(
"Finished importing Outlook Express emails"));
107 if (filterInfo()->shouldTerminate()) {
108 filterInfo()->addInfoLogEntry(
i18n(
"Finished import, canceled by user."));
111 qCDebug(MAILIMPORTER_LOG) <<
"total emails in current file:" << totalEmails;
112 qCDebug(MAILIMPORTER_LOG) <<
"0x84 Mails:" << count0x84;
113 qCDebug(MAILIMPORTER_LOG) <<
"0x04 Mails:" << count0x04;
116void FilterOE::importMailBox(
const QString &fileName)
118 QFile mailfile(fileName);
120 QString _nameOfFile = fileName;
121 _nameOfFile.
remove(mailDir());
123 filterInfo()->setFrom(mailfileinfo.fileName());
126 filterInfo()->addErrorLogEntry(
i18n(
"Unable to open mailbox %1", fileName));
135 mailbox >> sig_block1 >> sig_block2;
136 if (sig_block1 == OE4_SIG_1 && sig_block2 == OE4_SIG_2) {
138 filterInfo()->addInfoLogEntry(
i18n(
"Importing OE4 Mailbox %1", QStringLiteral(
"../") + _nameOfFile));
139 filterInfo()->setTo(folderName);
145 mailbox >> sig_block3 >> sig_block4;
146 if (sig_block1 == OE5_SIG_1 && sig_block3 == OE5_SIG_3 && sig_block4 == OE5_SIG_4) {
147 if (sig_block2 == OE5_EMAIL_SIG_2) {
150 const QString _tmpFolder = getFolderName(_nameOfFile);
155 filterInfo()->addInfoLogEntry(
i18n(
"Importing OE5+ Mailbox %1", QStringLiteral(
"../") + _nameOfFile));
156 filterInfo()->setTo(folderName);
159 }
else if (sig_block2 == OE5_FOLDER_SIG_2) {
161 filterInfo()->addInfoLogEntry(
i18n(
"Importing OE5+ Folder file %1", QStringLiteral(
"../") + _nameOfFile));
162 currentIsFolderFile =
true;
164 currentIsFolderFile =
false;
181 ds >> msgCount >> lastMsgNum >> fileSize;
183 qCDebug(MAILIMPORTER_LOG) <<
"This mailbox has" << msgCount <<
" messages";
191 while (!ds.
atEnd()) {
201 ds >> msgNumber >> msgSize >> msgTextSize;
204 if (msgMagic != MBX_MAILMAGIC) {
205 dataStream << msgMagic;
209 }
while (!ds.
atEnd());
211 if (!importMessage(folderName, tmp.
fileName(), filterInfo()->removeDupMessage())) {
212 filterInfo()->addErrorLogEntry(
i18n(
"Could not import %1", tmp.
fileName()));
215 if (filterInfo()->shouldTerminate()) {
232 qCDebug(MAILIMPORTER_LOG) <<
"Item count is" << itemCount <<
", Index at" << indexPtr;
234 if (itemCount == 0) {
237 totalEmails = itemCount;
241 dbxReadIndex(ds, indexPtr);
244void FilterOE::dbxReadIndex(
QDataStream &ds,
int filePos)
246 if (filterInfo()->shouldTerminate()) {
251 quint32 nextIndexPtr;
260 qCDebug(MAILIMPORTER_LOG) <<
"Reading index of file" << folderName;
261 ds >> self >> unknown >> nextIndexPtr >> parent >> unknown2 >> ptrCount >> unknown3 >> indexCount;
263 qCDebug(MAILIMPORTER_LOG) <<
"This index has" << (int)ptrCount <<
" data pointers";
264 for (
int count = 0; count < ptrCount; ++count) {
265 if (filterInfo()->shouldTerminate()) {
268 quint32 dataIndexPtr;
269 quint32 anotherIndexPtr;
270 quint32 anotherIndexCount;
271 ds >> dataIndexPtr >> anotherIndexPtr >> anotherIndexCount;
273 if (anotherIndexCount > 0) {
274 qCDebug(MAILIMPORTER_LOG) <<
"Recursing to another table @" << anotherIndexPtr;
275 dbxReadIndex(ds, anotherIndexPtr);
277 qCDebug(MAILIMPORTER_LOG) <<
"Data index @" << dataIndexPtr;
278 dbxReadDataBlock(ds, dataIndexPtr);
281 if (indexCount > 0) {
282 qCDebug(MAILIMPORTER_LOG) <<
"Recurring to next table @" << nextIndexPtr;
283 dbxReadIndex(ds, nextIndexPtr);
289void FilterOE::dbxReadDataBlock(
QDataStream &ds,
int filePos)
302 ds >> curOffset >> blockSize >> unknown >> count >> unknown2;
303 qCDebug(MAILIMPORTER_LOG) <<
"Data block has" << (int)count <<
" elements";
305 for (
int c = 0; c < count; c++) {
306 if (filterInfo()->shouldTerminate()) {
316 if (!currentIsFolderFile) {
318 qCDebug(MAILIMPORTER_LOG) <<
"**** Offset of emaildata (0x84)" << value <<
" ****";
319 dbxReadEmail(ds, value);
321 }
else if (type == 0x04) {
323 ds.
device()->
seek(filePos + 12 + value + (count * 4));
326 qCDebug(MAILIMPORTER_LOG) <<
"**** Offset of emaildata (0x04)" << newOFF;
328 dbxReadEmail(ds, newOFF);
335 folderEntry[0] = parseFolderOEString(ds, filePos + 12 + value + (count * 4));
336 }
else if (type == 0x03) {
338 folderEntry[1] = parseFolderOEString(ds, filePos + 12 + value + (count * 4));
339 }
else if (type == 0x80) {
342 }
else if (type == 0x81) {
348 if (currentIsFolderFile) {
349 folderStructure.append(FolderStructure(folderEntry));
354void FilterOE::dbxReadEmail(
QDataStream &ds,
int filePos)
356 if (filterInfo()->shouldTerminate()) {
360 quint32 nextAddressOffset;
361 quint32 nextAddress = 0;
373 ds >> self >> nextAddressOffset >> blockSize >> intCount >> unknown >> nextAddress;
376 tempDs.writeRawData(blockBuffer.data(), blockSize);
383 }
while (nextAddress != 0);
387 if (!importMessage(folderName, tmp.
fileName(), filterInfo()->removeDupMessage())) {
388 filterInfo()->addErrorLogEntry(
i18n(
"Could not import %1", tmp.
fileName()));
392 int currentPercentage = (int)(((
float)currentEmail / totalEmails) * 100);
393 filterInfo()->setCurrent(currentPercentage);
423 bool foundFilename =
false;
430 for (FolderStructureIterator it = folderStructure.begin(); it != folderStructure.end(); ++it) {
431 FolderStructure tmp = *it;
432 if (foundFilename ==
false) {
434 _tmpFileName = _tmpFileName.
toLower();
435 if (_tmpFileName == search) {
438 foundFilename =
true;
443 if (_currentID == search) {
455 if ((foundFilename ==
false) && (folder.
isEmpty())) {
void importMails(const QString &maildir)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
QIODevice * device() const const
int readRawData(char *s, int len)
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, Options options)
virtual bool atEnd() const const
virtual qint64 pos() const const
virtual bool seek(qint64 pos)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
iterator erase(const_iterator begin, const_iterator end)
bool isEmpty() const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & prepend(QChar ch)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString toLower() const const
virtual QString fileName() const const override