MailImporter

filterevolution_v3.cpp
1/*
2 SPDX-FileCopyrightText: 2012-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "filterevolution_v3.h"
8
9#include <KLocalizedString>
10#include <QFileDialog>
11
12using namespace MailImporter;
13
14class MailImporter::FilterEvolution_v3Private
15{
16public:
17 int mImportDirDone = -1;
18 int mTotalDir = -1;
19};
20/** Default constructor. */
22 : Filter(i18n("Import Evolution 3.x Local Mails and Folder Structure"),
23 QStringLiteral("Laurent Montel"),
24 i18n("<p><b>Evolution 3.x import filter</b></p>"
25 "<p>Select the base directory of your local Evolution mailfolder (usually ~/.local/share/evolution/mail/local/).</p>"
26 "<p>Since it is possible to recreate the folder structure, the folders "
27 "will be stored under: \"Evolution-Import\".</p>"))
28 , d(new MailImporter::FilterEvolution_v3Private)
29{
30}
31
32/** Destructor. */
34
35QString FilterEvolution_v3::isMailerFound()
36{
37 QDir directory(FilterEvolution_v3::defaultSettingsPath());
38 if (directory.exists()) {
39 return i18nc("name of evolution application", "Evolution (v3)");
40 }
41 return {};
42}
43
44QString FilterEvolution_v3::defaultSettingsPath()
45{
46 return QDir::homePath() + QLatin1StringView("/.local/share/evolution/mail/local/");
47}
48
49/** Recursive import of KMail maildir. */
51{
52 clearCountDuplicate();
53 QString evolDir = defaultSettingsPath();
54 QDir d(evolDir);
55 if (!d.exists()) {
56 evolDir = QDir::homePath();
57 }
58
59 const QString dir = QFileDialog::getExistingDirectory(nullptr, QString(), evolDir);
60 if (!dir.isEmpty()) {
61 importMails(dir);
62 }
63}
64
65void FilterEvolution_v3::processDirectory(const QString &path)
66{
67 QDir dir(path);
68 const QStringList rootSubDirs = dir.entryList(QStringList(QStringLiteral("*")), QDir::Dirs | QDir::Hidden, QDir::Name);
69 QStringList::ConstIterator end = rootSubDirs.constEnd();
70 for (QStringList::ConstIterator filename = rootSubDirs.constBegin(); filename != end; ++filename) {
71 if (filterInfo()->shouldTerminate()) {
72 break;
73 }
74 if (!(*filename == QLatin1Char('.') || *filename == QLatin1StringView(".."))) {
75 filterInfo()->setCurrent(0);
76 importDirContents(dir.filePath(*filename));
77 filterInfo()->setOverall((d->mTotalDir > 0) ? (int)((float)d->mImportDirDone / d->mTotalDir * 100) : 0);
78 filterInfo()->setCurrent(100);
79 }
80 }
81}
82
84{
85 if (maildir.isEmpty()) {
86 filterInfo()->alert(i18n("No directory selected."));
87 return;
88 }
89 setMailDir(maildir);
90 /**
91 * If the user only select homedir no import needed because
92 * there should be no files and we surely import wrong files.
93 */
94 if (mailDir() == QDir::homePath() || mailDir() == (QDir::homePath() + QLatin1Char('/'))) {
95 filterInfo()->addErrorLogEntry(i18n("No files found for import."));
96 } else {
97 filterInfo()->setOverall(0);
98 d->mImportDirDone = 0;
99
100 /** Recursive import of the MailArchives */
101 QDir dir(mailDir());
102 d->mTotalDir = Filter::countDirectory(dir, true /*search hidden directory*/);
103
104 processDirectory(mailDir());
105
106 filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", mailDir()));
107
108 if (countDuplicates() > 0) {
109 filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported", "%1 duplicate messages not imported", countDuplicates()));
110 }
111
112 if (filterInfo()->shouldTerminate()) {
113 filterInfo()->addInfoLogEntry(i18n("Finished import, canceled by user."));
114 }
115 }
116 filterInfo()->setCurrent(100);
117 filterInfo()->setOverall(100);
118}
119
120/**
121 * Import of a directory contents.
122 * @param info Information storage for the operation.
123 * @param dirName The name of the directory to import.
124 */
125void FilterEvolution_v3::importDirContents(const QString &dirName)
126{
127 /** Here Import all archives in the current dir */
128 importFiles(dirName);
129
130 /** If there are subfolders, we import them one by one */
131 processDirectory(dirName);
132}
133
134/**
135 * Import the files within a Folder.
136 * @param info Information storage for the operation.
137 * @param dirName The name of the directory to import.
138 */
139void FilterEvolution_v3::importFiles(const QString &dirName)
140{
141 QDir dir(dirName);
142 QString _path;
143 bool generatedPath = false;
144
145 QDir importDir(dirName);
146 const QStringList files = importDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Files, QDir::Name);
147 int currentFile = 1;
148 int numFiles = files.size();
149 QStringList::ConstIterator filesEnd(files.constEnd());
150
151 for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != filesEnd; ++mailFile, ++currentFile) {
152 if (filterInfo()->shouldTerminate()) {
153 return;
154 }
155 QString temp_mailfile = *mailFile;
156 if (!(temp_mailfile.endsWith(QLatin1StringView(".db")) || temp_mailfile.endsWith(QLatin1StringView(".cmeta"))
157 || temp_mailfile.endsWith(QLatin1StringView(".ev-summary")) || temp_mailfile.endsWith(QLatin1StringView(".ibex.index"))
158 || temp_mailfile.endsWith(QLatin1StringView(".ibex.index.data")))) {
159 if (!generatedPath) {
160 _path = i18nc("define folder name where we import evolution mails", "Evolution-Import");
161 QString _tmp = dir.filePath(*mailFile);
162 _tmp.remove(mailDir(), Qt::CaseSensitive);
163 QStringList subFList = _tmp.split(QLatin1Char('/'), Qt::SkipEmptyParts);
165 for (QStringList::ConstIterator it = subFList.constBegin(); it != end; ++it) {
166 QString _cat = *it;
167 if (!(_cat == *mailFile)) {
168 if (_cat.startsWith(QLatin1Char('.'))) {
169 _cat.remove(0, 1);
170 }
171 // Evolution store inbox as "."
172 if (_cat.startsWith(QLatin1Char('.'))) {
173 _cat.replace(0, 1, QStringLiteral("Inbox/"));
174 }
175
176 _path += QLatin1Char('/') + _cat;
177 _path.replace(QLatin1Char('.'), QLatin1Char('/'));
178 }
179 }
180 if (_path.endsWith(QLatin1StringView("cur"))) {
181 _path.remove(_path.length() - 4, 4);
182 }
183 QString _info = _path;
184 filterInfo()->addInfoLogEntry(i18n("Import folder %1...", _info));
185 filterInfo()->setFrom(_info);
186 filterInfo()->setTo(_path);
187 generatedPath = true;
188 }
189 MailImporter::MessageStatus status = statusFromFile(*mailFile);
190
191 if (!importMessage(_path, dir.filePath(*mailFile), filterInfo()->removeDupMessage(), status)) {
192 filterInfo()->addErrorLogEntry(i18n("Could not import %1", *mailFile));
193 }
194 filterInfo()->setCurrent((int)((float)currentFile / numFiles * 100));
195 }
196 }
197}
198
199MailImporter::MessageStatus FilterEvolution_v3::statusFromFile(const QString &filename)
200{
202 const int statusIndex = filename.indexOf(QLatin1StringView(":2,"));
203 if (statusIndex != -1) {
204 const QString statusStr = filename.right(filename.length() - statusIndex - 3);
205 if (statusStr.contains(QLatin1Char('S'))) {
206 status.setRead(true);
207 }
208 if (statusStr.contains(QLatin1Char('F'))) {
209 // TODO ?
210 }
211 if (statusStr.contains(QLatin1Char('R'))) {
212 status.setReplied(true);
213 }
214 if (statusStr.contains(QLatin1Char('P'))) {
215 status.setForwarded(true);
216 }
217 }
218 return status;
219}
void importMails(const QString &maildir)
void import() override
Recursive import of KMail maildir.
~FilterEvolution_v3() override
Destructor.
The Filter class.
Definition filters.h:29
The MessageStatus class.
Q_SCRIPTABLE CaptureState status()
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...)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
KIOCORE_EXPORT QString dir(const QString &fileClass)
bool exists() const const
QString homePath()
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, Options options)
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator end()
qsizetype size() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString right(qsizetype n) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
CaseSensitive
SkipEmptyParts
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 29 2024 11:54:56 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.