1 /*
2 filterkmail_maildir.cpp - Kmail maildir mail import
3
4 SPDX-FileCopyrightText: 2005 Danny Kukawka <danny.kukawka@web.de>
5 SPDX-FileCopyrightText: 2012-2021 Laurent Montel <montel@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "filterkmail_maildir.h"
11
12 #include <KLocalizedString>
13 #include <QFileDialog>
14
15 using namespace MailImporter;
16
17 class MailImporter::FilterKMail_maildirPrivate
18 {
19 public:
20 int mImportDirDone = 0;
21 int mTotalDir = 0;
22 };
23
24 /** Default constructor. */
FilterKMail_maildir()25 FilterKMail_maildir::FilterKMail_maildir()
26 : Filter(i18n("Import KMail Maildirs and Folder Structure"),
27 QStringLiteral("Danny Kukawka"),
28 i18n("<p><b>KMail import filter</b></p>"
29 "<p>Select the base directory of the KMail mailfolder you want to import.</p>"
30 "<p><b>Note:</b> Never select your current local KMail maildir (usually "
31 "~/Mail or ~/.kde/share/apps/kmail/mail ): in this case, ImportWizard may become stuck "
32 "in a continuous loop. </p>"
33 "<p>This filter does not import KMail mailfolders with mbox files.</p>"
34 "<p>Since it is possible to recreate the folder structure, the folders "
35 "will be stored under: \"KMail-Import\" in your local folder.</p>"))
36 , d(new MailImporter::FilterKMail_maildirPrivate)
37 {
38 }
39
40 /** Destructor. */
41 FilterKMail_maildir::~FilterKMail_maildir() = default;
42
43 /** Recursive import of KMail maildir. */
import()44 void FilterKMail_maildir::import()
45 {
46 clearCountDuplicate();
47 const QString homeDir = QDir::homePath();
48 const QString maildir = QFileDialog::getExistingDirectory(nullptr, QString(), homeDir);
49 if (!maildir.isEmpty()) {
50 importMails(maildir);
51 }
52 }
53
processDirectory(const QString & path)54 void FilterKMail_maildir::processDirectory(const QString &path)
55 {
56 QDir dir(path);
57 const QStringList rootSubDirs = dir.entryList(QStringList(QStringLiteral("*")), QDir::Dirs | QDir::Hidden, QDir::Name);
58 QStringList::ConstIterator end = rootSubDirs.constEnd();
59 for (QStringList::ConstIterator filename = rootSubDirs.constBegin(); filename != end; ++filename) {
60 if (filterInfo()->shouldTerminate()) {
61 break;
62 }
63 if (!(*filename == QLatin1Char('.') || *filename == QLatin1String(".."))) {
64 filterInfo()->setCurrent(0);
65 importDirContents(dir.filePath(*filename));
66 filterInfo()->setOverall((d->mTotalDir > 0) ? (int)((float)d->mImportDirDone / d->mTotalDir * 100) : 0);
67 filterInfo()->setCurrent(100);
68 ++d->mImportDirDone;
69 }
70 }
71 }
72
importMails(const QString & maildir)73 void FilterKMail_maildir::importMails(const QString &maildir)
74 {
75 if (maildir.isEmpty()) {
76 filterInfo()->alert(i18n("No directory selected."));
77 return;
78 }
79 setMailDir(maildir);
80 /**
81 * If the user only select homedir no import needed because
82 * there should be no files and we surely import wrong files.
83 */
84 if (mailDir() == QDir::homePath() || mailDir() == (QDir::homePath() + QLatin1Char('/'))) {
85 filterInfo()->addErrorLogEntry(i18n("No files found for import."));
86 } else {
87 filterInfo()->setOverall(0);
88 d->mImportDirDone = 0;
89
90 /** Recursive import of the MailArchives */
91 QDir dir(mailDir());
92 d->mTotalDir = Filter::countDirectory(dir, true /*search hidden directory*/);
93 processDirectory(mailDir());
94
95 filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", mailDir()));
96 if (countDuplicates() > 0) {
97 filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported", "%1 duplicate messages not imported", countDuplicates()));
98 }
99 }
100 if (filterInfo()->shouldTerminate()) {
101 filterInfo()->addInfoLogEntry(i18n("Finished import, canceled by user."));
102 }
103 filterInfo()->setCurrent(100);
104 filterInfo()->setOverall(100);
105 }
106
107 /**
108 * Import of a directory contents.
109 * @param info Information storage for the operation.
110 * @param dirName The name of the directory to import.
111 */
importDirContents(const QString & dirName)112 void FilterKMail_maildir::importDirContents(const QString &dirName)
113 {
114 /** Here Import all archives in the current dir */
115 importFiles(dirName);
116
117 /** If there are subfolders, we import them one by one */
118
119 processDirectory(dirName);
120 }
121
122 /**
123 * Import the files within a Folder.
124 * @param info Information storage for the operation.
125 * @param dirName The name of the directory to import.
126 */
importFiles(const QString & dirName)127 void FilterKMail_maildir::importFiles(const QString &dirName)
128 {
129 QDir dir(dirName);
130 QString _path;
131 bool generatedPath = false;
132
133 QDir importDir(dirName);
134 const QStringList files = importDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Files, QDir::Name);
135 int currentFile = 1;
136 int numFiles = files.size();
137 QStringList::ConstIterator filesEnd(files.constEnd());
138
139 for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != filesEnd; ++mailFile, ++currentFile) {
140 if (filterInfo()->shouldTerminate()) {
141 return;
142 }
143
144 QString temp_mailfile = *mailFile;
145 if (!(temp_mailfile.endsWith(QLatin1String(".index")) || temp_mailfile.endsWith(QLatin1String(".index.ids"))
146 || temp_mailfile.endsWith(QLatin1String(".index.sorted")) || temp_mailfile.endsWith(QLatin1String(".uidcache")))) {
147 if (!generatedPath) {
148 _path = QStringLiteral("KMail-Import");
149 QString _tmp = dir.filePath(*mailFile);
150 _tmp.remove(mailDir(), Qt::CaseSensitive);
151 const QStringList subFList = _tmp.split(QLatin1Char('/'), Qt::SkipEmptyParts);
152 QStringList::ConstIterator end(subFList.end());
153 for (QStringList::ConstIterator it = subFList.constBegin(); it != end; ++it) {
154 QString _cat = *it;
155 if (!(_cat == *mailFile)) {
156 if (_cat.startsWith(QLatin1Char('.')) && _cat.endsWith(QLatin1String(".directory"))) {
157 _cat.remove(0, 1);
158 _cat.remove((_cat.length() - 10), 10);
159 } else if (_cat.startsWith(QLatin1Char('.'))) {
160 _cat.remove(0, 1);
161 }
162 _path += QLatin1Char('/') + _cat;
163 }
164 }
165 if (_path.endsWith(QLatin1String("cur"))) {
166 _path.remove(_path.length() - 4, 4);
167 }
168 QString _info = _path;
169 filterInfo()->addInfoLogEntry(i18n("Import folder %1...", _info.remove(0, 12)));
170 filterInfo()->setFrom(_info);
171 filterInfo()->setTo(_path);
172 generatedPath = true;
173 }
174
175 if (!importMessage(_path, dir.filePath(*mailFile), filterInfo()->removeDupMessage())) {
176 filterInfo()->addErrorLogEntry(i18n("Could not import %1, duplicated message", *mailFile));
177 }
178 filterInfo()->setCurrent((int)((float)currentFile / numFiles * 100));
179 }
180 }
181 }
182