Warning, file /pim/mailcommon/src/job/expirejob.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /** 0002 * SPDX-FileCopyrightText: 2004 David Faure <faure@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "expirejob.h" 0008 #include "collectionpage/attributes/expirecollectionattribute.h" 0009 #include "expiredeletejob.h" 0010 #include "expiremovejob.h" 0011 #include "kernel/mailkernel.h" 0012 0013 #include <PimCommon/BroadcastStatus> 0014 using PimCommon::BroadcastStatus; 0015 #include "mailcommon_debug.h" 0016 0017 #include <KLocalizedString> 0018 0019 #include <Akonadi/ItemDeleteJob> 0020 #include <Akonadi/ItemFetchJob> 0021 #include <Akonadi/ItemFetchScope> 0022 #include <Akonadi/ItemModifyJob> 0023 #include <Akonadi/ItemMoveJob> 0024 #include <Akonadi/MessageFlags> 0025 #include <Akonadi/MessageParts> 0026 #include <Akonadi/MessageStatus> 0027 #include <KMime/Message> 0028 0029 /* 0030 Testcases for folder expiry: 0031 Automatic expiry: 0032 - normal case (ensure folder has old mails and expiry settings, wait for auto-expiry) 0033 - having the folder selected when the expiry job would run (gets delayed) 0034 - selecting a folder while an expiry job is running for it (should interrupt) 0035 - exiting kmail while an expiry job is running (should abort & delete things cleanly) 0036 Manual expiry: 0037 - RMB / expire (for one folder) [KMMainWidget::slotExpireFolder()] 0038 - RMB on Local Folders / Expire All Folders [KMFolderMgr::expireAll()] 0039 - Expire All Folders [KMMainWidget::slotExpireAll()] 0040 */ 0041 0042 using namespace MailCommon; 0043 ExpireJob::ExpireJob(const Akonadi::Collection &folder, bool immediate) 0044 : ScheduledJob(folder, immediate) 0045 { 0046 } 0047 0048 ExpireJob::~ExpireJob() 0049 { 0050 qCDebug(MAILCOMMON_LOG); 0051 } 0052 0053 void ExpireJob::kill() 0054 { 0055 ScheduledJob::kill(); 0056 } 0057 0058 void ExpireJob::execute() 0059 { 0060 const MailCommon::ExpireCollectionAttribute *expirationAttribute = mSrcFolder.attribute<MailCommon::ExpireCollectionAttribute>(); 0061 if (expirationAttribute) { 0062 mMaxUnreadTime = 0; 0063 mMaxReadTime = 0; 0064 int unreadDays; 0065 int readDays; 0066 mExpireMessagesWithoutInvalidDate = expirationAttribute->expireMessagesWithValidDate(); 0067 expirationAttribute->daysToExpire(unreadDays, readDays); 0068 0069 if (unreadDays > 0) { 0070 qCDebug(MAILCOMMON_LOG) << "ExpireJob: deleting unread older than" << unreadDays << "days"; 0071 mMaxUnreadTime = QDateTime::currentDateTime().toSecsSinceEpoch() - unreadDays * 3600 * 24; 0072 } 0073 if (readDays > 0) { 0074 qCDebug(MAILCOMMON_LOG) << "ExpireJob: deleting read older than" << readDays << "days"; 0075 mMaxReadTime = QDateTime::currentDateTime().toSecsSinceEpoch() - readDays * 3600 * 24; 0076 } 0077 0078 if ((mMaxUnreadTime == 0) && (mMaxReadTime == 0)) { 0079 qCDebug(MAILCOMMON_LOG) << "ExpireJob: nothing to do"; 0080 deleteLater(); 0081 return; 0082 } 0083 } else { 0084 deleteLater(); 0085 return; 0086 } 0087 qCDebug(MAILCOMMON_LOG) << "ExpireJob: starting to expire in folder" << mSrcFolder.name(); 0088 slotDoWork(); 0089 // do nothing here, we might be deleted! 0090 } 0091 0092 void ExpireJob::slotDoWork() 0093 { 0094 auto job = new Akonadi::ItemFetchJob(mSrcFolder, this); 0095 job->fetchScope().fetchPayloadPart(Akonadi::MessagePart::Envelope); 0096 connect(job, &Akonadi::ItemFetchJob::result, this, &ExpireJob::itemFetchResult); 0097 } 0098 0099 void ExpireJob::itemFetchResult(KJob *job) 0100 { 0101 if (job->error()) { 0102 qCWarning(MAILCOMMON_LOG) << job->errorString(); 0103 deleteLater(); 0104 return; 0105 } 0106 0107 const Akonadi::Item::List items = qobject_cast<Akonadi::ItemFetchJob *>(job)->items(); 0108 for (const Akonadi::Item &item : items) { 0109 if (!item.hasPayload<KMime::Message::Ptr>()) { 0110 continue; 0111 } 0112 0113 const auto mb = item.payload<KMime::Message::Ptr>(); 0114 Akonadi::MessageStatus status; 0115 status.setStatusFromFlags(item.flags()); 0116 if ((status.isImportant() || status.isToAct() || status.isWatched()) && SettingsIf->excludeImportantMailFromExpiry()) { 0117 continue; 0118 } 0119 0120 auto mailDate = mb->date(false); 0121 if (!mailDate) { 0122 if (mExpireMessagesWithoutInvalidDate) { 0123 mRemovedMsgs.append(item); 0124 } 0125 } else { 0126 const time_t maxTime = status.isRead() ? mMaxReadTime : mMaxUnreadTime; 0127 if (mailDate->dateTime().toSecsSinceEpoch() < maxTime) { 0128 mRemovedMsgs.append(item); 0129 } 0130 } 0131 } 0132 0133 done(); 0134 } 0135 0136 void ExpireJob::done() 0137 { 0138 QString str; 0139 bool moving = false; 0140 if (!mRemovedMsgs.isEmpty()) { 0141 const int count = mRemovedMsgs.count(); 0142 0143 // The command shouldn't kill us because it opens the folder 0144 mCancellable = false; 0145 0146 const MailCommon::ExpireCollectionAttribute *expirationAttribute = mSrcFolder.attribute<MailCommon::ExpireCollectionAttribute>(); 0147 if (expirationAttribute) { 0148 const QString srcFolderName{mSrcFolder.name()}; 0149 if (expirationAttribute->expireAction() == MailCommon::ExpireCollectionAttribute::ExpireDelete) { 0150 // Expire by deletion, i.e. move to null target folder 0151 qCDebug(MAILCOMMON_LOG) << "ExpireJob: finished expiring in folder" << srcFolderName << count << "messages to remove."; 0152 auto job = new ExpireDeleteJob(this); 0153 job->setRemovedMsgs(mRemovedMsgs); 0154 job->setSourceFolderName(srcFolderName); 0155 connect(job, &ExpireDeleteJob::expireDeleteDone, this, &ExpireJob::slotExpireDeleteDone); 0156 moving = true; 0157 str = i18np("Removing 1 old message from folder %2...", "Removing %1 old messages from folder %2...", count, srcFolderName); 0158 job->start(); 0159 } else { 0160 // Expire by moving 0161 mMoveToFolder = Kernel::self()->collectionFromId(expirationAttribute->expireToFolderId()); 0162 if (!mMoveToFolder.isValid()) { 0163 str = i18n( 0164 "Cannot expire messages from folder %1: destination " 0165 "folder %2 not found", 0166 srcFolderName, 0167 expirationAttribute->expireToFolderId()); 0168 qCWarning(MAILCOMMON_LOG) << str; 0169 } else { 0170 qCDebug(MAILCOMMON_LOG) << "ExpireJob: finished expiring in folder" << srcFolderName << mRemovedMsgs.count() << "messages to move to" 0171 << mMoveToFolder.name(); 0172 0173 auto job = new ExpireMoveJob(this); 0174 job->setRemovedMsgs(mRemovedMsgs); 0175 job->setSrcFolderName(srcFolderName); 0176 job->setMoveToFolder(mMoveToFolder); 0177 connect(job, &ExpireMoveJob::expireMovedDone, this, &ExpireJob::slotExpireDeleteDone); 0178 job->start(); 0179 moving = true; 0180 str = i18np("Moving 1 old message from folder %2 to folder %3...", 0181 "Moving %1 old messages from folder %2 to folder %3...", 0182 count, 0183 srcFolderName, 0184 mMoveToFolder.name()); 0185 } 0186 } 0187 } 0188 if (!str.isEmpty()) { 0189 BroadcastStatus::instance()->setStatusMsg(str); 0190 } 0191 } 0192 0193 if (!moving) { 0194 deleteLater(); 0195 } 0196 } 0197 0198 void ExpireJob::slotExpireDeleteDone() 0199 { 0200 deleteLater(); 0201 } 0202 0203 #include "moc_expirejob.cpp"