MailImporter

filterevolution.cpp
1/*
2 SPDX-FileCopyrightText: 2004 Simon MARTIN <simartin@users.sourceforge.net>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "filterevolution.h"
8
9#include <KLocalizedString>
10#include <QFileDialog>
11#include <QTemporaryFile>
12
13using namespace MailImporter;
14
15/** Default constructor. */
17 : Filter(i18n("Import Evolution 1.x Local Mails and Folder Structure"),
18 i18n("Simon MARTIN<br /><br />( Filter accelerated by Danny Kukawka )"),
19 i18n("<p><b>Evolution 1.x import filter</b></p>"
20 "<p>Select the base directory of Evolution's mails (usually ~/evolution/local).</p>"
21 "<p>Since it is possible to recreate the folder structure, the folders "
22 "will be stored under: \"Evolution-Import\".</p>"))
23{
24}
25
26/** Destructor. */
30
31QString FilterEvolution::isMailerFound()
32{
33 QDir directory(FilterEvolution::defaultSettingsPath());
34 if (directory.exists()) {
35 return i18nc("name of evolution application", "Evolution");
36 }
37 return {};
38}
39
40QString FilterEvolution::defaultSettingsPath()
41{
42 return QDir::homePath() + QLatin1StringView("/evolution/local");
43}
44
45/** Recursive import of Evolution's mboxes. */
47{
48 // We ask the user to choose Evolution's root directory.
49 QString evolDir = defaultSettingsPath();
50 QDir d(evolDir);
51 if (!d.exists()) {
52 evolDir = QDir::homePath();
53 }
54 importMails(QFileDialog::getExistingDirectory(filterInfo()->parentWidget(), QString(), evolDir));
55}
56
58{
59 if (maildir.isEmpty()) {
60 filterInfo()->alert(i18n("No directory selected."));
61 return;
62 }
63 setMailDir(maildir);
64 /**
65 * If the user only select homedir no import needed because
66 * there should be no files and we surely import wrong files.
67 */
68 if (mailDir() == QDir::homePath() || mailDir() == (QDir::homePath() + QLatin1Char('/'))) {
69 filterInfo()->addErrorLogEntry(i18n("No files found for import."));
70 } else {
71 filterInfo()->setOverall(0);
72 // Recursive import of the MBoxes.
73 QDir dir(mailDir());
74 const QStringList rootSubDirs = dir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Dirs, QDir::Name); // Removal of . and ..
75 int currentDir = 1;
76 int numSubDirs = rootSubDirs.size();
77 QStringList::ConstIterator end(rootSubDirs.constEnd());
78 for (QStringList::ConstIterator filename = rootSubDirs.constBegin(); filename != end; ++filename, ++currentDir) {
79 importDirContents(dir.filePath(*filename), *filename, QString());
80 filterInfo()->setOverall((int)((float)currentDir / numSubDirs * 100));
81 }
82 }
83 filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", mailDir()));
84 filterInfo()->setCurrent(100);
85 filterInfo()->setOverall(100);
86}
87
88/**
89 * Import of a directory contents.
90 * @param info Information storage for the operation.
91 * @param dirName The name of the directory to import.
92 * @param KMailRootDir The directory's root directory in KMail's folder structure.
93 * @param KMailSubDir The directory's direct ancestor in KMail's folder structure.
94 */
95void FilterEvolution::importDirContents(const QString &dirName, const QString &KMailRootDir, const QString &KMailSubDir)
96{
97 // If there is a mbox, we import it
98 QDir dir(dirName);
99 if (dir.exists(QStringLiteral("mbox"))) {
100 importMBox(dirName + QLatin1StringView("/mbox"), KMailRootDir, KMailSubDir);
101 }
102 // If there are subfolders, we import them one by one
103 if (dir.exists(QStringLiteral("subfolders"))) {
104 QDir subfolders(dirName + QLatin1StringView("/subfolders"));
105 const QStringList subDirs = subfolders.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Dirs, QDir::Name);
107
108 for (QStringList::ConstIterator filename = subDirs.constBegin(); filename != end; ++filename) {
109 QString kSubDir;
110 if (!KMailSubDir.isNull()) {
111 kSubDir = KMailSubDir + QLatin1Char('/') + *filename;
112 } else {
113 kSubDir = *filename;
114 }
115 importDirContents(subfolders.filePath(*filename), KMailRootDir, kSubDir);
116 }
117 }
118}
119
120/**
121 * Import of a MBox file.
122 * @param info Information storage for the operation.
123 * @param dirName The MBox's name.
124 * @param KMailRootDir The directory's root directory in KMail's folder structure.
125 * @param KMailSubDir The directory's equivalent in KMail's folder structure. *
126 */
127void FilterEvolution::importMBox(const QString &mboxName, const QString &rootDir, const QString &targetDir)
128{
129 QFile mbox(mboxName);
130 QString tmp_from = mboxName;
131 if (!mbox.open(QIODevice::ReadOnly)) {
132 filterInfo()->alert(i18n("Unable to open %1, skipping", mboxName));
133 } else {
134 bool first_msg = true;
135 QFileInfo filenameInfo(mboxName);
136
137 filterInfo()->setCurrent(0);
138 if (mboxName.length() > 20) {
139 QString tmp_info = mboxName;
140 tmp_info.replace(mailDir(), QStringLiteral(".."));
141 if (tmp_info.contains(QLatin1StringView("subfolders/"))) {
142 tmp_info.remove(QStringLiteral("subfolders/"));
143 }
144 filterInfo()->setFrom(tmp_info);
145 tmp_from = tmp_info;
146 } else {
147 filterInfo()->setFrom(mboxName);
148 }
149 if (targetDir.contains(QLatin1StringView("subfolders/"))) {
150 QString tmp_info = targetDir;
151 tmp_info.remove(QStringLiteral("subfolders/"));
152 filterInfo()->setTo(tmp_info);
153 } else {
154 filterInfo()->setTo(targetDir);
155 }
156
157 filterInfo()->addInfoLogEntry(i18n("Importing emails from %1...", tmp_from));
158
159 QByteArray input(MAX_LINE, '\0');
160 long l = 0;
161
162 while (!mbox.atEnd()) {
163 QTemporaryFile tmp;
164 tmp.open();
165 /* comment by Danny:
166 * Don't use QTextStream to read from mbox, better use QDataStream. QTextStream only
167 * support Unicode/Latin1/Locale. So you lost information from emails with
168 * charset!=Unicode/Latin1/Locale (e.g. KOI8-R) and Content-Transfer-Encoding != base64
169 * (e.g. 8Bit). It also not help to convert the QTextStream to Unicode. By this you
170 * get Unicode/UTF-email but KMail can't detect the correct charset.
171 */
172 QByteArray separate;
173
174 if (!first_msg) {
175 tmp.write(input.constData(), l);
176 }
177 l = mbox.readLine(input.data(), MAX_LINE); // read the first line, prevent "From "
178 tmp.write(input.constData(), l);
179
180 while (!mbox.atEnd() && (l = mbox.readLine(input.data(), MAX_LINE)) && ((separate = input.data()).left(5) != "From ")) {
181 tmp.write(input.constData(), l);
182 }
183 tmp.flush();
184 first_msg = false;
185
186 QString destFolder = rootDir;
187 if (!targetDir.isNull()) {
188 destFolder = QLatin1StringView("Evolution-Import/") + destFolder + QLatin1Char('/') + targetDir;
189 } else {
190 destFolder = QLatin1StringView("Evolution-Import/") + destFolder;
191 }
192
193 if (!importMessage(destFolder, tmp.fileName(), filterInfo()->removeDupMessage())) {
194 filterInfo()->addErrorLogEntry(i18n("Could not import %1", tmp.fileName()));
195 }
196
197 const int currentPercentage = (int)(((float)mbox.pos() / filenameInfo.size()) * 100);
198 filterInfo()->setCurrent(currentPercentage);
199 if (filterInfo()->shouldTerminate()) {
200 return;
201 }
202 }
203
204 if (countDuplicates() > 0) {
205 filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported", "%1 duplicate messages not imported", countDuplicates()));
206 }
207 clearCountDuplicate();
208 mbox.close();
209 }
210}
~FilterEvolution() override
Destructor.
FilterEvolution()
Default constructor.
void import() override
Recursive import of Evolution's mboxes.
void importMails(const QString &maildir)
The Filter class.
Definition filters.h:29
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
bool exists() const const
QString homePath()
bool flush()
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, Options options)
qint64 write(const QByteArray &data)
typedef ConstIterator
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype size() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isNull() const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
virtual QString fileName() const const override
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:39 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.