MailImporter

filterevolution_v2.cpp
1/*
2 filterevolution_v2.cpp - Evolution 2.0.x mail import
3
4 SPDX-FileCopyrightText: 2005 Danny Kukawka <danny.kukawka@web.de>
5
6 Inspired and partly copied from filterevolution
7 SPDX-FileCopyrightText: 2004 Simon MARTIN <simartin@users.sourceforge.net>
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10*/
11
12#include "filterevolution_v2.h"
13
14#include <KLocalizedString>
15#include <QFileDialog>
16#include <QTemporaryFile>
17
18using namespace MailImporter;
19
20/** Default constructor. */
22 : Filter(i18n("Import Evolution 2.x Local Mails and Folder Structure"),
23 QStringLiteral("Danny Kukawka"),
24 i18n("<p><b>Evolution 2.x import filter</b></p>"
25 "<p>Select the base directory of your local Evolution mailfolder (usually ~/.evolution/mail/local/).</p>"
26 "<p><b>Note:</b> Never choose a Folder which <u>does not</u> contain mbox-files (for example "
27 "a maildir): if you do, you will get many new folders.</p>"
28 "<p>Since it is possible to recreate the folder structure, the folders "
29 "will be stored under: \"Evolution-Import\".</p>"))
30{
31}
32
33/** Destructor. */
37
38QString FilterEvolution_v2::isMailerFound()
39{
40 QDir directory(FilterEvolution_v2::defaultSettingsPath());
41 if (directory.exists()) {
42 return i18nc("name of evolution application", "Evolution (v2)");
43 }
44 return {};
45}
46
47QString FilterEvolution_v2::defaultSettingsPath()
48{
49 return QDir::homePath() + QLatin1StringView("/.evolution/mail/local");
50}
51
52/** Recursive import of Evolution's mboxes. */
54{
55 clearCountDuplicate();
56 /**
57 * We ask the user to choose Evolution's root directory.
58 * This should be usually ~/.evolution/mail/local/
59 */
60 QString evolDir = defaultSettingsPath();
61 QDir d(evolDir);
62 if (!d.exists()) {
63 evolDir = QDir::homePath();
64 }
65
66 // Select directory from where I have to import files
67 const QString maildir = QFileDialog::getExistingDirectory(nullptr, QString(), evolDir);
68 if (!maildir.isEmpty()) {
69 importMails(maildir);
70 }
71}
72
73bool FilterEvolution_v2::excludeFiles(const QString &file)
74{
75 if ((file.endsWith(QLatin1StringView(".db")) || file.endsWith(QLatin1StringView(".cmeta")) || file.endsWith(QLatin1StringView(".ev-summary"))
76 || file.endsWith(QLatin1StringView(".ibex.index")) || file.endsWith(QLatin1StringView(".ibex.index.data")))) {
77 return true;
78 }
79 return false;
80}
81
83{
84 if (maildir.isEmpty()) {
85 filterInfo()->alert(i18n("No directory selected."));
86 return;
87 }
88 setMailDir(maildir);
89 /**
90 * If the user only select homedir no import needed because
91 * there should be no files and we surely import wrong files.
92 */
93 if (mailDir() == QDir::homePath() || mailDir() == (QDir::homePath() + QLatin1Char('/'))) {
94 filterInfo()->addErrorLogEntry(i18n("No files found for import."));
95 } else {
96 filterInfo()->setOverall(0);
97
98 /** Recursive import of the MailArchives */
99 QDir dir(mailDir());
100 const QStringList rootSubDirs = dir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Dirs, QDir::Name); // Removal of . and ..
101 int currentDir = 1;
102 int numSubDirs = rootSubDirs.size();
103 QStringList::ConstIterator endFilename(rootSubDirs.constEnd());
104 for (QStringList::ConstIterator filename = rootSubDirs.constBegin(); filename != endFilename; ++filename, ++currentDir) {
105 if (filterInfo()->shouldTerminate()) {
106 break;
107 }
108 importDirContents(dir.filePath(*filename), *filename, *filename);
109 filterInfo()->setOverall((int)((float)currentDir / numSubDirs * 100));
110 }
111
112 /** import last but not least all archives from the root-dir */
113 QDir importDir(mailDir());
114 const QStringList files = importDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Files, QDir::Name);
115 endFilename = files.constEnd();
116 for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != endFilename; ++mailFile) {
117 if (filterInfo()->shouldTerminate()) {
118 break;
119 }
120 QString temp_mailfile = *mailFile;
121 if (!excludeFiles(temp_mailfile)) {
122 filterInfo()->addInfoLogEntry(i18n("Start import file %1...", temp_mailfile));
123 importMBox(mailDir() + temp_mailfile, temp_mailfile, QString());
124 }
125 }
126
127 filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", mailDir()));
128 if (countDuplicates() > 0) {
129 filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported", "%1 duplicate messages not imported", countDuplicates()));
130 }
131 if (filterInfo()->shouldTerminate()) {
132 filterInfo()->addInfoLogEntry(i18n("Finished import, canceled by user."));
133 }
134 }
135 filterInfo()->setCurrent(100);
136 filterInfo()->setOverall(100);
137}
138
139/**
140 * Import of a directory contents.
141 * @param info Information storage for the operation.
142 * @param dirName The name of the directory to import.
143 * @param KMailRootDir The directory's root directory in KMail's folder structure.
144 * @param KMailSubDir The directory's direct ancestor in KMail's folder structure.
145 */
146void FilterEvolution_v2::importDirContents(const QString &dirName, const QString &KMailRootDir, const QString &KMailSubDir)
147{
148 if (filterInfo()->shouldTerminate()) {
149 return;
150 }
151
152 /** Here Import all archives in the current dir */
153 QDir dir(dirName);
154
155 QDir importDir(dirName);
156 const QStringList files = importDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Files, QDir::Name);
157 QStringList::ConstIterator mailFileEnd(files.constEnd());
158 for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != mailFileEnd; ++mailFile) {
159 QString temp_mailfile = *mailFile;
160 if (!excludeFiles(temp_mailfile)) {
161 filterInfo()->addInfoLogEntry(i18n("Start import file %1...", temp_mailfile));
162 importMBox((dirName + QLatin1Char('/') + temp_mailfile), KMailRootDir, KMailSubDir);
163 }
164 }
165
166 /** If there are subfolders, we import them one by one */
167 QDir subfolders(dirName);
168 const QStringList subDirs = subfolders.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Dirs, QDir::Name);
170 for (QStringList::ConstIterator filename = subDirs.constBegin(); filename != end; ++filename) {
171 QString kSubDir;
172 if (!KMailSubDir.isNull()) {
173 kSubDir = KMailSubDir + QLatin1Char('/') + *filename;
174 } else {
175 kSubDir = *filename;
176 }
177 importDirContents(subfolders.filePath(*filename), KMailRootDir, kSubDir);
178 }
179}
180
181/**
182 * Import of a MBox file.
183 * @param info Information storage for the operation.
184 * @param dirName The MBox's name.
185 * @param KMailRootDir The directory's root directory in KMail's folder structure.
186 * @param KMailSubDir The directory's equivalent in KMail's folder structure. *
187 */
188void FilterEvolution_v2::importMBox(const QString &mboxName, const QString &rootDir, const QString &targetDir)
189{
190 QFile mbox(mboxName);
191 if (!mbox.open(QIODevice::ReadOnly)) {
192 filterInfo()->alert(i18n("Unable to open %1, skipping", mboxName));
193 } else {
194 bool first_msg = true;
195 QFileInfo filenameInfo(mboxName);
196
197 filterInfo()->setCurrent(0);
198 if (mboxName.length() > 20) {
199 QString tmp_info = mboxName;
200 tmp_info.replace(mailDir(), QStringLiteral("../"));
201 if (tmp_info.contains(QLatin1StringView(".sbd"))) {
202 tmp_info.remove(QStringLiteral(".sbd"));
203 }
204 filterInfo()->setFrom(tmp_info);
205 } else {
206 filterInfo()->setFrom(mboxName);
207 }
208
209 if (targetDir.contains(QLatin1StringView(".sbd"))) {
210 QString tmp_info = targetDir;
211 tmp_info.remove(QStringLiteral(".sbd"));
212 filterInfo()->setTo(tmp_info);
213 } else {
214 filterInfo()->setTo(targetDir);
215 }
216
217 QByteArray input(MAX_LINE, '\0');
218 long l = 0;
219
220 while (!mbox.atEnd()) {
221 QTemporaryFile tmp;
222 tmp.open();
223 /** @todo check if the file is really a mbox, maybe search for 'from' string at start */
224 /* comment by Danny:
225 * Don't use QTextStream to read from mbox, better use QDataStream. QTextStream only
226 * support Unicode/Latin1/Locale. So you lost information from emails with
227 * charset!=Unicode/Latin1/Locale (e.g. KOI8-R) and Content-Transfer-Encoding != base64
228 * (e.g. 8Bit). It also not help to convert the QTextStream to Unicode. By this you
229 * get Unicode/UTF-email but KMail can't detect the correct charset.
230 */
231 QByteArray separate;
232
233 if (!first_msg) {
234 tmp.write(input.constData(), l);
235 }
236 l = mbox.readLine(input.data(), MAX_LINE); // read the first line, prevent "From "
237 tmp.write(input.constData(), l);
238
239 while (!mbox.atEnd() && (l = mbox.readLine(input.data(), MAX_LINE)) && ((separate = input.data()).left(5) != "From ")) {
240 tmp.write(input.constData(), l);
241 }
242 tmp.flush();
243 first_msg = false;
244
245 QString destFolder;
246 QString _targetDir = targetDir;
247 if (!targetDir.isNull()) {
248 if (_targetDir.contains(QLatin1StringView(".sbd"))) {
249 _targetDir.remove(QStringLiteral(".sbd"));
250 }
251 destFolder += QStringLiteral("Evolution-Import/") + _targetDir + QLatin1Char('/') + filenameInfo.completeBaseName(); // mboxName;
252 } else {
253 destFolder = QStringLiteral("Evolution-Import/") + rootDir;
254 if (destFolder.contains(QLatin1StringView(".sbd"))) {
255 destFolder.remove(QStringLiteral(".sbd"));
256 }
257 }
258
259 if (!importMessage(destFolder, tmp.fileName(), filterInfo()->removeDupMessage())) {
260 filterInfo()->addErrorLogEntry(i18n("Could not import %1", tmp.fileName()));
261 }
262
263 int currentPercentage = (int)(((float)mbox.pos() / filenameInfo.size()) * 100);
264 filterInfo()->setCurrent(currentPercentage);
265 if (filterInfo()->shouldTerminate()) {
266 break;
267 }
268 }
269 mbox.close();
270 }
271}
void importMails(const QString &maildir)
~FilterEvolution_v2() override
Destructor.
void import() override
Recursive import of Evolution's mboxes.
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...)
const QList< QKeySequence > & end()
QStringList entryList(Filters filters, SortFlags sort) const const
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 endsWith(QChar c, 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.