diff --git a/agents/newmailnotifier/newmailnotifieragent.cpp b/agents/newmailnotifier/newmailnotifieragent.cpp index d87db720a..a6133f332 100644 --- a/agents/newmailnotifier/newmailnotifieragent.cpp +++ b/agents/newmailnotifier/newmailnotifieragent.cpp @@ -1,479 +1,484 @@ /* Copyright (c) 2013-2019 Laurent Montel Copyright (c) 2010 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "newmailnotifieragent.h" #include #include "specialnotifierjob.h" #include "newmailnotifieradaptor.h" #include "newmailnotifieragentsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "newmailnotifier_debug.h" #include #include #include #include using namespace Akonadi; NewMailNotifierAgent::NewMailNotifierAgent(const QString &id) : AgentBase(id) { Kdelibs4ConfigMigrator migrate(QStringLiteral("newmailnotifieragent")); migrate.setConfigFiles(QStringList() << QStringLiteral("akonadi_newmailnotifier_agentrc") << QStringLiteral("akonadi_newmailnotifier_agent.notifyrc")); migrate.migrate(); - + connect(this, &Akonadi::AgentBase::reloadConfiguration, this, &NewMailNotifierAgent::reloadConfiguration); KLocalizedString::setApplicationDomain("akonadi_newmailnotifier_agent"); Akonadi::AttributeFactory::registerAttribute(); new NewMailNotifierAdaptor(this); NewMailNotifierAgentSettings::instance(KSharedConfig::openConfig()); mIdentityManager = KIdentityManagement::IdentityManager::self(); connect(mIdentityManager, QOverload<>::of(&KIdentityManagement::IdentityManager::changed), this, &NewMailNotifierAgent::slotIdentitiesChanged); slotIdentitiesChanged(); mDefaultIconName = QStringLiteral("kmail"); KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/NewMailNotifierAgent"), this, QDBusConnection::ExportAdaptors); QString service = QStringLiteral("org.freedesktop.Akonadi.NewMailNotifierAgent"); if (Akonadi::ServerManager::hasInstanceIdentifier()) { service += QLatin1Char('.') + Akonadi::ServerManager::instanceIdentifier(); } KDBusConnectionPool::threadConnection().registerService(service); connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceStatusChanged, this, &NewMailNotifierAgent::slotInstanceStatusChanged); connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceRemoved, this, &NewMailNotifierAgent::slotInstanceRemoved); connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceAdded, this, &NewMailNotifierAgent::slotInstanceAdded); connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceNameChanged, this, &NewMailNotifierAgent::slotInstanceNameChanged); changeRecorder()->setMimeTypeMonitored(KMime::Message::mimeType()); changeRecorder()->itemFetchScope().setCacheOnly(true); changeRecorder()->itemFetchScope().setFetchModificationTime(false); changeRecorder()->fetchCollection(true); changeRecorder()->setChangeRecordingEnabled(false); changeRecorder()->ignoreSession(Akonadi::Session::defaultSession()); changeRecorder()->collectionFetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); changeRecorder()->setCollectionMonitored(Collection::root(), true); mTimer.setInterval(5 * 1000); connect(&mTimer, &QTimer::timeout, this, &NewMailNotifierAgent::slotShowNotifications); if (isActive()) { mTimer.setSingleShot(true); } } +void NewMailNotifierAgent::reloadConfiguration() +{ + NewMailNotifierAgentSettings::self()->load(); +} + void NewMailNotifierAgent::slotIdentitiesChanged() { mListEmails = mIdentityManager->allEmails(); } void NewMailNotifierAgent::doSetOnline(bool online) { if (!online) { clearAll(); } } void NewMailNotifierAgent::setEnableAgent(bool enabled) { NewMailNotifierAgentSettings::setEnabled(enabled); NewMailNotifierAgentSettings::self()->save(); if (!enabled) { clearAll(); } } bool NewMailNotifierAgent::enabledAgent() const { return NewMailNotifierAgentSettings::enabled(); } void NewMailNotifierAgent::clearAll() { mNewMails.clear(); mInstanceNameInProgress.clear(); } bool NewMailNotifierAgent::excludeSpecialCollection(const Akonadi::Collection &collection) const { if (collection.hasAttribute()) { return true; } if (collection.hasAttribute()) { if (collection.attribute()->ignoreNewMail()) { return true; } } if (!collection.contentMimeTypes().contains(KMime::Message::mimeType())) { return true; } SpecialMailCollections::Type type = SpecialMailCollections::self()->specialCollectionType(collection); switch (type) { case SpecialMailCollections::Invalid: //Not a special collection case SpecialMailCollections::Inbox: return false; default: return true; } } void NewMailNotifierAgent::itemsRemoved(const Item::List &items) { if (!isActive()) { return; } QHash< Akonadi::Collection, QList >::iterator end(mNewMails.end()); for (QHash< Akonadi::Collection, QList >::iterator it = mNewMails.begin(); it != end; ++it) { QList idList = it.value(); bool itemFound = false; for (const Item &item : items) { const int numberOfItemsRemoved = idList.removeAll(item.id()); if (numberOfItemsRemoved > 0) { itemFound = true; } } if (itemFound) { if (mNewMails[it.key()].isEmpty()) { mNewMails.remove(it.key()); } else { mNewMails[it.key()] = idList; } } } } void NewMailNotifierAgent::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet &addedFlags, const QSet &removedFlags) { Q_UNUSED(removedFlags); if (!isActive()) { return; } for (const Akonadi::Item &item : items) { QHash< Akonadi::Collection, QList >::iterator end(mNewMails.end()); for (QHash< Akonadi::Collection, QList >::iterator it = mNewMails.begin(); it != end; ++it) { QList idList = it.value(); if (idList.contains(item.id()) && addedFlags.contains("\\SEEN")) { idList.removeAll(item.id()); if (idList.isEmpty()) { mNewMails.remove(it.key()); break; } else { (*it) = idList; } } } } } void NewMailNotifierAgent::itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination) { if (!isActive()) { return; } for (const Akonadi::Item &item : items) { if (ignoreStatusMail(item)) { continue; } if (excludeSpecialCollection(collectionSource)) { continue; // outbox, sent-mail, trash, drafts or templates. } if (mNewMails.contains(collectionSource)) { QList idListFrom = mNewMails[ collectionSource ]; const int removeItems = idListFrom.removeAll(item.id()); if (removeItems > 0) { if (idListFrom.isEmpty()) { mNewMails.remove(collectionSource); } else { mNewMails[ collectionSource ] = idListFrom; } if (!excludeSpecialCollection(collectionDestination)) { QList idListTo = mNewMails[ collectionDestination ]; idListTo.append(item.id()); mNewMails[ collectionDestination ] = idListTo; } } } } } bool NewMailNotifierAgent::ignoreStatusMail(const Akonadi::Item &item) { Akonadi::MessageStatus status; status.setStatusFromFlags(item.flags()); if (status.isRead() || status.isSpam() || status.isIgnored()) { return true; } return false; } void NewMailNotifierAgent::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) { if (!isActive()) { return; } if (excludeSpecialCollection(collection)) { return; // outbox, sent-mail, trash, drafts or templates. } if (ignoreStatusMail(item)) { return; } if (!mTimer.isActive()) { mTimer.start(); } mNewMails[ collection ].append(item.id()); } void NewMailNotifierAgent::slotShowNotifications() { if (mNewMails.isEmpty()) { return; } if (!isActive()) { return; } if (!mInstanceNameInProgress.isEmpty()) { //Restart timer until all is done. mTimer.start(); return; } QString message; if (NewMailNotifierAgentSettings::verboseNotification()) { bool hasUniqMessage = true; Akonadi::Item::Id item = -1; QString currentPath; QStringList texts; const int numberOfCollection(mNewMails.count()); if (numberOfCollection > 1) { hasUniqMessage = false; } QHash< Akonadi::Collection, QList >::const_iterator end(mNewMails.constEnd()); for (QHash< Akonadi::Collection, QList >::const_iterator it = mNewMails.constBegin(); it != end; ++it) { const Akonadi::EntityDisplayAttribute *attr = it.key().attribute(); QString displayName; if (attr && !attr->displayName().isEmpty()) { displayName = attr->displayName(); } else { displayName = it.key().name(); } if (hasUniqMessage) { const int numberOfValue(it.value().count()); if (numberOfValue == 0) { //You can have an unique folder with 0 message return; } else if (numberOfValue == 1) { item = it.value().at(0); currentPath = displayName; break; } else { hasUniqMessage = false; } } QString resourceName; if (!mCacheResourceName.contains(it.key().resource())) { const Akonadi::AgentInstance::List lst = Akonadi::AgentManager::self()->instances(); for (const Akonadi::AgentInstance &instance : lst) { if (instance.identifier() == it.key().resource()) { mCacheResourceName.insert(instance.identifier(), instance.name()); resourceName = instance.name(); break; } } } else { resourceName = mCacheResourceName.value(it.key().resource()); } const int numberOfEmails(it.value().count()); if (numberOfEmails > 0) { texts.append(i18ncp("%2 = name of mail folder; %3 = name of Akonadi POP3/IMAP/etc resource (as user named it)", "One new email in %2 from \"%3\"", "%1 new emails in %2 from \"%3\"", numberOfEmails, displayName, resourceName)); } } if (hasUniqMessage) { SpecialNotifierJob *job = new SpecialNotifierJob(mListEmails, currentPath, item, this); job->setDefaultIconName(mDefaultIconName); connect(job, &SpecialNotifierJob::displayNotification, this, &NewMailNotifierAgent::slotDisplayNotification); connect(job, &SpecialNotifierJob::say, this, &NewMailNotifierAgent::slotSay); mNewMails.clear(); return; } else { message = texts.join(QStringLiteral("
")); } } else { message = i18n("New mail arrived"); } qCDebug(NEWMAILNOTIFIER_LOG) << message; slotDisplayNotification(QPixmap(), message); mNewMails.clear(); } void NewMailNotifierAgent::slotDisplayNotification(const QPixmap &pixmap, const QString &message) { if (pixmap.isNull()) { KNotification::event(QStringLiteral("new-email"), QString(), message, mDefaultIconName, nullptr, NewMailNotifierAgentSettings::keepPersistentNotification() ? KNotification::Persistent | KNotification::SkipGrouping : KNotification::CloseOnTimeout, QStringLiteral("akonadi_newmailnotifier_agent")); } else { KNotification::event(QStringLiteral("new-email"), message, pixmap, nullptr, NewMailNotifierAgentSettings::keepPersistentNotification() ? KNotification::Persistent | KNotification::SkipGrouping : KNotification::CloseOnTimeout, QStringLiteral("akonadi_newmailnotifier_agent")); } } void NewMailNotifierAgent::slotInstanceNameChanged(const Akonadi::AgentInstance &instance) { if (!isActive()) { return; } const QString identifier(instance.identifier()); int resourceNameRemoved = mCacheResourceName.remove(identifier); if (resourceNameRemoved > 0) { mCacheResourceName.insert(identifier, instance.name()); } } void NewMailNotifierAgent::slotInstanceStatusChanged(const Akonadi::AgentInstance &instance) { if (!isActive()) { return; } const QString identifier(instance.identifier()); switch (instance.status()) { case Akonadi::AgentInstance::Broken: case Akonadi::AgentInstance::Idle: mInstanceNameInProgress.removeAll(identifier); break; case Akonadi::AgentInstance::Running: if (!excludeAgentType(instance)) { if (!mInstanceNameInProgress.contains(identifier)) { mInstanceNameInProgress.append(identifier); } } break; case Akonadi::AgentInstance::NotConfigured: //Nothing break; } } bool NewMailNotifierAgent::excludeAgentType(const Akonadi::AgentInstance &instance) { if (instance.type().mimeTypes().contains(KMime::Message::mimeType())) { const QStringList capabilities(instance.type().capabilities()); if (capabilities.contains(QLatin1String("Resource")) && !capabilities.contains(QLatin1String("Virtual")) && !capabilities.contains(QLatin1String("MailTransport"))) { return false; } else { return true; } } return true; } void NewMailNotifierAgent::slotInstanceRemoved(const Akonadi::AgentInstance &instance) { if (!isActive()) { return; } const QString identifier(instance.identifier()); mInstanceNameInProgress.removeAll(identifier); } void NewMailNotifierAgent::slotInstanceAdded(const Akonadi::AgentInstance &instance) { mCacheResourceName.insert(instance.identifier(), instance.name()); } void NewMailNotifierAgent::printDebug() { qCDebug(NEWMAILNOTIFIER_LOG) << "instance in progress: " << mInstanceNameInProgress << "\n notifier enabled : " << NewMailNotifierAgentSettings::enabled() << "\n check in progress : " << !mInstanceNameInProgress.isEmpty(); } bool NewMailNotifierAgent::isActive() const { return isOnline() && NewMailNotifierAgentSettings::enabled(); } void NewMailNotifierAgent::slotSay(const QString &message) { if (!mTextToSpeech) { mTextToSpeech = new QTextToSpeech(this); } if (mTextToSpeech->availableEngines().isEmpty()) { qCWarning(NEWMAILNOTIFIER_LOG) << "No texttospeech engine available"; } else { mTextToSpeech->say(message); } } AKONADI_AGENT_MAIN(NewMailNotifierAgent) diff --git a/agents/newmailnotifier/newmailnotifieragent.h b/agents/newmailnotifier/newmailnotifieragent.h index 04a50ff86..af7259b80 100644 --- a/agents/newmailnotifier/newmailnotifieragent.h +++ b/agents/newmailnotifier/newmailnotifieragent.h @@ -1,84 +1,85 @@ /* Copyright (c) 2013-2019 Laurent Montel Copyright (c) 2010 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef NEWMAILNOTIFIERAGENT_H #define NEWMAILNOTIFIERAGENT_H #include // make sure this is included before QHash, otherwise it wont find the correct qHash implementation for some reason #include #include #include #include class QTextToSpeech; namespace Akonadi { class AgentInstance; } namespace KIdentityManagement { class IdentityManager; } class NewMailNotifierAgent : public Akonadi::AgentBase, public Akonadi::AgentBase::ObserverV3 { Q_OBJECT public: explicit NewMailNotifierAgent(const QString &id); void setEnableAgent(bool b); - bool enabledAgent() const; + Q_REQUIRED_RESULT bool enabledAgent() const; void printDebug(); protected: void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) override; void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &sourceCollection, const Akonadi::Collection &destinationCollection) override; void itemsRemoved(const Akonadi::Item::List &items) override; void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet &addedFlags, const QSet &removedFlags) override; void doSetOnline(bool online) override; private: void slotShowNotifications(); void slotInstanceStatusChanged(const Akonadi::AgentInstance &instance); void slotInstanceRemoved(const Akonadi::AgentInstance &instance); void slotInstanceAdded(const Akonadi::AgentInstance &instance); void slotDisplayNotification(const QPixmap &pixmap, const QString &message); void slotIdentitiesChanged(); void slotInstanceNameChanged(const Akonadi::AgentInstance &instance); void slotSay(const QString &message); bool excludeAgentType(const Akonadi::AgentInstance &instance); bool ignoreStatusMail(const Akonadi::Item &item); bool isActive() const; void clearAll(); bool excludeSpecialCollection(const Akonadi::Collection &collection) const; + void reloadConfiguration(); QString mDefaultIconName; QStringList mListEmails; QHash > mNewMails; QHash mCacheResourceName; QTimer mTimer; QStringList mInstanceNameInProgress; KIdentityManagement::IdentityManager *mIdentityManager = nullptr; QTextToSpeech *mTextToSpeech = nullptr; }; #endif diff --git a/agents/newmailnotifier/newmailnotifieragentsettings.kcfgc b/agents/newmailnotifier/newmailnotifieragentsettings.kcfgc index a60cad3ff..e68a097fa 100644 --- a/agents/newmailnotifier/newmailnotifieragentsettings.kcfgc +++ b/agents/newmailnotifier/newmailnotifieragentsettings.kcfgc @@ -1,5 +1,6 @@ # Code generation options for kconfig_compiler File=newmailnotifieragentsettings.kcfg ClassName=NewMailNotifierAgentSettings Mutators=true Singleton=true +ItemAccessors=true