MailImporter

filterbalsa.cpp
1 /*
2  Copyright (c) 2012-2020 Laurent Montel <[email protected]>
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful, but
10  WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License along
15  with this program; if not, write to the Free Software Foundation, Inc.,
16  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include "filterbalsa.h"
20 
21 #include <KLocalizedString>
22 #include <QFileDialog>
23 
24 using namespace MailImporter;
25 
26 class MailImporter::FilterBalsaPrivate
27 {
28 public:
29  FilterBalsaPrivate()
30  : mImportDirDone(0)
31  , mTotalDir(0)
32  {
33  }
34 
35  int mImportDirDone = 0;
36  int mTotalDir = 0;
37 };
40  : Filter(i18n("Import Balsa Local Mails and Folder Structure"),
41  QStringLiteral("Laurent Montel"),
42  i18n("<p><b>Balsa import filter</b></p>"
43  "<p>Select the base directory of your local Balsa mailfolder (usually ~/mail/).</p>"
44  "<p>Since it is possible to recreate the folder structure, the folders "
45  "will be stored under: \"Balsa-Import\".</p>"))
46  , d(new MailImporter::FilterBalsaPrivate)
47 {
48 }
49 
52 {
53  delete d;
54 }
55 
56 QString FilterBalsa::isMailerFound()
57 {
58  QDir directory(FilterBalsa::defaultSettingsPath());
59  if (directory.exists()) {
60  return i18nc("name of balsa application", "Balsa");
61  }
62  return {};
63 }
64 
65 QString FilterBalsa::defaultSettingsPath()
66 {
67  return QDir::homePath() + QLatin1String("/.balsa/");
68 }
69 
70 QString FilterBalsa::localMailDirPath()
71 {
72  return QDir::homePath() + QLatin1String("/mail/");
73 }
74 
77 {
78  clearCountDuplicate();
79  QString balsaDir = localMailDirPath();
80  QDir d(balsaDir);
81  if (!d.exists()) {
82  balsaDir = QDir::homePath();
83  }
84  // Select directory from where I have to import files
85  const QString maildir = QFileDialog::getExistingDirectory(nullptr, QString(), balsaDir);
86  importMails(maildir);
87 }
88 
89 void FilterBalsa::processDirectory(const QString &path)
90 {
91  QDir dir(path);
92  const QStringList rootSubDirs = dir.entryList(QStringList(QStringLiteral("*")), QDir::Dirs | QDir::Hidden, QDir::Name);
93  QStringList::ConstIterator end = rootSubDirs.constEnd();
94  for (QStringList::ConstIterator filename = rootSubDirs.constBegin(); filename != end; ++filename) {
95  if (filterInfo()->shouldTerminate()) {
96  break;
97  }
98  if (!(*filename == QLatin1Char('.') || *filename == QLatin1String(".."))) {
99  filterInfo()->setCurrent(0);
100  importDirContents(dir.filePath(*filename));
101  filterInfo()->setOverall((d->mTotalDir > 0) ? (int)((float)d->mImportDirDone / d->mTotalDir * 100) : 0);
102  filterInfo()->setCurrent(100);
103  }
104  }
105 }
106 
107 void FilterBalsa::importMails(const QString &maildir)
108 {
109  if (maildir.isEmpty()) {
110  filterInfo()->alert(i18n("No directory selected."));
111  return;
112  }
113  setMailDir(maildir);
118  if (mailDir() == QDir::homePath() || mailDir() == (QDir::homePath() + QLatin1Char('/'))) {
119  filterInfo()->addErrorLogEntry(i18n("No files found for import."));
120  } else {
121  filterInfo()->setOverall(0);
122  d->mImportDirDone = 0;
123 
125  QDir dir(mailDir());
126  d->mTotalDir = Filter::countDirectory(dir, true /*search hidden directory*/);
127 
128  processDirectory(mailDir());
129 
130  filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", mailDir()));
131 
132  if (countDuplicates() > 0) {
133  filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported", "%1 duplicate messages not imported", countDuplicates()));
134  }
135 
136  if (filterInfo()->shouldTerminate()) {
137  filterInfo()->addInfoLogEntry(i18n("Finished import, canceled by user."));
138  }
139  }
140  filterInfo()->setCurrent(100);
141  filterInfo()->setOverall(100);
142 }
143 
149 void FilterBalsa::importDirContents(const QString &dirName)
150 {
152  importFiles(dirName);
153 
155  processDirectory(dirName);
156 }
157 
163 void FilterBalsa::importFiles(const QString &dirName)
164 {
165  QDir dir(dirName);
166  QString _path;
167  bool generatedPath = false;
168 
169  QDir importDir(dirName);
170  const QStringList files = importDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Files, QDir::Name);
171  int currentFile = 1, numFiles = files.size();
172  QStringList::ConstIterator filesEnd(files.constEnd());
173 
174  for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != filesEnd; ++mailFile, ++currentFile) {
175  if (filterInfo()->shouldTerminate()) {
176  return;
177  }
178  QString temp_mailfile = *mailFile;
179  if (!(temp_mailfile.endsWith(QLatin1String(".db"))
180  || temp_mailfile.endsWith(QLatin1String(".cmeta"))
181  || temp_mailfile.endsWith(QLatin1String(".ev-summary"))
182  || temp_mailfile.endsWith(QLatin1String(".ibex.index"))
183  || temp_mailfile.endsWith(QLatin1String(".ibex.index.data")))) {
184  if (!generatedPath) {
185  _path = i18nc("define folder name where we import evolution mails", "Evolution-Import");
186  QString _tmp = dir.filePath(*mailFile);
187  _tmp.remove(mailDir(), Qt::CaseSensitive);
188 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
189  QStringList subFList = _tmp.split(QLatin1Char('/'), QString::SkipEmptyParts);
190 #else
191  QStringList subFList = _tmp.split(QLatin1Char('/'), Qt::SkipEmptyParts);
192 #endif
193  QStringList::ConstIterator end(subFList.end());
194  for (QStringList::ConstIterator it = subFList.constBegin(); it != end; ++it) {
195  QString _cat = *it;
196  if (!(_cat == *mailFile)) {
197  if (_cat.startsWith(QLatin1Char('.'))) {
198  _cat.remove(0, 1);
199  }
200  //Evolution store inbox as "."
201  if (_cat.startsWith(QLatin1Char('.'))) {
202  _cat.replace(0, 1, QStringLiteral("Inbox/"));
203  }
204 
205  _path += QLatin1Char('/') + _cat;
206  _path.replace(QLatin1Char('.'), QLatin1Char('/'));
207  }
208  }
209  if (_path.endsWith(QLatin1String("cur"))) {
210  _path.remove(_path.length() - 4, 4);
211  }
212  QString _info = _path;
213  filterInfo()->addInfoLogEntry(i18n("Import folder %1...", _info));
214  filterInfo()->setFrom(_info);
215  filterInfo()->setTo(_path);
216  generatedPath = true;
217  }
218  const MailImporter::MessageStatus status = statusFromFile(*mailFile);
219 
220  if (!importMessage(_path, dir.filePath(*mailFile), filterInfo()->removeDupMessage(), status)) {
221  filterInfo()->addErrorLogEntry(i18n("Could not import %1", *mailFile));
222  }
223  filterInfo()->setCurrent((int)((float)currentFile / numFiles * 100));
224  }
225  }
226 }
227 
228 MailImporter::MessageStatus FilterBalsa::statusFromFile(const QString &filename)
229 {
231  const int statusIndex = filename.indexOf(QLatin1String(":2,"));
232  if (statusIndex != -1) {
233  const QString statusStr = filename.right(filename.length() - statusIndex - 3);
234  if (statusStr.contains(QLatin1Char('S'))) {
235  status.setRead(true);
236  }
237  if (statusStr.contains(QLatin1Char('F'))) {
238  //TODO
239  }
240  if (statusStr.contains(QLatin1Char('R'))) {
241  status.setReplied(true);
242  }
243  if (statusStr.contains(QLatin1Char('P'))) {
244  status.setForwarded(true);
245  }
246  }
247  return status;
248 }
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString filePath(const QString &fileName) const const
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString & remove(int position, int n)
The Filter class.
Definition: filters.h:39
QString homePath()
int size() const const
bool exists() const const
~FilterBalsa() override
Destructor.
Definition: filterbalsa.cpp:51
The MessageStatus class.
Definition: messagestatus.h:30
QString i18nc(const char *context, const char *text, const TYPE &arg...)
bool isEmpty() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
void import() override
Recursive import of KMail maildir.
Definition: filterbalsa.cpp:76
FilterBalsa()
Default constructor.
Definition: filterbalsa.cpp:39
QString right(int n) const const
QList::iterator end()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
void importMails(const QString &maildir)
QString i18n(const char *text, const TYPE &arg...)
QString & replace(int position, int n, QChar after)
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
typedef ConstIterator
int length() const const
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed May 27 2020 22:38:41 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.