File indexing completed on 2025-02-02 05:08:43

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "sendlateragent.h"
0008 #include "sendlateragent_debug.h"
0009 #include "sendlateragentadaptor.h"
0010 #include "sendlateragentsettings.h"
0011 #include "sendlaterconfiguredialog.h"
0012 #include "sendlatermanager.h"
0013 #include "sendlaterremovemessagejob.h"
0014 #include "sendlaterutil.h"
0015 #include <Akonadi/AgentInstance>
0016 #include <Akonadi/AgentManager>
0017 #include <Akonadi/AttributeFactory>
0018 #include <Akonadi/ChangeRecorder>
0019 #include <Akonadi/CollectionFetchScope>
0020 #include <Akonadi/ItemFetchScope>
0021 #include <Akonadi/ServerManager>
0022 #include <Akonadi/Session>
0023 #include <Akonadi/SpecialMailCollections>
0024 #include <KMime/Message>
0025 #include <QDBusConnection>
0026 
0027 #include <KWindowSystem>
0028 #include <QPointer>
0029 #include <QTimer>
0030 #include <chrono>
0031 
0032 using namespace std::chrono_literals;
0033 
0034 // #define DEBUG_SENDLATERAGENT 1
0035 
0036 SendLaterAgent::SendLaterAgent(const QString &id)
0037     : Akonadi::AgentBase(id)
0038     , mManager(new SendLaterManager(this))
0039 {
0040     connect(mManager, &SendLaterManager::needUpdateConfigDialogBox, this, &SendLaterAgent::needUpdateConfigDialogBox);
0041     new SendLaterAgentAdaptor(this);
0042     QDBusConnection::sessionBus().registerObject(QStringLiteral("/SendLaterAgent"), this, QDBusConnection::ExportAdaptors);
0043 
0044     const QString service = Akonadi::ServerManager::self()->agentServiceName(Akonadi::ServerManager::Agent, QStringLiteral("akonadi_sendlater_agent"));
0045 
0046     QDBusConnection::sessionBus().registerService(service);
0047 
0048     changeRecorder()->setMimeTypeMonitored(KMime::Message::mimeType());
0049     changeRecorder()->itemFetchScope().setCacheOnly(true);
0050     changeRecorder()->itemFetchScope().setFetchModificationTime(false);
0051     changeRecorder()->setChangeRecordingEnabled(false);
0052     changeRecorder()->ignoreSession(Akonadi::Session::defaultSession());
0053     setNeedsNetwork(true);
0054 
0055     if (SendLaterAgentSettings::enabled()) {
0056 #ifdef DEBUG_SENDLATERAGENT
0057         QTimer::singleShot(1s, this, &SendLaterAgent::slotStartAgent);
0058 #else
0059         QTimer::singleShot(4min, this, &SendLaterAgent::slotStartAgent);
0060 #endif
0061     }
0062     // For extra safety, check list every hour, in case we didn't properly get
0063     // notified about the network going up or down.
0064     auto reloadListTimer = new QTimer(this);
0065     connect(reloadListTimer, &QTimer::timeout, this, &SendLaterAgent::reload);
0066     reloadListTimer->start(1h); // 1 hour
0067 }
0068 
0069 SendLaterAgent::~SendLaterAgent() = default;
0070 
0071 void SendLaterAgent::slotStartAgent()
0072 {
0073     mAgentInitialized = true;
0074     if (isOnline()) {
0075         mManager->load();
0076     }
0077 }
0078 
0079 void SendLaterAgent::doSetOnline(bool online)
0080 {
0081     if (mAgentInitialized) {
0082         if (online) {
0083             reload();
0084         } else {
0085             mManager->stopAll();
0086         }
0087     }
0088 }
0089 
0090 void SendLaterAgent::reload()
0091 {
0092     qCDebug(SENDLATERAGENT_LOG) << " void SendLaterAgent::reload()";
0093     if (SendLaterAgentSettings::enabled()) {
0094         mManager->load(true);
0095     }
0096 }
0097 
0098 void SendLaterAgent::setEnableAgent(bool enabled)
0099 {
0100     if (SendLaterAgentSettings::enabled() == enabled) {
0101         return;
0102     }
0103 
0104     SendLaterAgentSettings::setEnabled(enabled);
0105     SendLaterAgentSettings::self()->save();
0106     if (enabled) {
0107         mManager->load();
0108     } else {
0109         mManager->stopAll();
0110     }
0111 }
0112 
0113 bool SendLaterAgent::enabledAgent() const
0114 {
0115     return SendLaterAgentSettings::enabled();
0116 }
0117 
0118 void SendLaterAgent::configure(WId windowId)
0119 {
0120     QPointer<SendLaterConfigureDialog> dialog = new SendLaterConfigureDialog();
0121     if (windowId) {
0122         dialog->setAttribute(Qt::WA_NativeWindow, true);
0123         KWindowSystem::setMainWindow(dialog->windowHandle(), windowId);
0124     }
0125     connect(this, &SendLaterAgent::needUpdateConfigDialogBox, dialog.data(), &SendLaterConfigureDialog::slotNeedToReloadConfig);
0126     connect(dialog.data(), &SendLaterConfigureDialog::sendNow, this, &SendLaterAgent::slotSendNow);
0127     if (dialog->exec()) {
0128         mManager->load();
0129         const QList<Akonadi::Item::Id> listMessage = dialog->messagesToRemove();
0130         if (!listMessage.isEmpty()) {
0131             // Will delete in specific job when done.
0132             auto sendlaterremovejob = new SendLaterRemoveMessageJob(listMessage, this);
0133             sendlaterremovejob->start();
0134         }
0135     }
0136     delete dialog;
0137 }
0138 
0139 void SendLaterAgent::removeItem(qint64 item)
0140 {
0141     if (mManager->itemRemoved(item)) {
0142         reload();
0143     }
0144 }
0145 
0146 void SendLaterAgent::addItem(qint64 timestamp,
0147                              bool recurrence,
0148                              int recurrenceValue,
0149                              int recurrenceUnit,
0150                              Akonadi::Item::Id id,
0151                              const QString &subject,
0152                              const QString &to)
0153 {
0154     auto info = new MessageComposer::SendLaterInfo;
0155     info->setDateTime(QDateTime::fromSecsSinceEpoch(timestamp));
0156     info->setRecurrence(recurrence);
0157     info->setRecurrenceEachValue(recurrenceValue);
0158     info->setRecurrenceUnit(static_cast<MessageComposer::SendLaterInfo::RecurrenceUnit>(recurrenceUnit));
0159     info->setItemId(id);
0160     info->setSubject(subject);
0161     info->setTo(to);
0162 
0163     SendLaterUtil::writeSendLaterInfo(SendLaterUtil::defaultConfig(), info);
0164     reload();
0165 }
0166 
0167 void SendLaterAgent::slotSendNow(Akonadi::Item::Id id)
0168 {
0169     mManager->sendNow(id);
0170 }
0171 
0172 void SendLaterAgent::itemsRemoved(const Akonadi::Item::List &items)
0173 {
0174     bool needToReload = false;
0175     for (const Akonadi::Item &item : items) {
0176         if (mManager->itemRemoved(item.id())) {
0177             needToReload = true;
0178         }
0179     }
0180     if (needToReload) {
0181         reload();
0182     }
0183 }
0184 
0185 void SendLaterAgent::itemsMoved(const Akonadi::Item::List &items,
0186                                 const Akonadi::Collection & /*sourceCollection*/,
0187                                 const Akonadi::Collection &destinationCollection)
0188 {
0189     if (Akonadi::SpecialMailCollections::self()->specialCollectionType(destinationCollection) != Akonadi::SpecialMailCollections::Trash) {
0190         return;
0191     }
0192     itemsRemoved(items);
0193 }
0194 
0195 QString SendLaterAgent::printDebugInfo() const
0196 {
0197     return mManager->printDebugInfo();
0198 }
0199 
0200 AKONADI_AGENT_MAIN(SendLaterAgent)
0201 
0202 #include "moc_sendlateragent.cpp"