Mailcommon

filterimporterexporter.cpp
1/*
2 SPDX-FileCopyrightText: 2007 Till Adam <adam@kde.org>
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
31using namespace MailCommon;
32
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
70void 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
96class Q_DECL_HIDDEN FilterImporterExporter::FilterImporterExporterPrivate
97{
98public:
99 FilterImporterExporterPrivate(QWidget *parent)
100 : mParent(parent)
101 {
102 }
103
104 void warningInfoAboutInvalidFilter(const QStringList &emptyFilters) const;
105 QWidget *const mParent;
106};
107
108void 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
127QList<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 = i18nc("@title:window", "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 = i18nc("@title:window", "Import Evolution Filters");
147 defaultPath = MailCommon::FilterImporterEvolution::defaultFiltersSettingsPath();
148 break;
149 case SylpheedFilter:
150 title = i18nc("@title:window", "Import Sylpheed Filters");
151 defaultPath = MailCommon::FilterImporterSylpheed::defaultFiltersSettingsPath();
152 break;
153 case ProcmailFilter:
154 title = i18nc("@title:window", "Import Procmail Filters");
155 defaultPath = MailCommon::FilterImporterProcmail::defaultFiltersSettingsPath();
156 break;
157 case BalsaFilter:
158 title = i18nc("@title:window", "Import Balsa Filters");
159 defaultPath = MailCommon::FilterImporterBalsa::defaultFiltersSettingsPath();
160 break;
161 case ClawsMailFilter:
162 title = i18nc("@title:window", "Import Claws Mail Filters");
163 defaultPath = MailCommon::FilterImporterClawsMails::defaultFiltersSettingsPath();
164 break;
165 case GmailFilter:
166 title = i18nc("@title:window", "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
311void 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 i18nc("@title:window", "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}
KConfigGroup group(const QString &group)
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QString readEntry(const char *key, const char *aDefault=nullptr) const
bool sync() override
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
Utility class that provides persisting of filters to/from KConfig.
FilterImporterExporter(QWidget *parent=nullptr)
Creates a new filter importer/exporter.
virtual ~FilterImporterExporter()
Destroys the filter importer/exporter.
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.
QList< MailFilter * > importFilters(bool &canceled, FilterImporterExporter::FilterType type=FilterImporterExporter::KMailFilter, const QString &filename=QString())
Imports filters.
static void writeFiltersToConfig(const QList< MailFilter * > &filters, KSharedConfig::Ptr config, bool exportFilter=false)
Writes the given list of filters to the given config file.
static QList< MailFilter * > readFiltersFromConfig(const KSharedConfig::Ptr &config, QStringList &emptyFilter)
Reads a list of filters from the given config file.
The FilterImporterGmail class.
The FilterImporterThunderbird class.
The MailFilter class.
Definition mailfilter.h:29
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void informationList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
The filter dialog.
QString homePath()
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual void close() override
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QUrl getSaveFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
void append(QList< T > &&value)
bool isEmpty() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QStringList filter(QStringView str, Qt::CaseSensitivity cs) const const
QUrl fromLocalFile(const QString &localFile)
bool isEmpty() const const
QString toLocalFile() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:01 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.