File indexing completed on 2025-01-05 04:49:33

0001 /*  -*- mode: C++ -*-
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 #pragma once
0009 
0010 #include <KAssistantDialog>
0011 #include <KSharedConfig>
0012 
0013 #include <Akonadi/Collection>
0014 #include <QList>
0015 
0016 class QLabel;
0017 class QCheckBox;
0018 class QBoxLayout;
0019 class QListWidget;
0020 
0021 namespace MailCommon
0022 {
0023 class FolderTreeWidget;
0024 class FolderRequester;
0025 }
0026 
0027 namespace KMail
0028 {
0029 class ASWizInfoPage;
0030 class ASWizSpamRulesPage;
0031 class ASWizVirusRulesPage;
0032 class ASWizSummaryPage;
0033 
0034 //---------------------------------------------------------------------------
0035 /**
0036     @short KMail anti-spam wizard.
0037     @author Andreas Gungl <a.gungl@gmx.de>
0038 
0039     The wizard helps to create filter rules to let KMail operate
0040     with external anti-spam tools. The wizard tries to detect the
0041     tools, but the user can override the preselections.
0042     Then the user can decide what functionality shall be supported
0043     by the created filter rules.
0044     The wizard will append the created filter rules after the
0045     last existing rule to keep possible conflicts with existing
0046     filter configurations minimal.
0047 
0048     Anti-virus support was added by Fred Emmott <fred87@users.sf.net>
0049 
0050     The configuration for the tools to get checked and set up
0051     is read from a config file. The structure of the file is as
0052     following:
0053     <pre>
0054     [General]
0055     tools=1
0056 
0057     [Spamtool #1]
0058     Ident=spamassassin
0059     Version=0
0060     Priority=1
0061     VisibleName=&Spamassassin
0062     Executable=spamassassin -V
0063     URL=http://spamassassin.org
0064     PipeFilterName=SpamAssassin Check
0065     PipeCmdDetect=spamassassin -L
0066     ExecCmdSpam=sa-learn --spam --no-sync --single
0067     ExecCmdHam=sa-learn --ham --no-sync --single
0068     PipeCmdNoSpam=spamassassin -d
0069     DetectionHeader=X-Spam-Status
0070     DetectionPattern=yes
0071     DetectionPattern2=
0072     DetectionOnly=0
0073     UseRegExp=0
0074     SupportsBayes=1
0075     SupportsUnsure=0
0076     ServerSided=0
0077     type=spam
0078     </pre>
0079     The name of the config file is kmail.antispamrc
0080     and it's expected in the config dir of KDE.
0081 
0082   */
0083 class AntiSpamWizard : public KAssistantDialog
0084 {
0085     Q_OBJECT
0086 
0087 public:
0088     /** The wizard can be used for setting up anti-spam tools and for
0089           setting up anti-virus tools.
0090       */
0091     enum WizardMode {
0092         AntiSpam,
0093         AntiVirus,
0094     };
0095 
0096     /** Constructor that needs to initialize from the main folder tree
0097         of KMail.
0098         @param mode The mode the wizard should run in.
0099         @param parent The parent widget for the wizard.
0100         @param mainFolderTree The main folder tree from which the folders
0101           are copied to allow the selection of a spam folder in a tree
0102           within one of the wizard pages.
0103       */
0104     AntiSpamWizard(WizardMode mode, QWidget *parent);
0105 
0106 protected:
0107     /**
0108         Instances of this class store the settings for one tool as read from
0109         the config file. Visible name and What's this text cannot get
0110         translated!
0111       */
0112     class SpamToolConfig
0113     {
0114     public:
0115         SpamToolConfig() = default;
0116 
0117         SpamToolConfig(const QString &toolId,
0118                        int configVersion,
0119                        int prio,
0120                        const QString &name,
0121                        const QString &exec,
0122                        const QString &url,
0123                        const QString &filter,
0124                        const QString &detection,
0125                        const QString &spam,
0126                        const QString &ham,
0127                        const QString &noSpam,
0128                        const QString &header,
0129                        const QString &pattern,
0130                        const QString &pattern2,
0131                        const QString &serverPattern,
0132                        bool detectionOnly,
0133                        bool regExp,
0134                        bool bayesFilter,
0135                        bool tristateDetection,
0136                        WizardMode type);
0137 
0138         [[nodiscard]] int getVersion() const;
0139         [[nodiscard]] int getPrio() const;
0140         [[nodiscard]] QString getId() const;
0141         [[nodiscard]] QString getVisibleName() const;
0142         [[nodiscard]] QString getExecutable() const;
0143         [[nodiscard]] QString getWhatsThisText() const;
0144         [[nodiscard]] QString getFilterName() const;
0145         [[nodiscard]] QString getDetectCmd() const;
0146         [[nodiscard]] QString getSpamCmd() const;
0147         [[nodiscard]] QString getHamCmd() const;
0148         [[nodiscard]] QString getNoSpamCmd() const;
0149         [[nodiscard]] QString getDetectionHeader() const;
0150         [[nodiscard]] QString getDetectionPattern() const;
0151         [[nodiscard]] QString getDetectionPattern2() const;
0152         [[nodiscard]] QString getServerPattern() const;
0153         [[nodiscard]] bool isServerBased() const;
0154         [[nodiscard]] bool isDetectionOnly() const;
0155         [[nodiscard]] bool isUseRegExp() const;
0156         [[nodiscard]] bool useBayesFilter() const;
0157         [[nodiscard]] bool hasTristateDetection() const;
0158         [[nodiscard]] WizardMode getType() const;
0159         // convenience methods for types
0160         [[nodiscard]] bool isSpamTool() const;
0161         [[nodiscard]] bool isVirusTool() const;
0162 
0163     private:
0164         // used to identify configs for the same tool
0165         QString mId;
0166         // The version of the config data, used for merging and
0167         // detecting newer configs
0168         int mVersion;
0169         // the priority of the tool in the list presented to the user
0170         int mPrio;
0171         // the name as shown by the checkbox in the dialog page
0172         QString mVisibleName;
0173         // the command to check the existence of the tool
0174         QString mExecutable;
0175         // the What's This help text (e.g. url for the tool)
0176         QString mWhatsThisText;
0177         // name for the created filter in the filter list
0178         QString mFilterName;
0179         // pipe through cmd used to detect spam messages
0180         QString mDetectCmd;
0181         // pipe through cmd to let the tool learn a spam message
0182         QString mSpamCmd;
0183         // pipe through cmd to let the tool learn a ham message
0184         QString mHamCmd;
0185         // pipe through cmd to let the tool delete the spam markup
0186         QString mNoSpamCmd;
0187         // by which header are messages marked as spam
0188         QString mDetectionHeader;
0189         // what header pattern is used to mark spam messages
0190         QString mDetectionPattern;
0191         // what header pattern is used to mark unsure messages
0192         QString mDetectionPattern2;
0193         // what header pattern is used in the account to check for a certain server
0194         QString mServerPattern;
0195         // filter cannot search actively but relies on pattern by regExp or contain rule
0196         bool mDetectionOnly;
0197         // filter searches for the pattern by regExp or contain rule
0198         bool mUseRegExp;
0199         // can the tool learn spam and ham, has it a bayesian algorithm
0200         bool mSupportsBayesFilter;
0201         // differentiate between ham, spam and a third "unsure" state
0202         bool mSupportsUnsure;
0203         // Is the tool AntiSpam or AntiVirus
0204         WizardMode mType;
0205     };
0206 
0207     /**
0208         Instances of this class control reading the configuration of the
0209         anti-spam tools from global and user config files as well as the
0210         merging of different config versions.
0211       */
0212     class ConfigReader
0213     {
0214     public:
0215         ConfigReader(WizardMode mode, QList<SpamToolConfig> &configList);
0216         ~ConfigReader();
0217 
0218         QList<SpamToolConfig> &getToolList()
0219         {
0220             return mToolList;
0221         }
0222 
0223         void readAndMergeConfig();
0224 
0225     private:
0226         QList<SpamToolConfig> &mToolList;
0227         KSharedConfig::Ptr mConfig;
0228         WizardMode mMode;
0229 
0230         SpamToolConfig readToolConfig(KConfigGroup &configGroup);
0231         SpamToolConfig createDummyConfig();
0232 
0233         void mergeToolConfig(const SpamToolConfig &config);
0234         void sortToolList();
0235     };
0236 
0237     /** Evaluate the settings made and create the appropriate filter rules. */
0238     void accept() override;
0239 
0240 protected Q_SLOTS:
0241     /** Modify the status of the wizard to reflect the selection of spam tools. */
0242     void checkProgramsSelections();
0243     /** Modify the status of the wizard to reflect the selected functionality. */
0244     void checkVirusRulesSelections();
0245     /** Check if the spam tools are available via the PATH */
0246     void checkToolAvailability();
0247     /** Show a help topic */
0248     void slotHelpClicked();
0249     /** Create the summary text based on the current settings */
0250     void slotBuildSummary();
0251 
0252 private:
0253     /* Check for the availability of an executible along the PATH */
0254     [[nodiscard]] int checkForProgram(const QString &executable) const;
0255     /* generic checks if any option in a page is checked */
0256     [[nodiscard]] bool anyVirusOptionChecked() const;
0257     /* convenience method calling the appropriate filter manager method */
0258     const QString uniqueNameFor(const QString &name);
0259     /* convenience method to sort out new and existing filters */
0260     void sortFilterOnExistance(const QString &intendedFilterName, QString &newFilters, QString &replaceFilters);
0261 
0262     /* The pages in the wizard */
0263     ASWizInfoPage *mInfoPage = nullptr;
0264     ASWizSpamRulesPage *mSpamRulesPage = nullptr;
0265     ASWizVirusRulesPage *mVirusRulesPage = nullptr;
0266     ASWizSummaryPage *mSummaryPage = nullptr;
0267 
0268     KPageWidgetItem *mInfoPageItem = nullptr;
0269     KPageWidgetItem *mSpamRulesPageItem = nullptr;
0270     KPageWidgetItem *mVirusRulesPageItem = nullptr;
0271     KPageWidgetItem *mSummaryPageItem = nullptr;
0272 
0273     /* The configured tools and it's settings to be used in the wizard. */
0274     QList<SpamToolConfig> mToolList;
0275 
0276     /* Are any spam tools selected? */
0277     bool mSpamToolsUsed;
0278     /* Are any virus tools selected? */
0279     bool mVirusToolsUsed;
0280 
0281     WizardMode mMode;
0282 };
0283 
0284 //---------------------------------------------------------------------------
0285 class ASWizPage : public QWidget
0286 {
0287     Q_OBJECT
0288 public:
0289     ASWizPage(QWidget *parent, const QString &name);
0290 
0291 protected:
0292     QBoxLayout *mLayout = nullptr;
0293 };
0294 
0295 //---------------------------------------------------------------------------
0296 class ASWizInfoPage : public ASWizPage
0297 {
0298     Q_OBJECT
0299 
0300 public:
0301     ASWizInfoPage(AntiSpamWizard::WizardMode mode, QWidget *parent, const QString &name);
0302 
0303     void setScanProgressText(const QString &toolName);
0304     void addAvailableTool(const QString &visibleName);
0305     [[nodiscard]] bool isProgramSelected(const QString &visibleName) const;
0306 
0307 Q_SIGNALS:
0308     void selectionChanged();
0309 
0310 private:
0311     void processSelectionChange();
0312     QLabel *mScanProgressText = nullptr;
0313     QLabel *mSelectionHint = nullptr;
0314     QListWidget *mToolsList = nullptr;
0315 };
0316 
0317 //---------------------------------------------------------------------------
0318 class ASWizSpamRulesPage : public ASWizPage
0319 {
0320     Q_OBJECT
0321 
0322 public:
0323     ASWizSpamRulesPage(QWidget *parent, const QString &name);
0324 
0325     [[nodiscard]] bool markAsReadSelected() const;
0326     [[nodiscard]] bool moveSpamSelected() const;
0327     [[nodiscard]] bool moveUnsureSelected() const;
0328 
0329     [[nodiscard]] QString selectedUnsureCollectionName() const;
0330     [[nodiscard]] QString selectedUnsureCollectionId() const;
0331 
0332     void allowUnsureFolderSelection(bool enabled);
0333     void allowMoveSpam(bool enabled);
0334 
0335     [[nodiscard]] QString selectedSpamCollectionId() const;
0336     [[nodiscard]] QString selectedSpamCollectionName() const;
0337 
0338 protected:
0339     Akonadi::Collection selectedSpamCollection() const;
0340     Akonadi::Collection selectedUnsureCollection() const;
0341 
0342 Q_SIGNALS:
0343     void selectionChanged();
0344 
0345 private:
0346     void processSelectionChange();
0347     QCheckBox *mMarkRules = nullptr;
0348     QCheckBox *mMoveSpamRules = nullptr;
0349     QCheckBox *mMoveUnsureRules = nullptr;
0350     MailCommon::FolderRequester *mFolderReqForSpamFolder = nullptr;
0351     MailCommon::FolderRequester *mFolderReqForUnsureFolder = nullptr;
0352 };
0353 
0354 //-------------------------------------------------------------------------
0355 class ASWizVirusRulesPage : public ASWizPage
0356 {
0357     Q_OBJECT
0358 
0359 public:
0360     ASWizVirusRulesPage(QWidget *parent, const QString &name);
0361 
0362     [[nodiscard]] bool pipeRulesSelected() const;
0363     [[nodiscard]] bool moveRulesSelected() const;
0364     [[nodiscard]] bool markReadRulesSelected() const;
0365 
0366     [[nodiscard]] QString selectedFolderName() const;
0367 
0368 Q_SIGNALS:
0369     void selectionChanged();
0370 
0371 private:
0372     void processSelectionChange();
0373     QCheckBox *mPipeRules = nullptr;
0374     QCheckBox *mMoveRules = nullptr;
0375     MailCommon::FolderTreeWidget *mFolderTree = nullptr;
0376     QCheckBox *mMarkRules = nullptr;
0377 };
0378 
0379 //---------------------------------------------------------------------------
0380 class ASWizSummaryPage : public ASWizPage
0381 {
0382     Q_OBJECT
0383 
0384 public:
0385     ASWizSummaryPage(QWidget *parent, const QString &name);
0386 
0387     void setSummaryText(const QString &text);
0388 
0389 private:
0390     QLabel *const mSummaryText;
0391 };
0392 } // namespace KMail