1 /* -*- mode: C++ -*- 2 This file is part of KMail. 3 SPDX-FileCopyrightText: 2003 Andreas Gungl <a.gungl@gmx.de> 4 5 SPDX-License-Identifier: GPL-2.0-only 6 */ 7 8 #pragma once 9 10 #include <KAssistantDialog> 11 #include <KSharedConfig> 12 13 #include <Akonadi/Collection> 14 #include <QList> 15 16 class QLabel; 17 class QCheckBox; 18 class QBoxLayout; 19 class QListWidget; 20 21 namespace MailCommon 22 { 23 class FolderTreeWidget; 24 class FolderRequester; 25 } 26 27 namespace KMail 28 { 29 class ASWizInfoPage; 30 class ASWizSpamRulesPage; 31 class ASWizVirusRulesPage; 32 class ASWizSummaryPage; 33 34 //--------------------------------------------------------------------------- 35 /** 36 @short KMail anti-spam wizard. 37 @author Andreas Gungl <a.gungl@gmx.de> 38 39 The wizard helps to create filter rules to let KMail operate 40 with external anti-spam tools. The wizard tries to detect the 41 tools, but the user can override the preselections. 42 Then the user can decide what functionality shall be supported 43 by the created filter rules. 44 The wizard will append the created filter rules after the 45 last existing rule to keep possible conflicts with existing 46 filter configurations minimal. 47 48 Anti-virus support was added by Fred Emmott <fred87@users.sf.net> 49 50 The configuration for the tools to get checked and set up 51 is read from a config file. The structure of the file is as 52 following: 53 <pre> 54 [General] 55 tools=1 56 57 [Spamtool #1] 58 Ident=spamassassin 59 Version=0 60 Priority=1 61 VisibleName=&Spamassassin 62 Executable=spamassassin -V 63 URL=http://spamassassin.org 64 PipeFilterName=SpamAssassin Check 65 PipeCmdDetect=spamassassin -L 66 ExecCmdSpam=sa-learn --spam --no-sync --single 67 ExecCmdHam=sa-learn --ham --no-sync --single 68 PipeCmdNoSpam=spamassassin -d 69 DetectionHeader=X-Spam-Status 70 DetectionPattern=yes 71 DetectionPattern2= 72 DetectionOnly=0 73 UseRegExp=0 74 SupportsBayes=1 75 SupportsUnsure=0 76 ServerSided=0 77 type=spam 78 </pre> 79 The name of the config file is kmail.antispamrc 80 and it's expected in the config dir of KDE. 81 82 */ 83 class AntiSpamWizard : public KAssistantDialog 84 { 85 Q_OBJECT 86 87 public: 88 /** The wizard can be used for setting up anti-spam tools and for 89 setting up anti-virus tools. 90 */ 91 enum WizardMode { 92 AntiSpam, 93 AntiVirus, 94 }; 95 96 /** Constructor that needs to initialize from the main folder tree 97 of KMail. 98 @param mode The mode the wizard should run in. 99 @param parent The parent widget for the wizard. 100 @param mainFolderTree The main folder tree from which the folders 101 are copied to allow the selection of a spam folder in a tree 102 within one of the wizard pages. 103 */ 104 AntiSpamWizard(WizardMode mode, QWidget *parent); 105 106 protected: 107 /** 108 Instances of this class store the settings for one tool as read from 109 the config file. Visible name and What's this text cannot get 110 translated! 111 */ 112 class SpamToolConfig 113 { 114 public: SpamToolConfig()115 SpamToolConfig() 116 { 117 } 118 119 SpamToolConfig(const QString &toolId, 120 int configVersion, 121 int prio, 122 const QString &name, 123 const QString &exec, 124 const QString &url, 125 const QString &filter, 126 const QString &detection, 127 const QString &spam, 128 const QString &ham, 129 const QString &noSpam, 130 const QString &header, 131 const QString &pattern, 132 const QString &pattern2, 133 const QString &serverPattern, 134 bool detectionOnly, 135 bool regExp, 136 bool bayesFilter, 137 bool tristateDetection, 138 WizardMode type); 139 140 Q_REQUIRED_RESULT int getVersion() const; 141 Q_REQUIRED_RESULT int getPrio() const; 142 Q_REQUIRED_RESULT QString getId() const; 143 Q_REQUIRED_RESULT QString getVisibleName() const; 144 Q_REQUIRED_RESULT QString getExecutable() const; 145 Q_REQUIRED_RESULT QString getWhatsThisText() const; 146 Q_REQUIRED_RESULT QString getFilterName() const; 147 Q_REQUIRED_RESULT QString getDetectCmd() const; 148 Q_REQUIRED_RESULT QString getSpamCmd() const; 149 Q_REQUIRED_RESULT QString getHamCmd() const; 150 Q_REQUIRED_RESULT QString getNoSpamCmd() const; 151 Q_REQUIRED_RESULT QString getDetectionHeader() const; 152 Q_REQUIRED_RESULT QString getDetectionPattern() const; 153 Q_REQUIRED_RESULT QString getDetectionPattern2() const; 154 Q_REQUIRED_RESULT QString getServerPattern() const; 155 Q_REQUIRED_RESULT bool isServerBased() const; 156 Q_REQUIRED_RESULT bool isDetectionOnly() const; 157 Q_REQUIRED_RESULT bool isUseRegExp() const; 158 Q_REQUIRED_RESULT bool useBayesFilter() const; 159 Q_REQUIRED_RESULT bool hasTristateDetection() const; 160 Q_REQUIRED_RESULT WizardMode getType() const; 161 // convenience methods for types 162 Q_REQUIRED_RESULT bool isSpamTool() const; 163 Q_REQUIRED_RESULT bool isVirusTool() const; 164 165 private: 166 // used to identify configs for the same tool 167 QString mId; 168 // The version of the config data, used for merging and 169 // detecting newer configs 170 int mVersion; 171 // the priority of the tool in the list presented to the user 172 int mPrio; 173 // the name as shown by the checkbox in the dialog page 174 QString mVisibleName; 175 // the command to check the existence of the tool 176 QString mExecutable; 177 // the What's This help text (e.g. url for the tool) 178 QString mWhatsThisText; 179 // name for the created filter in the filter list 180 QString mFilterName; 181 // pipe through cmd used to detect spam messages 182 QString mDetectCmd; 183 // pipe through cmd to let the tool learn a spam message 184 QString mSpamCmd; 185 // pipe through cmd to let the tool learn a ham message 186 QString mHamCmd; 187 // pipe through cmd to let the tool delete the spam markup 188 QString mNoSpamCmd; 189 // by which header are messages marked as spam 190 QString mDetectionHeader; 191 // what header pattern is used to mark spam messages 192 QString mDetectionPattern; 193 // what header pattern is used to mark unsure messages 194 QString mDetectionPattern2; 195 // what header pattern is used in the account to check for a certain server 196 QString mServerPattern; 197 // filter cannot search actively but relies on pattern by regExp or contain rule 198 bool mDetectionOnly; 199 // filter searches for the pattern by regExp or contain rule 200 bool mUseRegExp; 201 // can the tool learn spam and ham, has it a bayesian algorithm 202 bool mSupportsBayesFilter; 203 // differentiate between ham, spam and a third "unsure" state 204 bool mSupportsUnsure; 205 // Is the tool AntiSpam or AntiVirus 206 WizardMode mType; 207 }; 208 209 /** 210 Instances of this class control reading the configuration of the 211 anti-spam tools from global and user config files as well as the 212 merging of different config versions. 213 */ 214 class ConfigReader 215 { 216 public: 217 ConfigReader(WizardMode mode, QVector<SpamToolConfig> &configList); 218 ~ConfigReader(); 219 getToolList()220 QVector<SpamToolConfig> &getToolList() 221 { 222 return mToolList; 223 } 224 225 void readAndMergeConfig(); 226 227 private: 228 QVector<SpamToolConfig> &mToolList; 229 KSharedConfig::Ptr mConfig; 230 WizardMode mMode; 231 232 SpamToolConfig readToolConfig(KConfigGroup &configGroup); 233 SpamToolConfig createDummyConfig(); 234 235 void mergeToolConfig(const SpamToolConfig &config); 236 void sortToolList(); 237 }; 238 239 /** Evaluate the settings made and create the appropriate filter rules. */ 240 void accept() override; 241 242 protected Q_SLOTS: 243 /** Modify the status of the wizard to reflect the selection of spam tools. */ 244 void checkProgramsSelections(); 245 /** Modify the status of the wizard to reflect the selected functionality. */ 246 void checkVirusRulesSelections(); 247 /** Check if the spam tools are available via the PATH */ 248 void checkToolAvailability(); 249 /** Show a help topic */ 250 void slotHelpClicked(); 251 /** Create the summary text based on the current settings */ 252 void slotBuildSummary(); 253 254 private: 255 /* Check for the availability of an executible along the PATH */ 256 Q_REQUIRED_RESULT int checkForProgram(const QString &executable) const; 257 /* generic checks if any option in a page is checked */ 258 Q_REQUIRED_RESULT bool anyVirusOptionChecked() const; 259 /* convenience method calling the appropriate filter manager method */ 260 const QString uniqueNameFor(const QString &name); 261 /* convenience method to sort out new and existing filters */ 262 void sortFilterOnExistance(const QString &intendedFilterName, QString &newFilters, QString &replaceFilters); 263 264 /* The pages in the wizard */ 265 ASWizInfoPage *mInfoPage = nullptr; 266 ASWizSpamRulesPage *mSpamRulesPage = nullptr; 267 ASWizVirusRulesPage *mVirusRulesPage = nullptr; 268 ASWizSummaryPage *mSummaryPage = nullptr; 269 270 KPageWidgetItem *mInfoPageItem = nullptr; 271 KPageWidgetItem *mSpamRulesPageItem = nullptr; 272 KPageWidgetItem *mVirusRulesPageItem = nullptr; 273 KPageWidgetItem *mSummaryPageItem = nullptr; 274 275 /* The configured tools and it's settings to be used in the wizard. */ 276 QVector<SpamToolConfig> mToolList; 277 278 /* Are any spam tools selected? */ 279 bool mSpamToolsUsed; 280 /* Are any virus tools selected? */ 281 bool mVirusToolsUsed; 282 283 WizardMode mMode; 284 }; 285 286 //--------------------------------------------------------------------------- 287 class ASWizPage : public QWidget 288 { 289 Q_OBJECT 290 public: 291 ASWizPage(QWidget *parent, const QString &name); 292 293 protected: 294 QBoxLayout *mLayout = nullptr; 295 }; 296 297 //--------------------------------------------------------------------------- 298 class ASWizInfoPage : public ASWizPage 299 { 300 Q_OBJECT 301 302 public: 303 ASWizInfoPage(AntiSpamWizard::WizardMode mode, QWidget *parent, const QString &name); 304 305 void setScanProgressText(const QString &toolName); 306 void addAvailableTool(const QString &visibleName); 307 Q_REQUIRED_RESULT bool isProgramSelected(const QString &visibleName) const; 308 309 Q_SIGNALS: 310 void selectionChanged(); 311 312 private: 313 void processSelectionChange(); 314 QLabel *mScanProgressText = nullptr; 315 QLabel *mSelectionHint = nullptr; 316 QListWidget *mToolsList = nullptr; 317 }; 318 319 //--------------------------------------------------------------------------- 320 class ASWizSpamRulesPage : public ASWizPage 321 { 322 Q_OBJECT 323 324 public: 325 ASWizSpamRulesPage(QWidget *parent, const QString &name); 326 327 Q_REQUIRED_RESULT bool markAsReadSelected() const; 328 Q_REQUIRED_RESULT bool moveSpamSelected() const; 329 Q_REQUIRED_RESULT bool moveUnsureSelected() const; 330 331 Q_REQUIRED_RESULT QString selectedUnsureCollectionName() const; 332 Q_REQUIRED_RESULT QString selectedUnsureCollectionId() const; 333 334 void allowUnsureFolderSelection(bool enabled); 335 void allowMoveSpam(bool enabled); 336 337 Q_REQUIRED_RESULT QString selectedSpamCollectionId() const; 338 Q_REQUIRED_RESULT QString selectedSpamCollectionName() const; 339 340 protected: 341 Akonadi::Collection selectedSpamCollection() const; 342 Akonadi::Collection selectedUnsureCollection() const; 343 344 Q_SIGNALS: 345 void selectionChanged(); 346 347 private: 348 void processSelectionChange(); 349 QCheckBox *mMarkRules = nullptr; 350 QCheckBox *mMoveSpamRules = nullptr; 351 QCheckBox *mMoveUnsureRules = nullptr; 352 MailCommon::FolderRequester *mFolderReqForSpamFolder = nullptr; 353 MailCommon::FolderRequester *mFolderReqForUnsureFolder = nullptr; 354 }; 355 356 //------------------------------------------------------------------------- 357 class ASWizVirusRulesPage : public ASWizPage 358 { 359 Q_OBJECT 360 361 public: 362 ASWizVirusRulesPage(QWidget *parent, const QString &name); 363 364 Q_REQUIRED_RESULT bool pipeRulesSelected() const; 365 Q_REQUIRED_RESULT bool moveRulesSelected() const; 366 Q_REQUIRED_RESULT bool markReadRulesSelected() const; 367 368 Q_REQUIRED_RESULT QString selectedFolderName() const; 369 370 Q_SIGNALS: 371 void selectionChanged(); 372 373 private: 374 void processSelectionChange(); 375 QCheckBox *mPipeRules = nullptr; 376 QCheckBox *mMoveRules = nullptr; 377 MailCommon::FolderTreeWidget *mFolderTree = nullptr; 378 QCheckBox *mMarkRules = nullptr; 379 }; 380 381 //--------------------------------------------------------------------------- 382 class ASWizSummaryPage : public ASWizPage 383 { 384 Q_OBJECT 385 386 public: 387 ASWizSummaryPage(QWidget *parent, const QString &name); 388 389 void setSummaryText(const QString &text); 390 391 private: 392 QLabel *mSummaryText = nullptr; 393 }; 394 } // namespace KMail 395