File indexing completed on 2024-09-22 04:50:04

0001 /*
0002     SPDX-FileCopyrightText: 2011 Tobias Koenig <tokoe@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "filtermanager.h"
0008 #include "mailcommon_debug.h"
0009 
0010 #include "filteractions/filteractiondict.h"
0011 #include "filterimporterexporter.h"
0012 #include "mailfilteragentinterface.h"
0013 #include <Akonadi/Monitor>
0014 #include <Akonadi/Tag>
0015 #include <Akonadi/TagAttribute>
0016 #include <Akonadi/TagFetchJob>
0017 #include <Akonadi/TagFetchScope>
0018 #include <KConfigGroup>
0019 
0020 #include <QTimer>
0021 
0022 namespace MailCommon
0023 {
0024 class FilterManager::FilterManagerPrivate
0025 {
0026 public:
0027     FilterManagerPrivate(FilterManager *qq)
0028         : q(qq)
0029         , mMonitor(new Akonadi::Monitor)
0030     {
0031         const auto service = Akonadi::ServerManager::agentServiceName(Akonadi::ServerManager::Agent, QStringLiteral("akonadi_mailfilter_agent"));
0032         mMailFilterAgentInterface =
0033             new org::freedesktop::Akonadi::MailFilterAgent(service, QStringLiteral("/MailFilterAgent"), QDBusConnection::sessionBus(), q);
0034     }
0035 
0036     void readConfig();
0037     void writeConfig(bool withSync = true) const;
0038     void clear();
0039 
0040     QMap<QUrl, QString> mTagList;
0041     static FilterManager *mInstance;
0042     static FilterActionDict *mFilterActionDict;
0043 
0044     FilterManager *const q;
0045     OrgFreedesktopAkonadiMailFilterAgentInterface *mMailFilterAgentInterface = nullptr;
0046     QList<MailCommon::MailFilter *> mFilters;
0047     Akonadi::Monitor *const mMonitor;
0048     bool mInitialized = false;
0049 };
0050 
0051 void FilterManager::FilterManagerPrivate::readConfig()
0052 {
0053     KSharedConfig::Ptr config =
0054         KSharedConfig::openConfig(Akonadi::ServerManager::addNamespace(QStringLiteral("akonadi_mailfilter_agent")) + QStringLiteral("rc"));
0055     clear();
0056     QStringList emptyFilters;
0057     mFilters = FilterImporterExporter::readFiltersFromConfig(config, emptyFilters);
0058     Q_EMIT q->filtersChanged();
0059 }
0060 
0061 void FilterManager::FilterManagerPrivate::writeConfig(bool withSync) const
0062 {
0063     KSharedConfig::Ptr config =
0064         KSharedConfig::openConfig(Akonadi::ServerManager::addNamespace(QStringLiteral("akonadi_mailfilter_agent")) + QStringLiteral("rc"));
0065 
0066     // Now, write out the new stuff:
0067     FilterImporterExporter::writeFiltersToConfig(mFilters, config);
0068     KConfigGroup group = config->group("General");
0069 
0070     if (withSync) {
0071         group.sync();
0072     }
0073 }
0074 
0075 void FilterManager::FilterManagerPrivate::clear()
0076 {
0077     qDeleteAll(mFilters);
0078     mFilters.clear();
0079 }
0080 }
0081 
0082 using namespace MailCommon;
0083 
0084 FilterManager *FilterManager::FilterManagerPrivate::mInstance = nullptr;
0085 FilterActionDict *FilterManager::FilterManagerPrivate::mFilterActionDict = nullptr;
0086 
0087 FilterManager *FilterManager::instance()
0088 {
0089     if (!FilterManager::FilterManagerPrivate::mInstance) {
0090         FilterManager::FilterManagerPrivate::mInstance = new FilterManager;
0091     }
0092 
0093     return FilterManager::FilterManagerPrivate::mInstance;
0094 }
0095 
0096 FilterActionDict *FilterManager::filterActionDict()
0097 {
0098     if (!FilterManager::FilterManagerPrivate::mFilterActionDict) {
0099         FilterManager::FilterManagerPrivate::mFilterActionDict = new FilterActionDict;
0100     }
0101 
0102     return FilterManager::FilterManagerPrivate::mFilterActionDict;
0103 }
0104 
0105 FilterManager::FilterManager()
0106     : d(new FilterManagerPrivate(this))
0107 {
0108     updateTagList();
0109 
0110     d->mMonitor->setObjectName(QLatin1StringView("FilterManagerTagMonitor"));
0111     d->mMonitor->setTypeMonitored(Akonadi::Monitor::Tags);
0112     d->mMonitor->tagFetchScope().fetchAttribute<Akonadi::TagAttribute>();
0113     connect(d->mMonitor, &Akonadi::Monitor::tagAdded, this, &FilterManager::slotTagAdded);
0114     connect(d->mMonitor, &Akonadi::Monitor::tagRemoved, this, &FilterManager::slotTagRemoved);
0115     connect(d->mMonitor, &Akonadi::Monitor::tagChanged, this, &FilterManager::slotTagChanged);
0116 
0117     qDBusRegisterMetaType<QList<qint64>>();
0118     Akonadi::ServerManager::State state = Akonadi::ServerManager::self()->state();
0119     if (state == Akonadi::ServerManager::Running) {
0120         QTimer::singleShot(0, this, &FilterManager::slotReadConfig);
0121     } else {
0122         connect(Akonadi::ServerManager::self(), &Akonadi::ServerManager::stateChanged, this, &FilterManager::slotServerStateChanged);
0123     }
0124 }
0125 
0126 FilterManager::~FilterManager()
0127 {
0128     cleanup();
0129 }
0130 
0131 void FilterManager::cleanup()
0132 {
0133     d->clear();
0134 }
0135 
0136 void FilterManager::slotServerStateChanged(Akonadi::ServerManager::State state)
0137 {
0138     if (state == Akonadi::ServerManager::Running) {
0139         d->readConfig();
0140         disconnect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)));
0141     }
0142 }
0143 
0144 void FilterManager::updateTagList()
0145 {
0146     auto fetchJob = new Akonadi::TagFetchJob(this);
0147     fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>();
0148     connect(fetchJob, &Akonadi::TagFetchJob::result, this, &FilterManager::slotFinishedTagListing);
0149 }
0150 
0151 bool FilterManager::initialized() const
0152 {
0153     return d->mInitialized;
0154 }
0155 
0156 void FilterManager::slotReadConfig()
0157 {
0158     d->readConfig();
0159     d->mInitialized = true;
0160     Q_EMIT loadingFiltersDone();
0161 }
0162 
0163 void FilterManager::slotFinishedTagListing(KJob *job)
0164 {
0165     if (job->error()) {
0166         qCWarning(MAILCOMMON_LOG) << "failed to retrieve tags " << job->errorString();
0167     }
0168     auto fetchJob = static_cast<Akonadi::TagFetchJob *>(job);
0169     const Akonadi::Tag::List lstTags = fetchJob->tags();
0170     for (const Akonadi::Tag &tag : lstTags) {
0171         d->mTagList.insert(tag.url(), tag.name());
0172     }
0173 
0174     Q_EMIT tagListingFinished();
0175 }
0176 
0177 void FilterManager::slotTagAdded(const Akonadi::Tag &tag)
0178 {
0179     d->mTagList.insert(tag.url(), tag.name());
0180     Q_EMIT tagListingFinished();
0181 }
0182 
0183 void FilterManager::slotTagChanged(const Akonadi::Tag &tag)
0184 {
0185     if (d->mTagList.contains(tag.url())) {
0186         d->mTagList.insert(tag.url(), tag.name());
0187     }
0188     Q_EMIT tagListingFinished();
0189 }
0190 
0191 void FilterManager::slotTagRemoved(const Akonadi::Tag &tag)
0192 {
0193     d->mTagList.remove(tag.url());
0194     Q_EMIT tagListingFinished();
0195 }
0196 
0197 QMap<QUrl, QString> FilterManager::tagList() const
0198 {
0199     return d->mTagList;
0200 }
0201 
0202 bool FilterManager::isValid() const
0203 {
0204     return d->mMailFilterAgentInterface->isValid();
0205 }
0206 
0207 QString FilterManager::createUniqueFilterName(const QString &name) const
0208 {
0209     return d->mMailFilterAgentInterface->createUniqueName(name);
0210 }
0211 
0212 void FilterManager::showFilterLogDialog(qlonglong windowId)
0213 {
0214     d->mMailFilterAgentInterface->showFilterLogDialog(windowId);
0215 }
0216 
0217 void FilterManager::filter(const Akonadi::Item &item, const QString &identifier, const QString &resourceId) const
0218 {
0219     d->mMailFilterAgentInterface->filter(item.id(), identifier, resourceId);
0220 }
0221 
0222 void FilterManager::filter(const Akonadi::Item &item, FilterSet set, bool account, const QString &resourceId) const
0223 {
0224     d->mMailFilterAgentInterface->filterItem(item.id(), static_cast<int>(set), account ? resourceId : QString());
0225 }
0226 
0227 void FilterManager::filter(const Akonadi::Collection &collection, FilterSet set) const
0228 {
0229     filter(Akonadi::Collection::List{collection}, set);
0230 }
0231 
0232 void FilterManager::filter(const Akonadi::Collection::List &collections, FilterSet set) const
0233 {
0234     QList<qint64> colIds;
0235     colIds.reserve(collections.size());
0236     for (const auto &col : collections) {
0237         colIds << col.id();
0238     }
0239 
0240     d->mMailFilterAgentInterface->filterCollections(colIds, static_cast<int>(set));
0241 }
0242 
0243 void FilterManager::filter(const Akonadi::Collection &collection, const QStringList &listFilters) const
0244 {
0245     filter(Akonadi::Collection::List{collection}, listFilters);
0246 }
0247 
0248 void FilterManager::filter(const Akonadi::Collection::List &collections, const QStringList &listFilters, FilterSet set) const
0249 {
0250     QList<qint64> colIds;
0251     colIds.reserve(collections.size());
0252     for (const auto &col : collections) {
0253         colIds << col.id();
0254     }
0255 
0256     d->mMailFilterAgentInterface->applySpecificFiltersOnCollections(colIds, listFilters, static_cast<int>(set));
0257 }
0258 
0259 void FilterManager::filter(const Akonadi::Item::List &messages, FilterManager::FilterSet set) const
0260 {
0261     QList<qint64> itemIds;
0262 
0263     itemIds.reserve(messages.size());
0264     for (const Akonadi::Item &item : messages) {
0265         itemIds << item.id();
0266     }
0267 
0268     d->mMailFilterAgentInterface->filterItems(itemIds, static_cast<int>(set));
0269 }
0270 
0271 void FilterManager::filter(const Akonadi::Item::List &messages, SearchRule::RequiredPart requiredPart, const QStringList &listFilters) const
0272 {
0273     QList<qint64> itemIds;
0274 
0275     itemIds.reserve(messages.size());
0276     for (const Akonadi::Item &item : messages) {
0277         itemIds << item.id();
0278     }
0279     d->mMailFilterAgentInterface->applySpecificFilters(itemIds, static_cast<int>(requiredPart), listFilters);
0280 }
0281 
0282 void FilterManager::setFilters(const QList<MailCommon::MailFilter *> &filters)
0283 {
0284     beginUpdate();
0285     d->clear();
0286     d->mFilters = filters;
0287     endUpdate();
0288 }
0289 
0290 QList<MailCommon::MailFilter *> FilterManager::filters() const
0291 {
0292     return d->mFilters;
0293 }
0294 
0295 void FilterManager::appendFilters(const QList<MailCommon::MailFilter *> &filters, bool replaceIfNameExists)
0296 {
0297     beginUpdate();
0298     if (replaceIfNameExists) {
0299         for (const MailCommon::MailFilter *newFilter : filters) {
0300             int numberOfFilters = d->mFilters.count();
0301             for (int i = 0; i < numberOfFilters; ++i) {
0302                 MailCommon::MailFilter *filter = d->mFilters.at(i);
0303                 if (newFilter->name() == filter->name()) {
0304                     d->mFilters.removeAll(filter);
0305                     i = 0;
0306                     numberOfFilters = d->mFilters.count();
0307                 }
0308             }
0309         }
0310     }
0311 
0312     d->mFilters += filters;
0313     endUpdate();
0314 }
0315 
0316 void FilterManager::removeFilter(MailCommon::MailFilter *filter)
0317 {
0318     beginUpdate();
0319     d->mFilters.removeAll(filter);
0320     endUpdate();
0321 }
0322 
0323 void FilterManager::beginUpdate()
0324 {
0325 }
0326 
0327 void FilterManager::endUpdate()
0328 {
0329     d->writeConfig(true);
0330     d->mMailFilterAgentInterface->reload();
0331     Q_EMIT filtersChanged();
0332 }
0333 
0334 #include "moc_filtermanager.cpp"