Mailcommon

filterimporterexporter.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 Till Adam <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "filterimporterexporter.h"
8 #include "dialog/selectthunderbirdfilterfilesdialog.h"
9 #include "filterimporter/filterimporterbalsa.h"
10 #include "filterimporter/filterimporterclawsmail.h"
11 #include "filterimporter/filterimporterevolution.h"
12 #include "filterimporter/filterimportergmail.h"
13 #include "filterimporter/filterimporterprocmail.h"
14 #include "filterimporter/filterimportersylpheed.h"
15 #include "filterimporter/filterimporterthunderbird.h"
16 #include "filterselectiondialog.h"
17 #include "mailcommon_debug.h"
18 #include "mailfilter.h"
19 
20 #include <MessageViewer/MessageViewerUtil>
21 
22 #include <KConfig>
23 #include <KConfigGroup>
24 #include <KListWidgetSearchLine>
25 #include <KMessageBox>
26 #include <QFileDialog>
27 #include <QPointer>
28 #include <QPushButton>
29 #include <QRegularExpression>
30 
31 using namespace MailCommon;
32 
33 QList<MailFilter *> FilterImporterExporter::readFiltersFromConfig(const KSharedConfig::Ptr &config, QStringList &emptyFilters)
34 {
35  const KConfigGroup group = config->group("General");
36 
37  const int numFilters = group.readEntry("filters", 0);
38 
39  bool filterNeedUpdate = false;
40  QList<MailFilter *> filters;
41  for (int i = 0; i < numFilters; ++i) {
42  const QString groupName = QStringLiteral("Filter #%1").arg(i);
43 
44  const KConfigGroup group = config->group(groupName);
45  bool update = false;
46  auto filter = new MailFilter(group, true /*interactive*/, update);
47  filter->purify();
48  if (update) {
49  filterNeedUpdate = true;
50  }
51  if (filter->isEmpty()) {
52  qCDebug(MAILCOMMON_LOG) << "Filter" << filter->asString() << "is empty!";
53  emptyFilters << filter->name();
54  delete filter;
55  } else {
56  filters.append(filter);
57  }
58  }
59  if (filterNeedUpdate) {
60  KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("akonadi_mailfilter_agentrc"));
61 
62  // Now, write out the new stuff:
64  KConfigGroup group = config->group("General");
65  group.sync();
66  }
67  return filters;
68 }
69 
70 void FilterImporterExporter::writeFiltersToConfig(const QList<MailFilter *> &filters, KSharedConfig::Ptr config, bool exportFiler)
71 {
72  // first, delete all filter groups:
73  const QStringList filterGroups = config->groupList().filter(QRegularExpression(QStringLiteral("Filter #\\d+")));
74 
75  for (const QString &group : filterGroups) {
76  config->deleteGroup(group);
77  }
78 
79  int i = 0;
80  for (const MailFilter *filter : filters) {
81  if (!filter->isEmpty()) {
82  const QString groupName = QStringLiteral("Filter #%1").arg(i);
83 
84  KConfigGroup group = config->group(groupName);
85  filter->writeConfig(group, exportFiler);
86  ++i;
87  }
88  }
89 
90  KConfigGroup group = config->group("General");
91  group.writeEntry("filters", i);
92 
93  config->sync();
94 }
95 
96 class Q_DECL_HIDDEN FilterImporterExporter::FilterImporterExporterPrivate
97 {
98 public:
99  FilterImporterExporterPrivate(QWidget *parent)
100  : mParent(parent)
101  {
102  }
103 
104  void warningInfoAboutInvalidFilter(const QStringList &emptyFilters) const;
105  QWidget *const mParent;
106 };
107 
108 void FilterImporterExporter::FilterImporterExporterPrivate::warningInfoAboutInvalidFilter(const QStringList &emptyFilters) const
109 {
110  if (!emptyFilters.isEmpty()) {
112  i18n("The following filters have not been saved because they were invalid "
113  "(e.g. containing no actions or no search rules)."),
114  emptyFilters,
115  QString(),
116  QStringLiteral("ShowInvalidFilterWarning"));
117  }
118 }
119 
121  : d(new FilterImporterExporterPrivate(parent))
122 {
123 }
124 
126 
127 QList<MailFilter *> FilterImporterExporter::importFilters(bool &canceled, FilterImporterExporter::FilterType type, const QString &filename)
128 {
129  QString fileName(filename);
130 
131  QFile file;
132  if ((type != ThunderBirdFilter) && (type != IcedoveFilter) && (type != SeaMonkeyFilter)) {
133  if (fileName.isEmpty()) {
134  QString title;
135  QString defaultPath;
136  switch (type) {
137  case KMailFilter:
138  title = i18n("Import KMail Filters");
139  defaultPath = QDir::homePath();
140  break;
141  case ThunderBirdFilter:
142  case IcedoveFilter:
143  case SeaMonkeyFilter:
144  break;
145  case EvolutionFilter:
146  title = i18n("Import Evolution Filters");
147  defaultPath = MailCommon::FilterImporterEvolution::defaultFiltersSettingsPath();
148  break;
149  case SylpheedFilter:
150  title = i18n("Import Sylpheed Filters");
151  defaultPath = MailCommon::FilterImporterSylpheed::defaultFiltersSettingsPath();
152  break;
153  case ProcmailFilter:
154  title = i18n("Import Procmail Filters");
155  defaultPath = MailCommon::FilterImporterProcmail::defaultFiltersSettingsPath();
156  break;
157  case BalsaFilter:
158  title = i18n("Import Balsa Filters");
159  defaultPath = MailCommon::FilterImporterBalsa::defaultFiltersSettingsPath();
160  break;
161  case ClawsMailFilter:
162  title = i18n("Import Claws Mail Filters");
163  defaultPath = MailCommon::FilterImporterClawsMails::defaultFiltersSettingsPath();
164  break;
165  case GmailFilter:
166  title = i18n("Import Gmail Filters");
167  defaultPath = MailCommon::FilterImporterGmail::defaultFiltersSettingsPath();
168  break;
169  }
170 
171  fileName = QFileDialog::getOpenFileName(d->mParent, title, defaultPath);
172  if (fileName.isEmpty()) {
173  canceled = true;
174  return {}; // cancel
175  }
176  }
177  file.setFileName(fileName);
178  if (!file.open(QIODevice::ReadOnly)) {
179  KMessageBox::error(d->mParent,
180  i18n("The selected file is not readable. "
181  "Your file access permissions might be insufficient."));
182  return {};
183  }
184  }
185 
186  QList<MailFilter *> imported;
187  QStringList emptyFilter;
188 
189  switch (type) {
190  case KMailFilter: {
191  const KSharedConfig::Ptr config = KSharedConfig::openConfig(fileName);
192  imported = readFiltersFromConfig(config, emptyFilter);
193  break;
194  }
195  case IcedoveFilter:
196  case SeaMonkeyFilter:
197  case ThunderBirdFilter:
198  if (fileName.isEmpty()) {
199  QString defaultPath;
200  if (type == ThunderBirdFilter) {
201  defaultPath = MailCommon::FilterImporterThunderbird::defaultThunderbirdFiltersSettingsPath();
202  } else if (type == IcedoveFilter) {
203  defaultPath = MailCommon::FilterImporterThunderbird::defaultIcedoveFiltersSettingsPath();
204  } else if (type == SeaMonkeyFilter) {
205  defaultPath = MailCommon::FilterImporterThunderbird::defaultSeaMonkeyFiltersSettingsPath();
206  }
207 
208  QPointer<SelectThunderbirdFilterFilesDialog> selectThunderBirdFileDialog = new SelectThunderbirdFilterFilesDialog(defaultPath, d->mParent);
209  selectThunderBirdFileDialog->setStartDir(QUrl::fromLocalFile(defaultPath));
210  if (selectThunderBirdFileDialog->exec()) {
211  const QStringList lstFiles = selectThunderBirdFileDialog->selectedFiles();
212  for (const QString &url : lstFiles) {
213  QFile fileThunderbird(url);
214  if (!fileThunderbird.open(QIODevice::ReadOnly)) {
215  KMessageBox::error(d->mParent,
216  i18n("The selected file is not readable. "
217  "Your file access permissions might be insufficient."));
218  } else {
219  auto thunderBirdFilter = new MailCommon::FilterImporterThunderbird(&fileThunderbird);
220 
221  imported.append(thunderBirdFilter->importFilter());
222  emptyFilter.append(thunderBirdFilter->emptyFilter());
223  delete thunderBirdFilter;
224  }
225  }
226  } else {
227  canceled = true;
228  delete selectThunderBirdFileDialog;
229  return {};
230  }
231  delete selectThunderBirdFileDialog;
232  } else {
233  file.setFileName(fileName);
234  if (!file.open(QIODevice::ReadOnly)) {
235  KMessageBox::error(d->mParent,
236  i18n("The selected file is not readable. "
237  "Your file access permissions might be insufficient."));
238  return {};
239  }
240 
241  auto thunderBirdFilter = new MailCommon::FilterImporterThunderbird(&file);
242  imported = thunderBirdFilter->importFilter();
243  emptyFilter = thunderBirdFilter->emptyFilter();
244  delete thunderBirdFilter;
245  }
246  break;
247  case EvolutionFilter: {
248  auto filter = new MailCommon::FilterImporterEvolution(&file);
249 
250  imported = filter->importFilter();
251  emptyFilter = filter->emptyFilter();
252  delete filter;
253  break;
254  }
255  case SylpheedFilter: {
256  auto filter = new MailCommon::FilterImporterSylpheed(&file);
257 
258  imported = filter->importFilter();
259  emptyFilter = filter->emptyFilter();
260  delete filter;
261  break;
262  }
263  case ProcmailFilter: {
264  auto filter = new MailCommon::FilterImporterProcmail(&file);
265 
266  imported = filter->importFilter();
267  emptyFilter = filter->emptyFilter();
268  delete filter;
269  break;
270  }
271  case BalsaFilter: {
272  auto filter = new MailCommon::FilterImporterBalsa(&file);
273 
274  imported = filter->importFilter();
275  emptyFilter = filter->emptyFilter();
276  delete filter;
277  break;
278  }
279  case ClawsMailFilter: {
280  auto filter = new MailCommon::FilterImporterClawsMails(&file);
281 
282  imported = filter->importFilter();
283  emptyFilter = filter->emptyFilter();
284  delete filter;
285  break;
286  }
287  case GmailFilter: {
288  auto filter = new MailCommon::FilterImporterGmail(&file);
289 
290  imported = filter->importFilter();
291  emptyFilter = filter->emptyFilter();
292  delete filter;
293  break;
294  }
295  }
296  d->warningInfoAboutInvalidFilter(emptyFilter);
297  file.close();
298 
299  QPointer<FilterSelectionDialog> dlg = new FilterSelectionDialog(d->mParent);
300  dlg->setFilters(imported);
301  if (dlg->exec() == QDialog::Accepted) {
302  const QList<MailFilter *> selected = dlg->selectedFilters();
303  delete dlg;
304  return selected;
305  }
306  delete dlg;
307  canceled = true;
308  return {};
309 }
310 
311 void FilterImporterExporter::exportFilters(const QList<MailFilter *> &filters, const QUrl &fileName, bool saveAll)
312 {
313  QUrl saveUrl;
314  if (fileName.isEmpty()) {
315  saveUrl = QFileDialog::getSaveFileUrl(d->mParent,
316  i18n("Export Filters"),
318  QString(),
319  nullptr,
321 
322  if (saveUrl.isEmpty() || !MessageViewer::Util::checkOverwrite(saveUrl, d->mParent)) {
323  qDeleteAll(filters);
324  return;
325  }
326  } else {
327  saveUrl = fileName;
328  }
329  KSharedConfig::Ptr config = KSharedConfig::openConfig(saveUrl.toLocalFile());
330  if (saveAll) {
331  writeFiltersToConfig(filters, config, true);
332  // qDeleteAll(filters);
333  } else {
334  std::unique_ptr<FilterSelectionDialog> dlg(new FilterSelectionDialog(d->mParent));
335  dlg->setFilters(filters);
336  if (dlg->exec() == QDialog::Accepted && dlg) {
337  QList<MailFilter *> lst = dlg->selectedFilters();
338  writeFiltersToConfig(lst, config, true);
339  qDeleteAll(lst);
340  }
341  }
342 }
Utility class that provides persisting of filters to/from KConfig.
void append(const T &value)
QString readEntry(const char *key, const char *aDefault=nullptr) const
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
FilterImporterExporter(QWidget *parent=nullptr)
Creates a new filter importer/exporter.
virtual ~FilterImporterExporter()
Destroys the filter importer/exporter.
virtual bool open(QIODevice::OpenMode mode) override
static QList< MailFilter * > readFiltersFromConfig(const KSharedConfig::Ptr &config, QStringList &emptyFilter)
Reads a list of filters from the given config file.
QString homePath()
The MailFilter class.
Definition: mailfilter.h:28
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
The FilterImporterThunderbird class.
QString i18n(const char *text, const TYPE &arg...)
bool isEmpty() const const
bool isEmpty() const const
QUrl getSaveFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes)
QList< MailFilter * > importFilters(bool &canceled, FilterImporterExporter::FilterType type=FilterImporterExporter::KMailFilter, const QString &filename=QString())
Imports filters.
QUrl fromLocalFile(const QString &localFile)
void setFileName(const QString &name)
bool isEmpty() const const
QString toLocalFile() const const
virtual void close() override
KSharedConfigPtr config()
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool sync() override
void exportFilters(const QList< MailFilter * > &filters, const QUrl &fileName=QUrl(), bool saveAll=false)
Exports the given filters to a file which is asked from the user.
static void writeFiltersToConfig(const QList< MailFilter * > &filters, KSharedConfig::Ptr config, bool exportFilter=false)
Writes the given list of filters to the given config file.
void informationList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
The FilterImporterGmail class.
The filter dialog.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Nov 28 2023 03:59:04 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.