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

KDE's Doxygen guidelines are available online.