File indexing completed on 2025-01-05 04:49:33
0001 /* 0002 This file is part of KMail. 0003 SPDX-FileCopyrightText: 2003 Andreas Gungl <a.gungl@gmx.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-only 0006 */ 0007 0008 #include "antispamwizard.h" 0009 #include <KCursorSaver> 0010 #include <MailCommon/FilterAction> 0011 #include <MailCommon/FilterActionDict> 0012 #include <MailCommon/FilterManager> 0013 #include <MailCommon/FolderRequester> 0014 #include <MailCommon/FolderTreeView> 0015 #include <MailCommon/FolderTreeWidget> 0016 #include <MailCommon/FolderTreeWidgetProxyModel> 0017 #include <MailCommon/MailFilter> 0018 #include <MailCommon/MailKernel> 0019 #include <MailCommon/MailUtil> 0020 0021 #include <PimCommon/PimUtil> 0022 0023 #include <Akonadi/AgentInstance> 0024 0025 #include <KConfigGroup> 0026 #include <KLocalizedString> 0027 #include <KProcess> 0028 #include <QDialog> 0029 0030 #include <KConfigGroup> 0031 #include <MailCommon/ResourceReadConfigFile> 0032 #include <QApplication> 0033 #include <QBoxLayout> 0034 #include <QCheckBox> 0035 #include <QEventLoop> 0036 #include <QGridLayout> 0037 #include <QHBoxLayout> 0038 #include <QLabel> 0039 #include <QListWidget> 0040 #include <QPushButton> 0041 #include <QTextEdit> 0042 #include <QTimer> 0043 #include <QVBoxLayout> 0044 using namespace KMail; 0045 using namespace MailCommon; 0046 0047 AntiSpamWizard::AntiSpamWizard(WizardMode mode, QWidget *parent) 0048 : KAssistantDialog(parent) 0049 , mInfoPage(nullptr) 0050 , mSpamRulesPage(nullptr) 0051 , mVirusRulesPage(nullptr) 0052 , mSummaryPage(nullptr) 0053 , mSpamToolsUsed(false) 0054 , mVirusToolsUsed(false) 0055 , mMode(mode) 0056 { 0057 // read the configuration for the anti-spam tools 0058 ConfigReader reader(mMode, mToolList); 0059 reader.readAndMergeConfig(); 0060 mToolList = reader.getToolList(); 0061 #ifndef NDEBUG 0062 if (mMode == AntiSpam) { 0063 qDebug() << "\nConsidered anti-spam tools:"; 0064 } else { 0065 qDebug() << "\nConsidered anti-virus tools:"; 0066 } 0067 QList<SpamToolConfig>::ConstIterator end(mToolList.constEnd()); 0068 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0069 qDebug() << "Predefined tool:" << (*it).getId(); 0070 qDebug() << "Config version:" << (*it).getVersion(); 0071 qDebug() << "Selection priority:" << (*it).getPrio(); 0072 qDebug() << "Displayed name:" << (*it).getVisibleName(); 0073 qDebug() << "Executable:" << (*it).getExecutable(); 0074 qDebug() << "WhatsThis URL:" << (*it).getWhatsThisText(); 0075 qDebug() << "Filter name:" << (*it).getFilterName(); 0076 qDebug() << "Detection command:" << (*it).getDetectCmd(); 0077 qDebug() << "Learn spam command:" << (*it).getSpamCmd(); 0078 qDebug() << "Learn ham command:" << (*it).getHamCmd(); 0079 qDebug() << "Detection header:" << (*it).getDetectionHeader(); 0080 qDebug() << "Detection pattern:" << (*it).getDetectionPattern(); 0081 qDebug() << "Use as RegExp:" << (*it).isUseRegExp(); 0082 qDebug() << "Supports Bayes Filter:" << (*it).useBayesFilter(); 0083 qDebug() << "Type:" << (*it).getType(); 0084 } 0085 #endif 0086 0087 const bool isAntiSpam = (mMode == AntiSpam); 0088 setWindowTitle(isAntiSpam ? i18nc("@title:window", "Anti-Spam Wizard") : i18nc("@title:window", "Anti-Virus Wizard")); 0089 mInfoPage = new ASWizInfoPage(mMode, nullptr, QString()); 0090 mInfoPageItem = addPage(mInfoPage, isAntiSpam ? i18n("Welcome to the KMail Anti-Spam Wizard") : i18n("Welcome to the KMail Anti-Virus Wizard")); 0091 connect(mInfoPage, &ASWizInfoPage::selectionChanged, this, &AntiSpamWizard::checkProgramsSelections); 0092 0093 if (isAntiSpam) { 0094 mSpamRulesPage = new ASWizSpamRulesPage(nullptr, QString()); 0095 mSpamRulesPageItem = addPage(mSpamRulesPage, i18n("Options to fine-tune the handling of spam messages")); 0096 connect(mSpamRulesPage, &ASWizSpamRulesPage::selectionChanged, this, &AntiSpamWizard::slotBuildSummary); 0097 0098 mSummaryPage = new ASWizSummaryPage(nullptr, QString()); 0099 mSummaryPageItem = addPage(mSummaryPage, i18n("Summary of changes to be made by this wizard")); 0100 } else { 0101 mVirusRulesPage = new ASWizVirusRulesPage(nullptr, QString()); 0102 mVirusRulesPageItem = addPage(mVirusRulesPage, i18n("Options to fine-tune the handling of virus messages")); 0103 connect(mVirusRulesPage, &ASWizVirusRulesPage::selectionChanged, this, &AntiSpamWizard::checkVirusRulesSelections); 0104 } 0105 0106 connect(button(QDialogButtonBox::Help), &QPushButton::clicked, this, &AntiSpamWizard::slotHelpClicked); 0107 0108 QTimer::singleShot(0, this, &AntiSpamWizard::checkToolAvailability); 0109 } 0110 0111 void AntiSpamWizard::accept() 0112 { 0113 if (mSpamRulesPage) { 0114 qDebug() << "Folder name for messages classified as spam is" << mSpamRulesPage->selectedSpamCollectionId(); 0115 qDebug() << "Folder name for messages classified as unsure is" << mSpamRulesPage->selectedUnsureCollectionId(); 0116 } 0117 if (mVirusRulesPage) { 0118 qDebug() << "Folder name for viruses is" << mVirusRulesPage->selectedFolderName(); 0119 } 0120 0121 FilterActionDict dict; 0122 QList<MailFilter *> filterList; 0123 bool replaceExistingFilters = false; 0124 0125 // Let's start with virus detection and handling, 0126 // so we can avoid spam checks for viral messages 0127 if (mMode == AntiVirus) { 0128 if (!mVirusToolsUsed) { 0129 QDialog::accept(); 0130 return; 0131 } 0132 QList<SpamToolConfig>::const_iterator end(mToolList.constEnd()); 0133 for (QList<SpamToolConfig>::const_iterator it = mToolList.constBegin(); it != end; ++it) { 0134 if (mInfoPage->isProgramSelected((*it).getVisibleName()) && (mVirusRulesPage->pipeRulesSelected() && (*it).isVirusTool())) { 0135 // pipe messages through the anti-virus tools, 0136 // one single filter for each tool 0137 // (could get combined but so it's easier to understand for the user) 0138 auto pipeFilter = new MailFilter(); 0139 QList<FilterAction *> *pipeFilterActions = pipeFilter->actions(); 0140 FilterAction *pipeFilterAction = dict.value(QStringLiteral("filter app"))->create(); 0141 pipeFilterAction->argsFromString((*it).getDetectCmd()); 0142 pipeFilterActions->append(pipeFilterAction); 0143 SearchPattern *pipeFilterPattern = pipeFilter->pattern(); 0144 pipeFilterPattern->setName(uniqueNameFor((*it).getFilterName())); 0145 pipeFilterPattern->append(SearchRule::createInstance("<size>", SearchRule::FuncIsGreaterOrEqual, QStringLiteral("0"))); 0146 pipeFilter->setApplyOnOutbound(false); 0147 pipeFilter->setApplyOnInbound(true); 0148 pipeFilter->setApplyOnExplicit(true); 0149 pipeFilter->setStopProcessingHere(false); 0150 pipeFilter->setConfigureShortcut(false); 0151 0152 filterList.append(pipeFilter); 0153 } 0154 } 0155 0156 if (mVirusRulesPage->moveRulesSelected()) { 0157 // Sort out viruses depending on header fields set by the tools 0158 auto virusFilter = new MailFilter(); 0159 QList<FilterAction *> *virusFilterActions = virusFilter->actions(); 0160 FilterAction *virusFilterAction1 = dict.value(QStringLiteral("transfer"))->create(); 0161 virusFilterAction1->argsFromString(mVirusRulesPage->selectedFolderName()); 0162 virusFilterActions->append(virusFilterAction1); 0163 if (mVirusRulesPage->markReadRulesSelected()) { 0164 FilterAction *virusFilterAction2 = dict.value(QStringLiteral("set status"))->create(); 0165 virusFilterAction2->argsFromString(QStringLiteral("R")); // Read 0166 virusFilterActions->append(virusFilterAction2); 0167 } 0168 SearchPattern *virusFilterPattern = virusFilter->pattern(); 0169 virusFilterPattern->setName(uniqueNameFor(i18n("Virus handling"))); 0170 virusFilterPattern->setOp(SearchPattern::OpOr); 0171 QList<SpamToolConfig>::ConstIterator endSpamTool(mToolList.constEnd()); 0172 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != endSpamTool; ++it) { 0173 if (mInfoPage->isProgramSelected((*it).getVisibleName())) { 0174 if ((*it).isVirusTool()) { 0175 const QByteArray header = (*it).getDetectionHeader().toLatin1(); 0176 const QString &pattern = (*it).getDetectionPattern(); 0177 if ((*it).isUseRegExp()) { 0178 virusFilterPattern->append(SearchRule::createInstance(header, SearchRule::FuncRegExp, pattern)); 0179 } else { 0180 virusFilterPattern->append(SearchRule::createInstance(header, SearchRule::FuncContains, pattern)); 0181 } 0182 } 0183 } 0184 } 0185 virusFilter->setApplyOnOutbound(false); 0186 virusFilter->setApplyOnInbound(true); 0187 virusFilter->setApplyOnExplicit(true); 0188 virusFilter->setStopProcessingHere(true); 0189 virusFilter->setConfigureShortcut(false); 0190 0191 filterList.append(virusFilter); 0192 } 0193 } else { // AntiSpam mode 0194 if (!mSpamToolsUsed) { 0195 QDialog::accept(); 0196 return; 0197 } 0198 // TODO Existing filters with same name are replaced. This is hardcoded 0199 // ATM and needs to be replaced with a value from a (still missing) 0200 // checkbox in the GUI. At least, the replacement is announced in the GUI. 0201 replaceExistingFilters = true; 0202 QList<SpamToolConfig>::ConstIterator end(mToolList.constEnd()); 0203 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0204 if (mInfoPage->isProgramSelected((*it).getVisibleName()) && (*it).isSpamTool() && !(*it).isDetectionOnly()) { 0205 // pipe messages through the anti-spam tools, 0206 // one single filter for each tool 0207 // (could get combined but so it's easier to understand for the user) 0208 auto pipeFilter = new MailFilter(); 0209 QList<FilterAction *> *pipeFilterActions = pipeFilter->actions(); 0210 FilterAction *pipeFilterAction = dict.value(QStringLiteral("filter app"))->create(); 0211 pipeFilterAction->argsFromString((*it).getDetectCmd()); 0212 pipeFilterActions->append(pipeFilterAction); 0213 SearchPattern *pipeFilterPattern = pipeFilter->pattern(); 0214 if (replaceExistingFilters) { 0215 pipeFilterPattern->setName((*it).getFilterName()); 0216 } else { 0217 pipeFilterPattern->setName(uniqueNameFor((*it).getFilterName())); 0218 } 0219 pipeFilterPattern->append(SearchRule::createInstance("<size>", SearchRule::FuncIsLessOrEqual, QStringLiteral("256000"))); 0220 pipeFilter->setApplyOnOutbound(false); 0221 pipeFilter->setApplyOnInbound(true); 0222 pipeFilter->setApplyOnExplicit(true); 0223 pipeFilter->setStopProcessingHere(false); 0224 pipeFilter->setConfigureShortcut(false); 0225 0226 filterList.append(pipeFilter); 0227 } 0228 } 0229 0230 // Sort out spam depending on header fields set by the tools 0231 auto spamFilter = new MailFilter(); 0232 QList<FilterAction *> *spamFilterActions = spamFilter->actions(); 0233 if (mSpamRulesPage->moveSpamSelected()) { 0234 FilterAction *spamFilterAction1 = dict.value(QStringLiteral("transfer"))->create(); 0235 spamFilterAction1->argsFromString(mSpamRulesPage->selectedSpamCollectionId()); 0236 spamFilterActions->append(spamFilterAction1); 0237 } 0238 FilterAction *spamFilterAction2 = dict.value(QStringLiteral("set status"))->create(); 0239 spamFilterAction2->argsFromString(QStringLiteral("P")); // Spam 0240 spamFilterActions->append(spamFilterAction2); 0241 if (mSpamRulesPage->markAsReadSelected()) { 0242 FilterAction *spamFilterAction3 = dict.value(QStringLiteral("set status"))->create(); 0243 spamFilterAction3->argsFromString(QStringLiteral("R")); // Read 0244 spamFilterActions->append(spamFilterAction3); 0245 } 0246 SearchPattern *spamFilterPattern = spamFilter->pattern(); 0247 if (replaceExistingFilters) { 0248 spamFilterPattern->setName(i18n("Spam Handling")); 0249 } else { 0250 spamFilterPattern->setName(uniqueNameFor(i18n("Spam Handling"))); 0251 } 0252 spamFilterPattern->setOp(SearchPattern::OpOr); 0253 QList<SpamToolConfig>::ConstIterator endToolList(mToolList.constEnd()); 0254 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != endToolList; ++it) { 0255 if (mInfoPage->isProgramSelected((*it).getVisibleName())) { 0256 if ((*it).isSpamTool()) { 0257 const QByteArray header = (*it).getDetectionHeader().toLatin1(); 0258 const QString &pattern = (*it).getDetectionPattern(); 0259 if ((*it).isUseRegExp()) { 0260 spamFilterPattern->append(SearchRule::createInstance(header, SearchRule::FuncRegExp, pattern)); 0261 } else { 0262 spamFilterPattern->append(SearchRule::createInstance(header, SearchRule::FuncContains, pattern)); 0263 } 0264 } 0265 } 0266 } 0267 spamFilter->setApplyOnOutbound(false); 0268 spamFilter->setApplyOnInbound(true); 0269 spamFilter->setApplyOnExplicit(true); 0270 spamFilter->setStopProcessingHere(true); 0271 spamFilter->setConfigureShortcut(false); 0272 filterList.append(spamFilter); 0273 0274 if (mSpamRulesPage->moveUnsureSelected()) { 0275 // Sort out messages classified as unsure 0276 bool atLeastOneUnsurePattern = false; 0277 auto unsureFilter = new MailFilter(); 0278 QList<FilterAction *> *unsureFilterActions = unsureFilter->actions(); 0279 FilterAction *unsureFilterAction1 = dict.value(QStringLiteral("transfer"))->create(); 0280 unsureFilterAction1->argsFromString(mSpamRulesPage->selectedUnsureCollectionId()); 0281 unsureFilterActions->append(unsureFilterAction1); 0282 SearchPattern *unsureFilterPattern = unsureFilter->pattern(); 0283 if (replaceExistingFilters) { 0284 unsureFilterPattern->setName(i18n("Semi spam (unsure) handling")); 0285 } else { 0286 unsureFilterPattern->setName(uniqueNameFor(i18n("Semi spam (unsure) handling"))); 0287 } 0288 unsureFilterPattern->setOp(SearchPattern::OpOr); 0289 QList<SpamToolConfig>::ConstIterator end(mToolList.constEnd()); 0290 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0291 if (mInfoPage->isProgramSelected((*it).getVisibleName())) { 0292 if ((*it).isSpamTool() && (*it).hasTristateDetection()) { 0293 atLeastOneUnsurePattern = true; 0294 const QByteArray header = (*it).getDetectionHeader().toLatin1(); 0295 const QString &pattern = (*it).getDetectionPattern2(); 0296 if ((*it).isUseRegExp()) { 0297 unsureFilterPattern->append(SearchRule::createInstance(header, SearchRule::FuncRegExp, pattern)); 0298 } else { 0299 unsureFilterPattern->append(SearchRule::createInstance(header, SearchRule::FuncContains, pattern)); 0300 } 0301 } 0302 } 0303 } 0304 unsureFilter->setApplyOnOutbound(false); 0305 unsureFilter->setApplyOnInbound(true); 0306 unsureFilter->setApplyOnExplicit(true); 0307 unsureFilter->setStopProcessingHere(true); 0308 unsureFilter->setConfigureShortcut(false); 0309 0310 if (atLeastOneUnsurePattern) { 0311 filterList.append(unsureFilter); 0312 } else { 0313 delete unsureFilter; 0314 } 0315 } 0316 0317 // Classify messages manually as Spam 0318 auto classSpamFilter = new MailFilter(); 0319 classSpamFilter->setIcon(QStringLiteral("mail-mark-junk")); 0320 QList<FilterAction *> *classSpamFilterActions = classSpamFilter->actions(); 0321 FilterAction *classSpamFilterActionFirst = dict.value(QStringLiteral("set status"))->create(); 0322 classSpamFilterActionFirst->argsFromString(QStringLiteral("P")); 0323 classSpamFilterActions->append(classSpamFilterActionFirst); 0324 QList<SpamToolConfig>::ConstIterator endToolList2(mToolList.constEnd()); 0325 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != endToolList2; ++it) { 0326 if (mInfoPage->isProgramSelected((*it).getVisibleName()) && (*it).useBayesFilter() && !(*it).isDetectionOnly()) { 0327 FilterAction *classSpamFilterAction = dict.value(QStringLiteral("execute"))->create(); 0328 classSpamFilterAction->argsFromString((*it).getSpamCmd()); 0329 classSpamFilterActions->append(classSpamFilterAction); 0330 } 0331 } 0332 if (mSpamRulesPage->moveSpamSelected()) { 0333 FilterAction *classSpamFilterActionLast = dict.value(QStringLiteral("transfer"))->create(); 0334 classSpamFilterActionLast->argsFromString(mSpamRulesPage->selectedSpamCollectionId()); 0335 classSpamFilterActions->append(classSpamFilterActionLast); 0336 } 0337 0338 SearchPattern *classSpamFilterPattern = classSpamFilter->pattern(); 0339 if (replaceExistingFilters) { 0340 classSpamFilterPattern->setName(i18n("Classify as Spam")); 0341 } else { 0342 classSpamFilterPattern->setName(uniqueNameFor(i18n("Classify as Spam"))); 0343 } 0344 classSpamFilterPattern->append(SearchRule::createInstance("<size>", SearchRule::FuncIsGreaterOrEqual, QStringLiteral("0"))); 0345 classSpamFilter->setApplyOnOutbound(false); 0346 classSpamFilter->setApplyOnInbound(false); 0347 classSpamFilter->setApplyOnExplicit(false); 0348 classSpamFilter->setStopProcessingHere(true); 0349 classSpamFilter->setConfigureShortcut(true); 0350 classSpamFilter->setConfigureToolbar(true); 0351 classSpamFilter->setToolbarName(i18n("Spam")); 0352 filterList.append(classSpamFilter); 0353 0354 // Classify messages manually as not Spam / as Ham 0355 auto classHamFilter = new MailFilter(); 0356 classHamFilter->setIcon(QStringLiteral("mail-mark-notjunk")); 0357 QList<FilterAction *> *classHamFilterActions = classHamFilter->actions(); 0358 FilterAction *classHamFilterActionFirst = dict.value(QStringLiteral("set status"))->create(); 0359 classHamFilterActionFirst->argsFromString(QStringLiteral("H")); 0360 classHamFilterActions->append(classHamFilterActionFirst); 0361 end = mToolList.constEnd(); 0362 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0363 if (mInfoPage->isProgramSelected((*it).getVisibleName()) && (*it).useBayesFilter() && !(*it).isDetectionOnly()) { 0364 FilterAction *classHamFilterAction = dict.value(QStringLiteral("execute"))->create(); 0365 classHamFilterAction->argsFromString((*it).getHamCmd()); 0366 classHamFilterActions->append(classHamFilterAction); 0367 } 0368 } 0369 end = mToolList.constEnd(); 0370 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0371 if (mInfoPage->isProgramSelected((*it).getVisibleName()) && (*it).useBayesFilter() && !(*it).isDetectionOnly()) { 0372 FilterAction *classHamFilterAction = dict.value(QStringLiteral("filter app"))->create(); 0373 classHamFilterAction->argsFromString((*it).getNoSpamCmd()); 0374 classHamFilterActions->append(classHamFilterAction); 0375 } 0376 } 0377 SearchPattern *classHamFilterPattern = classHamFilter->pattern(); 0378 if (replaceExistingFilters) { 0379 classHamFilterPattern->setName(i18n("Classify as NOT Spam")); 0380 } else { 0381 classHamFilterPattern->setName(uniqueNameFor(i18n("Classify as NOT Spam"))); 0382 } 0383 classHamFilterPattern->append(SearchRule::createInstance("<size>", SearchRule::FuncIsGreaterOrEqual, QStringLiteral("0"))); 0384 classHamFilter->setApplyOnOutbound(false); 0385 classHamFilter->setApplyOnInbound(false); 0386 classHamFilter->setApplyOnExplicit(false); 0387 classHamFilter->setStopProcessingHere(true); 0388 classHamFilter->setConfigureShortcut(true); 0389 classHamFilter->setConfigureToolbar(true); 0390 classHamFilter->setToolbarName(i18n("Ham")); 0391 filterList.append(classHamFilter); 0392 } 0393 0394 /* Now that all the filters have been added to the list, tell 0395 * the filter manager about it. That will Q_EMIT filterListUpdate 0396 * which will result in the filter list in kmmainwidget being 0397 * initialized. This should happened only once. */ 0398 if (!filterList.isEmpty()) { 0399 MailCommon::FilterManager::instance()->appendFilters(filterList, replaceExistingFilters); 0400 } 0401 0402 QDialog::accept(); 0403 } 0404 0405 void AntiSpamWizard::checkProgramsSelections() 0406 { 0407 bool supportUnsure = false; 0408 0409 mSpamToolsUsed = false; 0410 mVirusToolsUsed = false; 0411 QList<SpamToolConfig>::ConstIterator end(mToolList.constEnd()); 0412 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0413 if (mInfoPage->isProgramSelected((*it).getVisibleName())) { 0414 if ((*it).isSpamTool()) { 0415 mSpamToolsUsed = true; 0416 if ((*it).hasTristateDetection()) { 0417 supportUnsure = true; 0418 } 0419 } 0420 if ((*it).isVirusTool()) { 0421 mVirusToolsUsed = true; 0422 } 0423 0424 if (mSpamToolsUsed && mVirusToolsUsed && supportUnsure) { 0425 break; 0426 } 0427 } 0428 } 0429 0430 if (mMode == AntiSpam) { 0431 mSpamRulesPage->allowUnsureFolderSelection(supportUnsure); 0432 mSpamRulesPage->allowMoveSpam(mSpamToolsUsed); 0433 slotBuildSummary(); 0434 setAppropriate(mSpamRulesPageItem, mSpamToolsUsed); 0435 setAppropriate(mSummaryPageItem, mSpamToolsUsed); 0436 } else if (mMode == AntiVirus) { 0437 if (mVirusToolsUsed) { 0438 checkVirusRulesSelections(); 0439 } 0440 setAppropriate(mVirusRulesPageItem, mVirusToolsUsed); 0441 } 0442 } 0443 0444 void AntiSpamWizard::checkVirusRulesSelections() 0445 { 0446 // setFinishEnabled( mVirusRulesPage, anyVirusOptionChecked() ); 0447 } 0448 0449 void AntiSpamWizard::checkToolAvailability() 0450 { 0451 // this can take some time to find the tools 0452 KCursorSaver saver(Qt::WaitCursor); 0453 bool found = false; 0454 QList<SpamToolConfig>::ConstIterator end(mToolList.constEnd()); 0455 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0456 const QString text(i18n("Scanning for %1...", (*it).getId())); 0457 mInfoPage->setScanProgressText(text); 0458 if ((*it).isSpamTool() && (*it).isServerBased()) { 0459 // check the configured account for pattern in <server> 0460 const QString pattern = (*it).getServerPattern(); 0461 qDebug() << "Testing for server pattern:" << pattern; 0462 const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances(); 0463 for (const Akonadi::AgentInstance &type : lst) { 0464 if (type.status() == Akonadi::AgentInstance::Broken) { 0465 continue; 0466 } 0467 const QString typeIdentifier(type.identifier()); 0468 if (PimCommon::Util::isImapResource(typeIdentifier)) { 0469 MailCommon::ResourceReadConfigFile resourceFile(typeIdentifier); 0470 const KConfigGroup grp = resourceFile.group(QStringLiteral("network")); 0471 if (grp.isValid()) { 0472 const QString host = grp.readEntry(QStringLiteral("ImapServer")); 0473 if (host.contains(pattern.toLower(), Qt::CaseInsensitive)) { 0474 mInfoPage->addAvailableTool((*it).getVisibleName()); 0475 found = true; 0476 } 0477 } 0478 } else if (type.identifier().contains(POP3_RESOURCE_IDENTIFIER)) { 0479 MailCommon::ResourceReadConfigFile resourceFile(typeIdentifier); 0480 const KConfigGroup grp = resourceFile.group(QStringLiteral("General")); 0481 if (grp.isValid()) { 0482 const QString host = grp.readEntry(QStringLiteral("host")); 0483 if (host.contains(pattern.toLower(), Qt::CaseInsensitive)) { 0484 mInfoPage->addAvailableTool((*it).getVisibleName()); 0485 found = true; 0486 } 0487 } 0488 } 0489 } 0490 } else { 0491 // check the availability of the application 0492 qApp->processEvents(QEventLoop::ExcludeUserInputEvents, 200); 0493 if (!checkForProgram((*it).getExecutable())) { 0494 mInfoPage->addAvailableTool((*it).getVisibleName()); 0495 found = true; 0496 } 0497 } 0498 } 0499 if (found) { 0500 mInfoPage->setScanProgressText((mMode == AntiSpam) ? i18n("Scanning for anti-spam tools finished.") : i18n("Scanning for anti-virus tools finished.")); 0501 } else { 0502 mInfoPage->setScanProgressText((mMode == AntiSpam) ? i18n("<p>Sorry, no spam detection tools have been found. " 0503 "Install your spam detection software and " 0504 "re-run this wizard.</p>") 0505 : i18n("Scanning complete. No anti-virus tools found.")); 0506 } 0507 checkProgramsSelections(); 0508 } 0509 0510 void AntiSpamWizard::slotHelpClicked() 0511 { 0512 PimCommon::Util::invokeHelp((mMode == AntiSpam) ? QStringLiteral("kmail2/the-anti-spam-wizard.html") : QStringLiteral("kmail2/the-anti-virus-wizard.html")); 0513 } 0514 0515 void AntiSpamWizard::slotBuildSummary() 0516 { 0517 QString text; 0518 QString newFilters; 0519 QString replaceFilters; 0520 0521 if (mMode == AntiVirus) { 0522 text.clear(); // TODO add summary for the virus part 0523 } else { // AntiSpam mode 0524 if (mSpamRulesPage->markAsReadSelected()) { 0525 if (mSpamRulesPage->moveSpamSelected()) { 0526 text = i18n( 0527 "<p>Messages classified as spam are marked as read." 0528 "<br />Spam messages are moved into the folder named <i>%1</i>.</p>", 0529 mSpamRulesPage->selectedSpamCollectionName()); 0530 } else { 0531 text = i18n( 0532 "<p>Messages classified as spam are marked as read." 0533 "<br />Spam messages are not moved into a certain folder.</p>"); 0534 } 0535 } else { 0536 if (mSpamRulesPage->moveSpamSelected()) { 0537 text = i18n( 0538 "<p>Messages classified as spam are not marked as read." 0539 "<br />Spam messages are moved into the folder named <i>%1</i>.</p>", 0540 mSpamRulesPage->selectedSpamCollectionName()); 0541 } else { 0542 text = i18n( 0543 "<p>Messages classified as spam are not marked as read." 0544 "<br />Spam messages are not moved into a certain folder.</p>"); 0545 } 0546 } 0547 QList<SpamToolConfig>::ConstIterator end(mToolList.constEnd()); 0548 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0549 if (mInfoPage->isProgramSelected((*it).getVisibleName()) && (*it).isSpamTool() && !(*it).isDetectionOnly()) { 0550 sortFilterOnExistance((*it).getFilterName(), newFilters, replaceFilters); 0551 } 0552 } 0553 sortFilterOnExistance(i18n("Spam Handling"), newFilters, replaceFilters); 0554 0555 // The need for a handling of status "probably spam" depends on the tools chosen 0556 if (mSpamRulesPage->moveUnsureSelected()) { 0557 bool atLeastOneUnsurePattern = false; 0558 end = mToolList.constEnd(); 0559 for (QList<SpamToolConfig>::ConstIterator it = mToolList.constBegin(); it != end; ++it) { 0560 if (mInfoPage->isProgramSelected((*it).getVisibleName())) { 0561 if ((*it).isSpamTool() && (*it).hasTristateDetection()) { 0562 atLeastOneUnsurePattern = true; 0563 break; 0564 } 0565 } 0566 } 0567 if (atLeastOneUnsurePattern) { 0568 sortFilterOnExistance(i18n("Semi spam (unsure) handling"), newFilters, replaceFilters); 0569 text += 0570 i18n("<p>The folder for messages classified as unsure (probably spam) is <i>%1</i>.</p>", mSpamRulesPage->selectedUnsureCollectionName()); 0571 } 0572 } 0573 0574 // Manual classification via toolbar icon / manually applied filter action 0575 sortFilterOnExistance(i18n("Classify as Spam"), newFilters, replaceFilters); 0576 sortFilterOnExistance(i18n("Classify as NOT Spam"), newFilters, replaceFilters); 0577 0578 // Show the filters in the summary 0579 if (!newFilters.isEmpty()) { 0580 text += i18n("<p>The wizard will create the following filters:<ul>%1</ul></p>", newFilters); 0581 } 0582 if (!replaceFilters.isEmpty()) { 0583 text += i18n("<p>The wizard will replace the following filters:<ul>%1</ul></p>", replaceFilters); 0584 } 0585 } 0586 0587 mSummaryPage->setSummaryText(text); 0588 } 0589 0590 int AntiSpamWizard::checkForProgram(const QString &executable) const 0591 { 0592 qDebug() << "Testing for executable:" << executable; 0593 KProcess process; 0594 process.setShellCommand(executable); 0595 return process.execute(); 0596 } 0597 0598 bool AntiSpamWizard::anyVirusOptionChecked() const 0599 { 0600 return mVirusRulesPage->moveRulesSelected() || mVirusRulesPage->pipeRulesSelected(); 0601 } 0602 0603 const QString AntiSpamWizard::uniqueNameFor(const QString &name) 0604 { 0605 return MailCommon::FilterManager::instance()->createUniqueFilterName(name); 0606 } 0607 0608 void AntiSpamWizard::sortFilterOnExistance(const QString &intendedFilterName, QString &newFilters, QString &replaceFilters) 0609 { 0610 if (uniqueNameFor(intendedFilterName) == intendedFilterName) { 0611 newFilters += QLatin1StringView("<li>") + intendedFilterName + QLatin1StringView("</li>"); 0612 } else { 0613 replaceFilters += QLatin1StringView("<li>") + intendedFilterName + QLatin1StringView("</li>"); 0614 } 0615 } 0616 0617 //--------------------------------------------------------------------------- 0618 AntiSpamWizard::SpamToolConfig::SpamToolConfig(const QString &toolId, 0619 int configVersion, 0620 int prio, 0621 const QString &name, 0622 const QString &exec, 0623 const QString &url, 0624 const QString &filter, 0625 const QString &detection, 0626 const QString &spam, 0627 const QString &ham, 0628 const QString &noSpam, 0629 const QString &header, 0630 const QString &pattern, 0631 const QString &pattern2, 0632 const QString &serverPattern, 0633 bool detectionOnly, 0634 bool regExp, 0635 bool bayesFilter, 0636 bool tristateDetection, 0637 WizardMode type) 0638 : mId(toolId) 0639 , mVersion(configVersion) 0640 , mPrio(prio) 0641 , mVisibleName(name) 0642 , mExecutable(exec) 0643 , mWhatsThisText(url) 0644 , mFilterName(filter) 0645 , mDetectCmd(detection) 0646 , mSpamCmd(spam) 0647 , mHamCmd(ham) 0648 , mNoSpamCmd(noSpam) 0649 , mDetectionHeader(header) 0650 , mDetectionPattern(pattern) 0651 , mDetectionPattern2(pattern2) 0652 , mServerPattern(serverPattern) 0653 , mDetectionOnly(detectionOnly) 0654 , mUseRegExp(regExp) 0655 , mSupportsBayesFilter(bayesFilter) 0656 , mSupportsUnsure(tristateDetection) 0657 , mType(type) 0658 { 0659 } 0660 0661 int AntiSpamWizard::SpamToolConfig::getVersion() const 0662 { 0663 return mVersion; 0664 } 0665 0666 int AntiSpamWizard::SpamToolConfig::getPrio() const 0667 { 0668 return mPrio; 0669 } 0670 0671 QString AntiSpamWizard::SpamToolConfig::getId() const 0672 { 0673 return mId; 0674 } 0675 0676 QString AntiSpamWizard::SpamToolConfig::getVisibleName() const 0677 { 0678 return mVisibleName; 0679 } 0680 0681 QString AntiSpamWizard::SpamToolConfig::getExecutable() const 0682 { 0683 return mExecutable; 0684 } 0685 0686 QString AntiSpamWizard::SpamToolConfig::getWhatsThisText() const 0687 { 0688 return mWhatsThisText; 0689 } 0690 0691 QString AntiSpamWizard::SpamToolConfig::getFilterName() const 0692 { 0693 return mFilterName; 0694 } 0695 0696 QString AntiSpamWizard::SpamToolConfig::getDetectCmd() const 0697 { 0698 return mDetectCmd; 0699 } 0700 0701 QString AntiSpamWizard::SpamToolConfig::getSpamCmd() const 0702 { 0703 return mSpamCmd; 0704 } 0705 0706 QString AntiSpamWizard::SpamToolConfig::getHamCmd() const 0707 { 0708 return mHamCmd; 0709 } 0710 0711 QString AntiSpamWizard::SpamToolConfig::getNoSpamCmd() const 0712 { 0713 return mNoSpamCmd; 0714 } 0715 0716 QString AntiSpamWizard::SpamToolConfig::getDetectionHeader() const 0717 { 0718 return mDetectionHeader; 0719 } 0720 0721 QString AntiSpamWizard::SpamToolConfig::getDetectionPattern() const 0722 { 0723 return mDetectionPattern; 0724 } 0725 0726 QString AntiSpamWizard::SpamToolConfig::getDetectionPattern2() const 0727 { 0728 return mDetectionPattern2; 0729 } 0730 0731 QString AntiSpamWizard::SpamToolConfig::getServerPattern() const 0732 { 0733 return mServerPattern; 0734 } 0735 0736 bool AntiSpamWizard::SpamToolConfig::isServerBased() const 0737 { 0738 return !mServerPattern.isEmpty(); 0739 } 0740 0741 bool AntiSpamWizard::SpamToolConfig::isDetectionOnly() const 0742 { 0743 return mDetectionOnly; 0744 } 0745 0746 bool AntiSpamWizard::SpamToolConfig::isUseRegExp() const 0747 { 0748 return mUseRegExp; 0749 } 0750 0751 bool AntiSpamWizard::SpamToolConfig::useBayesFilter() const 0752 { 0753 return mSupportsBayesFilter; 0754 } 0755 0756 bool AntiSpamWizard::SpamToolConfig::hasTristateDetection() const 0757 { 0758 return mSupportsUnsure; 0759 } 0760 0761 AntiSpamWizard::WizardMode AntiSpamWizard::SpamToolConfig::getType() const 0762 { 0763 return mType; 0764 } 0765 0766 bool AntiSpamWizard::SpamToolConfig::isSpamTool() const 0767 { 0768 return mType == AntiSpam; 0769 } 0770 0771 bool AntiSpamWizard::SpamToolConfig::isVirusTool() const 0772 { 0773 return mType == AntiVirus; 0774 } 0775 0776 //--------------------------------------------------------------------------- 0777 AntiSpamWizard::ConfigReader::ConfigReader(WizardMode mode, QList<SpamToolConfig> &configList) 0778 : mToolList(configList) 0779 , mMode(mode) 0780 { 0781 if (mMode == AntiSpam) { 0782 mConfig = KSharedConfig::openConfig(QStringLiteral("kmail.antispamrc")); 0783 } else { 0784 mConfig = KSharedConfig::openConfig(QStringLiteral("kmail.antivirusrc")); 0785 } 0786 } 0787 0788 AntiSpamWizard::ConfigReader::~ConfigReader() = default; 0789 0790 void AntiSpamWizard::ConfigReader::readAndMergeConfig() 0791 { 0792 QString groupName = (mMode == AntiSpam) ? QStringLiteral("Spamtool #%1") : QStringLiteral("Virustool #%1"); 0793 // read the configuration from the global config file 0794 mConfig->setReadDefaults(true); 0795 KConfigGroup general(mConfig, QStringLiteral("General")); 0796 const int registeredTools = general.readEntry("tools", 0); 0797 for (int i = 1; i <= registeredTools; ++i) { 0798 KConfigGroup toolConfig(mConfig, groupName.arg(i)); 0799 if (!toolConfig.readEntry("HeadersOnly", false)) { 0800 mToolList.append(readToolConfig(toolConfig)); 0801 } 0802 } 0803 0804 // read the configuration from the user config file 0805 // and merge newer config data 0806 mConfig->setReadDefaults(false); 0807 KConfigGroup user_general(mConfig, QStringLiteral("General")); 0808 const int user_registeredTools = user_general.readEntry("tools", 0); 0809 for (int i = 1; i <= user_registeredTools; ++i) { 0810 KConfigGroup toolConfig(mConfig, groupName.arg(i)); 0811 if (!toolConfig.readEntry("HeadersOnly", false)) { 0812 mergeToolConfig(readToolConfig(toolConfig)); 0813 } 0814 } 0815 // Make sure to have add least one tool listed even when the 0816 // config file was not found or whatever went wrong 0817 // Currently only works for spam tools 0818 if (mMode == AntiSpam) { 0819 if (registeredTools < 1 && user_registeredTools < 1) { 0820 mToolList.append(createDummyConfig()); 0821 } 0822 sortToolList(); 0823 } 0824 } 0825 0826 AntiSpamWizard::SpamToolConfig AntiSpamWizard::ConfigReader::readToolConfig(KConfigGroup &configGroup) 0827 { 0828 const QString id = configGroup.readEntry("Ident"); 0829 const int version = configGroup.readEntry("Version", 0); 0830 #ifndef NDEBUG 0831 qDebug() << "Found predefined tool:" << id; 0832 qDebug() << "With config version :" << version; 0833 #endif 0834 const int prio = configGroup.readEntry("Priority", 1); 0835 const QString name = configGroup.readEntry("VisibleName"); 0836 const QString executable = configGroup.readEntry("Executable"); 0837 const QString url = configGroup.readEntry("URL"); 0838 const QString filterName = configGroup.readEntry("PipeFilterName"); 0839 const QString detectCmd = configGroup.readEntry("PipeCmdDetect"); 0840 const QString spamCmd = configGroup.readEntry("ExecCmdSpam"); 0841 const QString hamCmd = configGroup.readEntry("ExecCmdHam"); 0842 const QString noSpamCmd = configGroup.readEntry("PipeCmdNoSpam"); 0843 const QString header = configGroup.readEntry("DetectionHeader"); 0844 const QString pattern = configGroup.readEntry("DetectionPattern"); 0845 const QString pattern2 = configGroup.readEntry("DetectionPattern2"); 0846 const QString serverPattern = configGroup.readEntry("ServerPattern"); 0847 const bool detectionOnly = configGroup.readEntry("DetectionOnly", false); 0848 const bool useRegExp = configGroup.readEntry("UseRegExp", false); 0849 const bool supportsBayes = configGroup.readEntry("SupportsBayes", false); 0850 const bool supportsUnsure = configGroup.readEntry("SupportsUnsure", false); 0851 return SpamToolConfig(id, 0852 version, 0853 prio, 0854 name, 0855 executable, 0856 url, 0857 filterName, 0858 detectCmd, 0859 spamCmd, 0860 hamCmd, 0861 noSpamCmd, 0862 header, 0863 pattern, 0864 pattern2, 0865 serverPattern, 0866 detectionOnly, 0867 useRegExp, 0868 supportsBayes, 0869 supportsUnsure, 0870 mMode); 0871 } 0872 0873 AntiSpamWizard::SpamToolConfig AntiSpamWizard::ConfigReader::createDummyConfig() 0874 { 0875 return SpamToolConfig(QStringLiteral("spamassassin"), 0876 0, 0877 1, 0878 QStringLiteral("SpamAssassin"), 0879 QStringLiteral("spamassassin -V"), 0880 QStringLiteral("https://spamassassin.apache.org/"), 0881 QStringLiteral("SpamAssassin Check"), 0882 QStringLiteral("spamassassin -L"), 0883 QStringLiteral("sa-learn -L --spam --no-sync --single"), 0884 QStringLiteral("sa-learn -L --ham --no-sync --single"), 0885 QStringLiteral("spamassassin -d"), 0886 QStringLiteral("X-Spam-Status"), 0887 QStringLiteral("yes"), 0888 QString(), 0889 QString(), 0890 false, 0891 false, 0892 true, 0893 false, 0894 AntiSpam); 0895 } 0896 0897 void AntiSpamWizard::ConfigReader::mergeToolConfig(const AntiSpamWizard::SpamToolConfig &config) 0898 { 0899 bool found = false; 0900 QList<SpamToolConfig>::Iterator end(mToolList.end()); 0901 for (QList<SpamToolConfig>::Iterator it = mToolList.begin(); it != end; ++it) { 0902 #ifndef NDEBUG 0903 qDebug() << "Check against tool:" << (*it).getId(); 0904 qDebug() << "Against version :" << (*it).getVersion(); 0905 #endif 0906 if ((*it).getId() == config.getId()) { 0907 found = true; 0908 if ((*it).getVersion() < config.getVersion()) { 0909 #ifndef NDEBUG 0910 qDebug() << "Replacing config ..."; 0911 #endif 0912 mToolList.erase(it); 0913 mToolList.append(config); 0914 } 0915 break; 0916 } 0917 } 0918 if (!found) { 0919 mToolList.append(config); 0920 } 0921 } 0922 0923 void AntiSpamWizard::ConfigReader::sortToolList() 0924 { 0925 QList<SpamToolConfig> tmpList; 0926 SpamToolConfig config; 0927 0928 while (!mToolList.isEmpty()) { 0929 QList<SpamToolConfig>::Iterator highest; 0930 int priority = 0; // ascending 0931 QList<SpamToolConfig>::Iterator end(mToolList.end()); 0932 for (QList<SpamToolConfig>::Iterator it = mToolList.begin(); it != end; ++it) { 0933 if ((*it).getPrio() > priority) { 0934 priority = (*it).getPrio(); 0935 highest = it; 0936 } 0937 } 0938 config = (*highest); 0939 tmpList.append(config); 0940 mToolList.erase(highest); 0941 } 0942 QList<SpamToolConfig>::ConstIterator end(tmpList.constEnd()); 0943 for (QList<SpamToolConfig>::ConstIterator it = tmpList.constBegin(); it != end; ++it) { 0944 mToolList.append((*it)); 0945 } 0946 } 0947 0948 //--------------------------------------------------------------------------- 0949 ASWizPage::ASWizPage(QWidget *parent, const QString &name) 0950 : QWidget(parent) 0951 { 0952 setObjectName(name); 0953 mLayout = new QHBoxLayout(this); 0954 0955 auto sideLayout = new QVBoxLayout(); 0956 mLayout->addItem(sideLayout); 0957 mLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Minimum, QSizePolicy::Expanding)); 0958 0959 QPixmap banner; 0960 banner.load(QStringLiteral(":/org/kde/kmail/pics/kmwizard.png")); 0961 auto bannerLabel = new QLabel(this); 0962 bannerLabel->setPixmap(banner); 0963 bannerLabel->setScaledContents(false); 0964 bannerLabel->setFrameShape(QFrame::StyledPanel); 0965 bannerLabel->setFrameShadow(QFrame::Sunken); 0966 bannerLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0967 0968 sideLayout->addWidget(bannerLabel); 0969 sideLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Minimum, QSizePolicy::Expanding)); 0970 } 0971 0972 //--------------------------------------------------------------------------- 0973 ASWizInfoPage::ASWizInfoPage(AntiSpamWizard::WizardMode mode, QWidget *parent, const QString &name) 0974 : ASWizPage(parent, name) 0975 { 0976 QBoxLayout *layout = new QVBoxLayout(); 0977 mLayout->addItem(layout); 0978 0979 auto introText = new QTextEdit(this); 0980 introText->setText((mode == AntiSpamWizard::AntiSpam) ? i18n("The wizard will search for any tools to do spam detection\n" 0981 "and setup KMail to work with them.") 0982 : i18n("<p>Here you can get some assistance in setting up KMail's filter " 0983 "rules to use some commonly-known anti-virus tools.</p>" 0984 "<p>The wizard can detect those tools on your computer as " 0985 "well as create filter rules to classify messages using these " 0986 "tools and to separate messages containing viruses. " 0987 "The wizard will not take any existing filter " 0988 "rules into consideration: it will always append the new rules.</p>" 0989 "<p><b>Warning:</b> As KMail appears to be frozen during the scan of the " 0990 "messages for viruses, you may encounter problems with " 0991 "the responsiveness of KMail because anti-virus tool " 0992 "operations are usually time consuming; please consider " 0993 "deleting the filter rules created by the wizard to get " 0994 "back to the former behavior.</p>")); 0995 introText->setReadOnly(true); 0996 introText->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); 0997 layout->addWidget(introText); 0998 0999 mScanProgressText = new QLabel(this); 1000 mScanProgressText->clear(); 1001 mScanProgressText->setWordWrap(true); 1002 layout->addWidget(mScanProgressText); 1003 1004 mToolsList = new QListWidget(this); 1005 mToolsList->hide(); 1006 mToolsList->setSelectionMode(QAbstractItemView::MultiSelection); 1007 mToolsList->setLayoutMode(QListView::Batched); 1008 mToolsList->setBatchSize(10); 1009 mToolsList->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum)); 1010 layout->addWidget(mToolsList); 1011 connect(mToolsList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ASWizInfoPage::processSelectionChange); 1012 1013 mSelectionHint = new QLabel(this); 1014 mSelectionHint->clear(); 1015 mSelectionHint->setWordWrap(true); 1016 layout->addWidget(mSelectionHint); 1017 } 1018 1019 void ASWizInfoPage::setScanProgressText(const QString &toolName) 1020 { 1021 mScanProgressText->setText(toolName); 1022 } 1023 1024 void ASWizInfoPage::addAvailableTool(const QString &visibleName) 1025 { 1026 mToolsList->addItem(visibleName); 1027 if (!mToolsList->isVisible()) { 1028 mToolsList->show(); 1029 mToolsList->selectionModel()->clearSelection(); 1030 mToolsList->setCurrentRow(0); 1031 mSelectionHint->setText( 1032 i18n("<p>Please select the tools to be used " 1033 "for the detection and go " 1034 "to the next page.</p>")); 1035 } 1036 } 1037 1038 bool ASWizInfoPage::isProgramSelected(const QString &visibleName) const 1039 { 1040 const QList<QListWidgetItem *> foundItems = mToolsList->findItems(visibleName, Qt::MatchFixedString); 1041 return !foundItems.isEmpty() && foundItems[0]->isSelected(); 1042 } 1043 1044 void ASWizInfoPage::processSelectionChange() 1045 { 1046 Q_EMIT selectionChanged(); 1047 } 1048 1049 //--------------------------------------------------------------------------- 1050 ASWizSpamRulesPage::ASWizSpamRulesPage(QWidget *parent, const QString &name) 1051 : ASWizPage(parent, name) 1052 { 1053 auto layout = new QVBoxLayout(); 1054 mLayout->addItem(layout); 1055 1056 mMarkRules = new QCheckBox(i18n("&Mark detected spam messages as read"), this); 1057 mMarkRules->setWhatsThis(i18n("Mark messages which have been classified as spam as read.")); 1058 layout->addWidget(mMarkRules); 1059 1060 mMoveSpamRules = new QCheckBox(i18n("Move &known spam to:"), this); 1061 mMoveSpamRules->setWhatsThis( 1062 i18n("The default folder for spam messages is the trash folder, " 1063 "but you may change that in the folder view below.")); 1064 layout->addWidget(mMoveSpamRules); 1065 1066 mFolderReqForSpamFolder = new FolderRequester(this); 1067 mFolderReqForSpamFolder->setCollection(CommonKernel->trashCollectionFolder()); 1068 mFolderReqForSpamFolder->setMustBeReadWrite(true); 1069 mFolderReqForSpamFolder->setShowOutbox(false); 1070 1071 auto hLayout1 = new QHBoxLayout(); 1072 layout->addItem(hLayout1); 1073 hLayout1->addWidget(mFolderReqForSpamFolder); 1074 1075 mMoveUnsureRules = new QCheckBox(i18n("Move &probable spam to:"), this); 1076 mMoveUnsureRules->setWhatsThis( 1077 i18n("The default folder is the inbox folder, but you may change that " 1078 "in the folder view below.<p>" 1079 "Not all tools support a classification as unsure. If you have not " 1080 "selected a capable tool, you cannot select a folder as well.</p>")); 1081 layout->addWidget(mMoveUnsureRules); 1082 1083 mFolderReqForUnsureFolder = new FolderRequester(this); 1084 mFolderReqForUnsureFolder->setCollection(CommonKernel->inboxCollectionFolder()); 1085 mFolderReqForUnsureFolder->setMustBeReadWrite(true); 1086 mFolderReqForUnsureFolder->setShowOutbox(false); 1087 1088 auto hLayout2 = new QHBoxLayout(); 1089 layout->addItem(hLayout2); 1090 hLayout2->addWidget(mFolderReqForUnsureFolder); 1091 1092 layout->addStretch(); 1093 1094 connect(mMarkRules, &QAbstractButton::clicked, this, &ASWizSpamRulesPage::processSelectionChange); 1095 connect(mMoveSpamRules, &QAbstractButton::clicked, this, &ASWizSpamRulesPage::processSelectionChange); 1096 connect(mMoveUnsureRules, &QAbstractButton::clicked, this, &ASWizSpamRulesPage::processSelectionChange); 1097 connect(mFolderReqForSpamFolder, &FolderRequester::folderChanged, this, &ASWizSpamRulesPage::processSelectionChange); 1098 connect(mFolderReqForUnsureFolder, &FolderRequester::folderChanged, this, &ASWizSpamRulesPage::processSelectionChange); 1099 1100 mMarkRules->setChecked(true); 1101 mMoveSpamRules->setChecked(true); 1102 } 1103 1104 bool ASWizSpamRulesPage::markAsReadSelected() const 1105 { 1106 return mMarkRules->isChecked(); 1107 } 1108 1109 bool ASWizSpamRulesPage::moveSpamSelected() const 1110 { 1111 return mMoveSpamRules->isChecked(); 1112 } 1113 1114 bool ASWizSpamRulesPage::moveUnsureSelected() const 1115 { 1116 return mMoveUnsureRules->isChecked(); 1117 } 1118 1119 QString ASWizSpamRulesPage::selectedSpamCollectionId() const 1120 { 1121 return QString::number(selectedSpamCollection().id()); 1122 } 1123 1124 QString ASWizSpamRulesPage::selectedSpamCollectionName() const 1125 { 1126 return selectedSpamCollection().name(); 1127 } 1128 1129 Akonadi::Collection ASWizSpamRulesPage::selectedSpamCollection() const 1130 { 1131 if (mFolderReqForSpamFolder->hasCollection()) { 1132 return mFolderReqForSpamFolder->collection(); 1133 } else { 1134 return CommonKernel->trashCollectionFolder(); 1135 } 1136 } 1137 1138 Akonadi::Collection ASWizSpamRulesPage::selectedUnsureCollection() const 1139 { 1140 if (mFolderReqForUnsureFolder->hasCollection()) { 1141 return mFolderReqForUnsureFolder->collection(); 1142 } else { 1143 return CommonKernel->inboxCollectionFolder(); 1144 } 1145 } 1146 1147 QString ASWizSpamRulesPage::selectedUnsureCollectionName() const 1148 { 1149 return selectedUnsureCollection().name(); 1150 } 1151 1152 QString ASWizSpamRulesPage::selectedUnsureCollectionId() const 1153 { 1154 return QString::number(selectedUnsureCollection().id()); 1155 } 1156 1157 void ASWizSpamRulesPage::processSelectionChange() 1158 { 1159 mFolderReqForSpamFolder->setEnabled(mMoveSpamRules->isChecked()); 1160 mFolderReqForUnsureFolder->setEnabled(mMoveUnsureRules->isChecked()); 1161 Q_EMIT selectionChanged(); 1162 } 1163 1164 void ASWizSpamRulesPage::allowUnsureFolderSelection(bool enabled) 1165 { 1166 mMoveUnsureRules->setEnabled(enabled); 1167 mMoveUnsureRules->setVisible(enabled); 1168 mFolderReqForUnsureFolder->setEnabled(enabled); 1169 mFolderReqForUnsureFolder->setVisible(enabled); 1170 } 1171 1172 void ASWizSpamRulesPage::allowMoveSpam(bool enabled) 1173 { 1174 mMarkRules->setEnabled(enabled); 1175 mMarkRules->setChecked(enabled); 1176 mMoveSpamRules->setEnabled(enabled); 1177 mMoveSpamRules->setChecked(enabled); 1178 } 1179 1180 //--------------------------------------------------------------------------- 1181 ASWizVirusRulesPage::ASWizVirusRulesPage(QWidget *parent, const QString &name) 1182 : ASWizPage(parent, name) 1183 { 1184 auto grid = new QGridLayout(); 1185 mLayout->addItem(grid); 1186 1187 mPipeRules = new QCheckBox(i18n("Check messages using the anti-virus tools"), this); 1188 mPipeRules->setWhatsThis( 1189 i18n("Let the anti-virus tools check your messages. The wizard " 1190 "will create appropriate filters. The messages are usually " 1191 "marked by the tools so that following filters can react " 1192 "on this and, for example, move virus messages to a special folder.")); 1193 grid->addWidget(mPipeRules, 0, 0); 1194 1195 mMoveRules = new QCheckBox(i18n("Move detected viral messages to the selected folder"), this); 1196 mMoveRules->setWhatsThis( 1197 i18n("A filter to detect messages classified as virus-infected and to move " 1198 "those messages into a predefined folder is created. The " 1199 "default folder is the trash folder, but you may change that " 1200 "in the folder view.")); 1201 grid->addWidget(mMoveRules, 1, 0); 1202 1203 mMarkRules = new QCheckBox(i18n("Additionally, mark detected viral messages as read"), this); 1204 mMarkRules->setEnabled(false); 1205 mMarkRules->setWhatsThis( 1206 i18n("Mark messages which have been classified as " 1207 "virus-infected as read, as well as moving them " 1208 "to the selected folder.")); 1209 grid->addWidget(mMarkRules, 2, 0); 1210 FolderTreeWidget::TreeViewOptions opt = FolderTreeWidget::None; 1211 opt |= FolderTreeWidget::UseDistinctSelectionModel; 1212 1213 FolderTreeWidgetProxyModel::FolderTreeWidgetProxyModelOptions optReadableProxy = FolderTreeWidgetProxyModel::None; 1214 optReadableProxy |= FolderTreeWidgetProxyModel::HideVirtualFolder; 1215 optReadableProxy |= FolderTreeWidgetProxyModel::HideOutboxFolder; 1216 1217 mFolderTree = new FolderTreeWidget(this, nullptr, opt, optReadableProxy); 1218 mFolderTree->readConfig(); 1219 mFolderTree->folderTreeView()->expandAll(); 1220 mFolderTree->folderTreeWidgetProxyModel()->setAccessRights(Akonadi::Collection::CanCreateCollection); 1221 1222 mFolderTree->selectCollectionFolder(CommonKernel->trashCollectionFolder()); 1223 mFolderTree->folderTreeView()->setDragDropMode(QAbstractItemView::NoDragDrop); 1224 1225 mFolderTree->disableContextMenuAndExtraColumn(); 1226 grid->addWidget(mFolderTree, 3, 0); 1227 1228 connect(mPipeRules, &QCheckBox::clicked, this, &ASWizVirusRulesPage::processSelectionChange); 1229 connect(mMoveRules, &QCheckBox::clicked, this, &ASWizVirusRulesPage::processSelectionChange); 1230 connect(mMarkRules, &QCheckBox::clicked, this, &ASWizVirusRulesPage::processSelectionChange); 1231 connect(mMoveRules, &QCheckBox::toggled, mMarkRules, &QCheckBox::setEnabled); 1232 } 1233 1234 bool ASWizVirusRulesPage::pipeRulesSelected() const 1235 { 1236 return mPipeRules->isChecked(); 1237 } 1238 1239 bool ASWizVirusRulesPage::moveRulesSelected() const 1240 { 1241 return mMoveRules->isChecked(); 1242 } 1243 1244 bool ASWizVirusRulesPage::markReadRulesSelected() const 1245 { 1246 return mMarkRules->isChecked(); 1247 } 1248 1249 QString ASWizVirusRulesPage::selectedFolderName() const 1250 { 1251 if (mFolderTree->selectedCollection().isValid()) { 1252 return QString::number(mFolderTree->selectedCollection().id()); 1253 } else { 1254 return QString::number(CommonKernel->trashCollectionFolder().id()); 1255 } 1256 } 1257 1258 void ASWizVirusRulesPage::processSelectionChange() 1259 { 1260 Q_EMIT selectionChanged(); 1261 } 1262 1263 //--------------------------------------------------------------------------- 1264 ASWizSummaryPage::ASWizSummaryPage(QWidget *parent, const QString &name) 1265 : ASWizPage(parent, name) 1266 , mSummaryText(new QLabel(this)) 1267 { 1268 QBoxLayout *layout = new QVBoxLayout(); 1269 mLayout->addItem(layout); 1270 1271 layout->addWidget(mSummaryText); 1272 layout->addStretch(); 1273 } 1274 1275 void ASWizSummaryPage::setSummaryText(const QString &text) 1276 { 1277 mSummaryText->setText(text); 1278 } 1279 1280 #include "moc_antispamwizard.cpp"