filterevolution_v2.cpp 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/***************************************************************************
            filter_evolution_v2.cxx  -  Evolution 2.0.x mail import
                             -------------------
    begin                : Januar 26 2005
    copyright            : (C) 2005 by Danny Kukawka <danny.kukawka@web.de>
                           (inspired and partly copied from filter_evolution)
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "filterevolution_v2.h"

#include <KLocalizedString>
#include <qfiledialog.h>
#include <QTemporaryFile>

using namespace MailImporter;

/** Default constructor. */
Laurent Montel's avatar
Laurent Montel committed
27 28 29 30 31 32 33 34 35
FilterEvolution_v2::FilterEvolution_v2()
    : Filter(i18n("Import Evolution 2.x Local Mails and Folder Structure"),
             QStringLiteral("Danny Kukawka"),
             i18n("<p><b>Evolution 2.x import filter</b></p>"
                  "<p>Select the base directory of your local Evolution mailfolder (usually ~/.evolution/mail/local/).</p>"
                  "<p><b>Note:</b> Never choose a Folder which <u>does not</u> contain mbox-files (for example "
                  "a maildir): if you do, you will get many new folders.</p>"
                  "<p>Since it is possible to recreate the folder structure, the folders "
                  "will be stored under: \"Evolution-Import\".</p>"))
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
{
}

/** Destructor. */
FilterEvolution_v2::~FilterEvolution_v2()
{
}

QString FilterEvolution_v2::defaultSettingsPath()
{
    return QDir::homePath() + QLatin1String("/.evolution/mail/local");
}

/** Recursive import of Evolution's mboxes. */
void FilterEvolution_v2::import()
{
52
    clearCountDuplicate();
53 54 55 56 57 58 59 60 61 62 63
    /**
    * We ask the user to choose Evolution's root directory.
    * This should be usually ~/.evolution/mail/local/
    */
    QString evolDir = defaultSettingsPath();
    QDir d(evolDir);
    if (!d.exists()) {
        evolDir = QDir::homePath();
    }

    // Select directory from where I have to import files
Laurent Montel's avatar
Laurent Montel committed
64
    const QString maildir = QFileDialog::getExistingDirectory(nullptr, QString(), evolDir);
65 66 67 68 69 70 71
    if (!maildir.isEmpty()) {
        importMails(maildir);
    }
}

bool FilterEvolution_v2::excludeFiles(const QString &file)
{
Laurent Montel's avatar
Laurent Montel committed
72 73 74 75 76
    if ((file.endsWith(QLatin1String(".db"))
         || file.endsWith(QLatin1String(".cmeta"))
         || file.endsWith(QLatin1String(".ev-summary"))
         || file.endsWith(QLatin1String(".ibex.index"))
         || file.endsWith(QLatin1String(".ibex.index.data")))) {
77 78 79 80 81 82 83
        return true;
    }
    return false;
}

void FilterEvolution_v2::importMails(const QString &maildir)
{
84
    if (maildir.isEmpty()) {
85 86 87
        filterInfo()->alert(i18n("No directory selected."));
        return;
    }
88
    setMailDir(maildir);
89 90 91 92
    /**
    * If the user only select homedir no import needed because
    * there should be no files and we surely import wrong files.
    */
93
    if (mailDir() == QDir::homePath() || mailDir() == (QDir::homePath() + QLatin1Char('/'))) {
94 95 96 97 98 99 100 101 102 103 104 105 106 107
        filterInfo()->addErrorLogEntry(i18n("No files found for import."));
    } else {
        filterInfo()->setOverall(0);

        /** Recursive import of the MailArchives */
        QDir dir(mailDir());
        const QStringList rootSubDirs = dir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Dirs, QDir::Name); // Removal of . and ..
        int currentDir = 1, numSubDirs = rootSubDirs.size();
        QStringList::ConstIterator endFilename(rootSubDirs.constEnd());
        for (QStringList::ConstIterator filename = rootSubDirs.constBegin(); filename != endFilename; ++filename, ++currentDir) {
            if (filterInfo()->shouldTerminate()) {
                break;
            }
            importDirContents(dir.filePath(*filename), *filename, *filename);
Laurent Montel's avatar
Laurent Montel committed
108
            filterInfo()->setOverall((int)((float)currentDir / numSubDirs * 100));
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
        }

        /** import last but not least all archives from the root-dir */
        QDir importDir(mailDir());
        const QStringList files = importDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Files, QDir::Name);
        endFilename = files.constEnd();
        for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != endFilename; ++mailFile) {
            if (filterInfo()->shouldTerminate()) {
                break;
            }
            QString temp_mailfile = *mailFile;
            if (!excludeFiles(temp_mailfile)) {
                filterInfo()->addInfoLogEntry(i18n("Start import file %1...", temp_mailfile));
                importMBox(mailDir() + temp_mailfile, temp_mailfile, QString());
            }
        }

        filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", mailDir()));
        if (countDuplicates() > 0) {
            filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported", "%1 duplicate messages not imported", countDuplicates()));
        }
        if (filterInfo()->shouldTerminate()) {
            filterInfo()->addInfoLogEntry(i18n("Finished import, canceled by user."));
        }
    }
    filterInfo()->setCurrent(100);
    filterInfo()->setOverall(100);
}

/**
 * Import of a directory contents.
 * @param info Information storage for the operation.
 * @param dirName The name of the directory to import.
 * @param KMailRootDir The directory's root directory in KMail's folder structure.
 * @param KMailSubDir The directory's direct ancestor in KMail's folder structure.
 */
void FilterEvolution_v2::importDirContents(const QString &dirName, const QString &KMailRootDir, const QString &KMailSubDir)
{
    if (filterInfo()->shouldTerminate()) {
        return;
    }

    /** Here Import all archives in the current dir */
    QDir dir(dirName);

    QDir importDir(dirName);
    const QStringList files = importDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Files, QDir::Name);
    QStringList::ConstIterator mailFileEnd(files.constEnd());
    for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != mailFileEnd; ++mailFile) {
        QString temp_mailfile = *mailFile;
        if (!excludeFiles(temp_mailfile)) {
            filterInfo()->addInfoLogEntry(i18n("Start import file %1...", temp_mailfile));
            importMBox((dirName + QLatin1Char('/') + temp_mailfile), KMailRootDir, KMailSubDir);
        }
    }

    /** If there are subfolders, we import them one by one */
    QDir subfolders(dirName);
    const QStringList subDirs = subfolders.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Dirs, QDir::Name);
    QStringList::ConstIterator end(subDirs.constEnd());
    for (QStringList::ConstIterator filename = subDirs.constBegin(); filename != end; ++filename) {
        QString kSubDir;
        if (!KMailSubDir.isNull()) {
            kSubDir = KMailSubDir + QLatin1Char('/') + *filename;
        } else {
            kSubDir = *filename;
        }
        importDirContents(subfolders.filePath(*filename), KMailRootDir, kSubDir);
    }
}

/**
 * Import of a MBox file.
 * @param info Information storage for the operation.
 * @param dirName The MBox's name.
 * @param KMailRootDir The directory's root directory in KMail's folder structure.
 * @param KMailSubDir The directory's equivalent in KMail's folder structure. *
 */
void FilterEvolution_v2::importMBox(const QString &mboxName, const QString &rootDir, const QString &targetDir)
{
    QFile mbox(mboxName);
    if (!mbox.open(QIODevice::ReadOnly)) {
        filterInfo()->alert(i18n("Unable to open %1, skipping", mboxName));
    } else {
193
        bool first_msg = true;
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
        QFileInfo filenameInfo(mboxName);

        filterInfo()->setCurrent(0);
        if (mboxName.length() > 20) {
            QString tmp_info = mboxName;
            tmp_info = tmp_info.replace(mailDir(), QStringLiteral("../"));
            if (tmp_info.contains(QStringLiteral(".sbd"))) {
                tmp_info.remove(QStringLiteral(".sbd"));
            }
            filterInfo()->setFrom(tmp_info);
        } else {
            filterInfo()->setFrom(mboxName);
        }

        if (targetDir.contains(QStringLiteral(".sbd"))) {
            QString tmp_info = targetDir;
            tmp_info.remove(QStringLiteral(".sbd"));
            filterInfo()->setTo(tmp_info);
        } else {
            filterInfo()->setTo(targetDir);
        }

        QByteArray input(MAX_LINE, '\0');
        long l = 0;

        while (!mbox.atEnd()) {
            QTemporaryFile tmp;
            tmp.open();
            /** @todo check if the file is really a mbox, maybe search for 'from' string at start */
            /* comment by Danny:
            * Don't use QTextStream to read from mbox, better use QDataStream. QTextStream only
            * support Unicode/Latin1/Locale. So you lost information from emails with
            * charset!=Unicode/Latin1/Locale (e.g. KOI8-R) and Content-Transfer-Encoding != base64
            * (e.g. 8Bit). It also not help to convert the QTextStream to Unicode. By this you
            * get Unicode/UTF-email but KMail can't detect the correct charset.
            */
            QByteArray separate;

            if (!first_msg) {
233
                tmp.write(input.constData(), l);
234 235
            }
            l = mbox.readLine(input.data(), MAX_LINE); // read the first line, prevent "From "
236
            tmp.write(input.constData(), l);
237

Laurent Montel's avatar
Laurent Montel committed
238
            while (!mbox.atEnd() && (l = mbox.readLine(input.data(), MAX_LINE)) && ((separate = input.data()).left(5) != "From ")) {
239
                tmp.write(input.constData(), l);
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
            }
            tmp.flush();
            first_msg = false;

            QString destFolder;
            QString _targetDir = targetDir;
            if (!targetDir.isNull()) {
                if (_targetDir.contains(QStringLiteral(".sbd"))) {
                    _targetDir.remove(QStringLiteral(".sbd"));
                }
                destFolder += QStringLiteral("Evolution-Import/") + _targetDir + QLatin1Char('/') + filenameInfo.completeBaseName(); // mboxName;
            } else {
                destFolder = QStringLiteral("Evolution-Import/") + rootDir;
                if (destFolder.contains(QStringLiteral(".sbd"))) {
                    destFolder.remove(QStringLiteral(".sbd"));
                }
            }

Laurent Montel's avatar
Laurent Montel committed
258
            importMessage(destFolder, tmp.fileName(), filterInfo()->removeDupMessage());
259

Laurent Montel's avatar
Laurent Montel committed
260
            int currentPercentage = (int)(((float)mbox.pos() / filenameInfo.size()) * 100);
261 262 263 264 265 266 267 268
            filterInfo()->setCurrent(currentPercentage);
            if (filterInfo()->shouldTerminate()) {
                break;
            }
        }
        mbox.close();
    }
}