--- kdepim-3.1.95/kmail/kmmainwin.rc-- 2004-01-20 08:13:24.417860544 -0500 +++ kdepim-3.1.95/kmail/kmmainwin.rc 2004-01-20 08:13:51.755704560 -0500 @@ -1,5 +1,5 @@ <!DOCTYPE kpartgui> -<kpartgui version="69" name="kmmainwin" > +<kpartgui version="70" name="kmmainwin" > <MenuBar> <Menu noMerge="1" name="file" > <text>&File</text> @@ -123,6 +123,8 @@ <Action name="filter" append="save_merge"/> <Action name="popFilter" append="save_merge"/> <Separator/> + <Action name="antiSpamWizard" append="save_merge"/> + <Separator/> <Action name="options_configure_keybinding" group="settings_configure"/> <Action name="kmail_configure_notifications" group="settings_configure"/> <Action name="options_configure_toolbars" group="settings_configure" /> --- kdepim-3.1.95/kmail/Makefile.am-- 2004-01-20 08:10:51.803061520 -0500 +++ kdepim-3.1.95/kmail/Makefile.am 2004-01-20 08:11:48.755403448 -0500 @@ -83,7 +83,7 @@ libkmailprivate_la_SOURCES = kmmessage.c folderIface.cpp folderIface.skel mailserviceimpl.cpp \ attachmentlistview.cpp ssllabel.cpp \ iobserver.cpp isubject.cpp bodyvisitor.cpp \ - urlhandlermanager.cpp dictionarycombobox.cpp startupwizard.cpp + urlhandlermanager.cpp dictionarycombobox.cpp startupwizard.cpp antispamwizard.cpp kmail_SOURCES = main.cpp @@ -117,6 +117,9 @@ update_DATA = kmail.upd upgrade-transpor kmail-3.2-update-loop-on-goto-unread-settings.sh \ kmail-3.2-misc.sh +confdir = $(kde_confdir) +conf_DATA = kmail.antispamrc + tipdir = $(kde_datadir)/kmail tip_DATA = tips --- kdepim-3.1.95/kmail/kmmainwidget.cpp-- 2004-01-20 08:10:26.723874136 -0500 +++ kdepim-3.1.95/kmail/kmmainwidget.cpp 2004-01-20 08:12:53.663535912 -0500 @@ -69,6 +69,9 @@ using KMail::HeaderStyle; #include "folderjob.h" using KMail::FolderJob; #include "mailinglist-magic.h" +#include "antispamwizard.h" +using KMail::AntiSpamWizard; +#include <kstandarddirs.h> #include "kmgroupware.h" #include <assert.h> @@ -2649,6 +2652,10 @@ void KMMainWidget::setupActions() (void) new KAction( i18n("Configure &POP Filters..."), 0, this, SLOT(slotPopFilter()), actionCollection(), "popFilter" ); + if(KStandardDirs::mandrake_distro_version()!=KStandardDirs::DOWNLOAD){ + (void) new KAction( i18n("&Anti Spam Wizard..."), 0, this, + SLOT(slotAntiSpamWizard()), actionCollection(), "antiSpamWizard" ); + } (void) new KAction( KGuiItem( i18n("KMail &Introduction"), 0, i18n("Display KMail's Welcome Page") ), 0, this, SLOT(slotIntro()), @@ -3250,3 +3257,10 @@ void KMMainWidget::toggleSystray(bool en mSystemTray->setMode(mode); } } + +//----------------------------------------------------------------------------- +void KMMainWidget::slotAntiSpamWizard() +{ + AntiSpamWizard wiz( this, folderTree(), actionCollection() ); + wiz.exec(); +} --- kdepim-3.1.95/kmail/kmmainwidget.h.kmail_anti_spam 2004-01-20 08:07:04.178665688 -0500 +++ kdepim-3.1.95/kmail/kmmainwidget.h 2004-01-20 08:07:04.230657784 -0500 @@ -347,7 +347,7 @@ protected slots: void slotPrintMsg(); void slotConfigChanged(); - + void slotAntiSpamWizard(); private: // Message actions KAction *mTrashAction, *mDeleteAction, *mSaveAsAction, *mEditAction, --- kdepim-3.1.95/kmail/kmfiltermgr.h.kmail_anti_spam 2004-01-20 03:32:04.000000000 -0500 +++ kdepim-3.1.95/kmail/kmfiltermgr.h 2004-01-20 08:07:04.230657784 -0500 @@ -44,6 +44,11 @@ public: int moveMessage(KMMessage *msg) const; void endFiltering(KMMsgBase *msgBase) const; + /** Append the new filter to the current list of filters and + write everything back into the configuration.*/ + void appendFilter( KMFilter* filter ); + + /** Process given message by applying the filter rules one by one. You can select which set of filters (incoming or outgoing) should be used. --- kdepim-3.1.95/kmail/kmfiltermgr.cpp.kmail_anti_spam 2004-01-20 03:32:04.000000000 -0500 +++ kdepim-3.1.95/kmail/kmfiltermgr.cpp 2004-01-20 08:07:04.229657936 -0500 @@ -281,6 +281,15 @@ void KMFilterMgr::createFilter( const QC mEditDialog->createFilter( field, value ); } +//----------------------------------------------------------------------------- +void KMFilterMgr::appendFilter( KMFilter* filter ) +{ + beginUpdate(); + append( filter ); + writeConfig( TRUE ); + endUpdate(); +} + //----------------------------------------------------------------------------- bool KMFilterMgr::folderRemoved(KMFolder* aFolder, KMFolder* aNewFolder) --- /dev/null 1970-01-01 01:00:00.000000000 +0100 +++ kdepim/kmail/antispamwizard.h 2004-05-26 23:17:48.000000000 +0200 @@ -0,0 +1,339 @@ +/* + This file is part of KMail. + Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de> + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ +#ifndef KMAIL_ANTISPAMWIZARD_H +#define KMAIL_ANTISPAMWIZARD_H + +#include <kconfig.h> +#include <kwizard.h> + +#include <qcheckbox.h> +#include <qdict.h> + +class KActionCollection; +class KMFolderTree; +class QLabel; + +namespace KMail { + + class SimpleFolderTree; + + class ASWizInfoPage; + class ASWizProgramsPage; + class ASWizSpamRulesPage; + class ASWizVirusRulesPage; + + //--------------------------------------------------------------------------- + /** + @short KMail anti-spam wizard. + @author Andreas Gungl <a.gungl@gmx.de> + + The wizard helps to create filter rules to let KMail operate + with external anti-spam tools. The wizard tries to detect the + tools, but the user can overide the preselections. + Then the user can decide what funtionality shall be supported + by the created filter rules. + The wizard will append the created filter rules after the + last existing rule to keep possible conflicts with existing + filter configurations minimal. + + Anti-virus support was added by Fred Emmott <fred87@users.sf.net> + + The configuration for the tools to get checked and set up + is read fro a config file. The structure of the file is as + following: + <pre> + [General] + tools=1 + + [Spamtool #1] + Ident=spamassassin + Version=0 + VisibleName=&Spamassassin + Executable=spamassassin -V + URL=http://spamassassin.org + PipeFilterName=SpamAssassin Check + PipeCmdDetect=spamassassin -L + ExecCmdSpam=sa-learn --spam --no-rebuild --single + ExecCmdHam=sa-learn --ham --no-rebuild --single + DetectionHeader=X-Spam-Flag + DetectionPattern=yes + UseRegExp=0 + SupportsBayes=1 + type=spam + </pre> + The name of the config file is kmail.antispamrc + and it's expected in the config dir of KDE. + + */ + class AntiSpamWizard : public KWizard + { + Q_OBJECT + + public: + /** Constructor that needs to initialize from the main folder tree + of KMail. + @param parent The parent widget for the wizard. + @param mainFolderTree The main folder tree from which the folders + are copied to allow the selection of a spam folder in a tree + within one of the wizard pages. + @param collection In this collection there the wizard will search + for the filter menu actions which get created for classification + rules (to add them later to the main toolbar). + */ + AntiSpamWizard( QWidget * parent, KMFolderTree * mainFolderTree, + KActionCollection * collection ); + + protected: + /** Evaluate the settings made and create the appropriate filter rules. */ + void accept(); + /** Check for the availability of an executible along the PATH */ + int checkForProgram( QString executable ); + /** + Instances of this class store the settings for one tool as read from + the config file. Visible name and What's this text can not get + translated! + */ + class SpamToolConfig + { + public: + SpamToolConfig() {}; + SpamToolConfig( QString toolId, int configVersion, + QString name, QString exec, QString url, QString filter, + QString detection, QString spam, QString ham, + QString header, QString pattern, bool regExp, + bool bayesFilter, QString type ); + + int getVersion() const { return mVersion; }; + QString getId() const { return mId; }; + QString getVisibleName() const { return mVisibleName; }; + QString getExecutable() const { return mExecutable; }; + QString getWhatsThisText() const { return mWhatsThisText; }; + QString getFilterName() const { return mFilterName; }; + QString getDetectCmd() const { return mDetectCmd; }; + QString getSpamCmd() const { return mSpamCmd; }; + QString getHamCmd() const { return mHamCmd; }; + QString getDetectionHeader() const { return mDetectionHeader; }; + QString getDetectionPattern() const { return mDetectionPattern; }; + bool isUseRegExp() const { return mUseRegExp; }; + bool useBayesFilter() const { return mSupportsBayesFilter; }; + QString getType() const { return mType; }; + // convinience methods for types + bool isSpamTool() const { return ( mType == "spam" ); }; + bool isVirusTool() const { return ( mType == "av" ); }; + + private: + // used to identifiy configs for the same tool + QString mId; + // The version of the config data, used for merging and + // detecting newer configs + int mVersion; + // the name as shown by the checkbox in the dialog page + QString mVisibleName; + // the command to check the existance of the tool + QString mExecutable; + // the What's This help text (e.g. url for the tool) + QString mWhatsThisText; + // name for the created filter in the filter list + QString mFilterName; + // pipe through cmd used to detect spam messages + QString mDetectCmd; + // pipe through cmd to let the tool learn a spam message + QString mSpamCmd; + // pipe through cmd to let the tool learn a ham message + QString mHamCmd; + // by which header are messages marked as spam + QString mDetectionHeader; + // what header pattern is used to mark spam messages + QString mDetectionPattern; + // filter searches for the pattern by regExp or contain rule + bool mUseRegExp; + // can the tool learn spam and ham, has it a bayesian algorithm + bool mSupportsBayesFilter; + // Is the tool anti-spam ("spam") or anti-virus ("av") + QString mType; + }; + /** + Instances of this class control reading the configuration of the + anti-spam tools from global and user config files as well as the + merging of different config versions. + */ + class ConfigReader + { + public: + ConfigReader( QValueList<SpamToolConfig> & configList ); + + QValueList<SpamToolConfig> & getToolList() { return mToolList; }; + + void readAndMergeConfig(); + + private: + QValueList<SpamToolConfig> & mToolList; + KConfig mConfig; + + SpamToolConfig readToolConfig( KConfigGroup & configGroup ); + SpamToolConfig createDummyConfig(); + + void mergeToolConfig( SpamToolConfig config ); + }; + + + protected slots: + /** Modify the status of the wizard to reflect the selection of spam tools. */ + void checkProgramsSelections(); + /** Modify the status of the wizard to reflect the selected functionality. */ + void checkSpamRulesSelections(); + /** Modify the status of the wizard to reflect the selected functionality. */ + void checkVirusRulesSelections(); + /** Check if the spam tools are available via the PATH */ + void checkToolAvailability(); + /** Show a help topic */ + void slotHelpClicked(); + + private: + /* generic checks if any option in a page is checked */ + bool anySpamOptionChecked(); + bool anyVirusOptionChecked(); + + /* The pages in the wizard */ + ASWizInfoPage * mInfoPage; + ASWizProgramsPage * mProgramsPage; + ASWizSpamRulesPage * mSpamRulesPage; + ASWizVirusRulesPage * mVirusRulesPage; + + /* The configured tools and it's settings to be used in the wizard. */ + QValueList<SpamToolConfig> mToolList; + + /* The action collection where the filter menu action is searched in */ + KActionCollection * mActionCollection; + + /* Are any spam tools selected? */ + bool mSpamToolsUsed; + /* Are any virus tools selected? */ + bool mVirusToolsUsed; + }; + + + //--------------------------------------------------------------------------- + + //--------------------------------------------------------------------------- + class ASWizInfoPage : public QWidget + { + public: + ASWizInfoPage( QWidget *parent, const char *name ); + + void setScanProgressText( const QString &toolName ); + + private: + QLabel *mIntroText; + QLabel *mScanProgressText; + }; + + //--------------------------------------------------------------------------- + class ASWizProgramsPage : public QWidget + { + Q_OBJECT + + public: + ASWizProgramsPage( QWidget *parent, const char *name, + QStringList &checkBoxTextList, + QStringList &checkBoxWhatsThisList ); + + bool isProgramSelected( const QString &visibleName ); + void setProgramAsFound( const QString &visibleName, bool found ); + + private slots: + void processSelectionChange(); + + signals: + void selectionChanged(); + + private: + QDict<QCheckBox> mProgramDict; + }; + + //--------------------------------------------------------------------------- + class ASWizSpamRulesPage : public QWidget + { + Q_OBJECT + + public: + ASWizSpamRulesPage( QWidget * parent, const char * name, KMFolderTree * mainFolderTree ); + + bool pipeRulesSelected() const; + bool classifyRulesSelected() const; + bool moveRulesSelected() const; + bool markReadRulesSelected() const; + + QString selectedFolderName() const; + void allowClassification( bool enabled ); + + private slots: + void processSelectionChange(); + + signals: + void selectionChanged(); + + private: + QCheckBox * mPipeRules; + QCheckBox * mClassifyRules; + QCheckBox * mMoveRules; + SimpleFolderTree *mFolderTree; + QCheckBox * mMarkRules; + }; + + //------------------------------------------------------------------------- + class ASWizVirusRulesPage : public QWidget + { + Q_OBJECT + + public: + ASWizVirusRulesPage( QWidget * parent, const char * name, KMFolderTree * mainFolderTree ); + + bool pipeRulesSelected() const; + bool moveRulesSelected() const; + bool markReadRulesSelected() const; + + QString selectedFolderName() const; + + private slots: + void processSelectionChange(); + signals: + void selectionChanged(); + + private: + QCheckBox * mPipeRules; + QCheckBox * mMoveRules; + SimpleFolderTree *mFolderTree; + QCheckBox * mMarkRules; + }; + + +} // namespace KMail + +#endif // KMAIL_ANTISPAMWIZARD_H --- /dev/null 1970-01-01 01:00:00.000000000 +0100 +++ kdepim/kmail/antispamwizard.cpp 2004-06-16 14:19:41.000000000 +0200 @@ -0,0 +1,977 @@ +/* + This file is part of KMail. + Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de> + + KMail is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + KMail is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "antispamwizard.h" +#include "kcursorsaver.h" +#include "kmfilter.h" +#include "kmfilteraction.h" +#include "kmfiltermgr.h" +#include "kmkernel.h" +#include "kmfolderseldlg.h" +#include "kmfoldertree.h" +#include "kmmainwin.h" + +#include <kaction.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kdialog.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> + +#include <qdom.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +using namespace KMail; + +AntiSpamWizard::AntiSpamWizard( QWidget* parent, KMFolderTree * mainFolderTree, + KActionCollection * collection ) + : KWizard( parent ) +{ + // read the configuration for the anti-spam tools + ConfigReader reader( mToolList ); + reader.readAndMergeConfig(); + mToolList = reader.getToolList(); + +#ifndef NDEBUG + kdDebug(5006) << endl << "Considered anti-spam/virus tools: " << endl; +#endif + QStringList descriptionList; + QStringList whatsThisList; + QValueListIterator<SpamToolConfig> it = mToolList.begin(); + while ( it != mToolList.end() ) + { + descriptionList.append( (*it).getVisibleName() ); + whatsThisList.append( (*it).getWhatsThisText() ); +#ifndef NDEBUG + kdDebug(5006) << "Predefined tool: " << (*it).getId() << endl; + kdDebug(5006) << "Config version: " << (*it).getVersion() << endl; + kdDebug(5006) << "Displayed name: " << (*it).getVisibleName() << endl; + kdDebug(5006) << "Executable: " << (*it).getExecutable() << endl; + kdDebug(5006) << "WhatsThis URL: " << (*it).getWhatsThisText() << endl; + kdDebug(5006) << "Filter name: " << (*it).getFilterName() << endl; + kdDebug(5006) << "Detection command: " << (*it).getDetectCmd() << endl; + kdDebug(5006) << "Learn spam command: " << (*it).getSpamCmd() << endl; + kdDebug(5006) << "Learn ham command: " << (*it).getHamCmd() << endl; + kdDebug(5006) << "Detection header: " << (*it).getDetectionHeader() << endl; + kdDebug(5006) << "Detection pattern: " << (*it).getDetectionPattern() << endl; + kdDebug(5006) << "Use as RegExp: " << (*it).isUseRegExp() << endl; + kdDebug(5006) << "Supports Bayes Filter: " << (*it).useBayesFilter() << endl; + kdDebug(5006) << "Type: " << (*it).getType() << endl << endl; +#endif + it++; + } + + mActionCollection = collection; + + setCaption( i18n( "Anti-Spam/Virus Wizard" )); + mInfoPage = new ASWizInfoPage( 0, "" ); + addPage( mInfoPage, i18n( "Welcome to the KMail Anti-Spam/Virus Wizard." )); + mProgramsPage = new ASWizProgramsPage( 0, "", descriptionList, whatsThisList ); + addPage( mProgramsPage, i18n( "Please select the tools to be used by KMail." )); + mSpamRulesPage = new ASWizSpamRulesPage( 0, "", mainFolderTree ); + mVirusRulesPage = new ASWizVirusRulesPage( 0, "", mainFolderTree ); + + connect( mProgramsPage, SIGNAL( selectionChanged( void ) ), + this, SLOT( checkProgramsSelections( void ) ) ); + connect( mSpamRulesPage, SIGNAL( selectionChanged( void ) ), + this, SLOT( checkSpamRulesSelections( void ) ) ); + connect( mVirusRulesPage, SIGNAL( selectionChanged( void ) ), + this, SLOT( checkVirusRulesSelections( void ) ) ); + + connect( this, SIGNAL( helpClicked( void) ), + this, SLOT( slotHelpClicked( void ) ) ); + + setNextEnabled( mInfoPage, false ); + setNextEnabled( mProgramsPage, false ); + + QTimer::singleShot( 500, this, SLOT( checkToolAvailability( void ) ) ); +} + + +void AntiSpamWizard::accept() +{ + kdDebug( 5006 ) << "Folder name for spam is " + << mSpamRulesPage->selectedFolderName() << endl; + kdDebug( 5006 ) << "Folder name for viruses is " + << mVirusRulesPage->selectedFolderName() << endl; + + KMFilterActionDict dict; + + // Let's start with virus detection and handling, + // so we can avoid spam checks for viral messages + QValueListIterator<SpamToolConfig> it = mToolList.begin(); + while ( it != mToolList.end() ) + { + if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) && + ( mVirusRulesPage->pipeRulesSelected() && (*it).isVirusTool() ) ) + { + // pipe messages through the anti-virus tools, + // one single filter for each tool + // (could get combined but so it's easier to understand for the user) + KMFilter* pipeFilter = new KMFilter(); + QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions(); + KMFilterAction* pipeFilterAction = dict["filter app"]->create(); + pipeFilterAction->argsFromString( (*it).getDetectCmd() ); + pipeFilterActions->append( pipeFilterAction ); + KMSearchPattern* pipeFilterPattern = pipeFilter->pattern(); + pipeFilterPattern->setName( (*it).getFilterName() ); + pipeFilterPattern->append( KMSearchRule::createInstance( "<size>", + KMSearchRule::FuncIsGreaterOrEqual, "0" ) ); + pipeFilter->setApplyOnOutbound( FALSE); + pipeFilter->setApplyOnInbound(); + pipeFilter->setApplyOnExplicit(); + pipeFilter->setStopProcessingHere( FALSE ); + pipeFilter->setConfigureShortcut( FALSE ); + + KMKernel::self()->filterMgr()->appendFilter( pipeFilter ); + } + it++; + } + + if ( mVirusRulesPage->moveRulesSelected() ) + { + // Sort out viruses depending on header fields set by the tools + KMFilter* virusFilter = new KMFilter(); + QPtrList<KMFilterAction>* virusFilterActions = virusFilter->actions(); + KMFilterAction* virusFilterAction1 = dict["transfer"]->create(); + virusFilterAction1->argsFromString( mVirusRulesPage->selectedFolderName() ); + virusFilterActions->append( virusFilterAction1 ); + if ( mVirusRulesPage->markReadRulesSelected() ) { + KMFilterAction* virusFilterAction2 = dict["set status"]->create(); + virusFilterAction2->argsFromString( "R" ); // Read + virusFilterActions->append( virusFilterAction2 ); + } + KMSearchPattern* virusFilterPattern = virusFilter->pattern(); + virusFilterPattern->setName( i18n( "Virus handling" ) ); + virusFilterPattern->setOp( KMSearchPattern::OpOr ); + it = mToolList.begin(); + while ( it != mToolList.end() ) + { + if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() )) + { + if ( (*it).isVirusTool() ) + { + const QCString header = (*it).getDetectionHeader().ascii(); + const QString & pattern = (*it).getDetectionPattern(); + if ( (*it).isUseRegExp() ) + virusFilterPattern->append( + KMSearchRule::createInstance( header, + KMSearchRule::FuncRegExp, pattern ) ); + else + virusFilterPattern->append( + KMSearchRule::createInstance( header, + KMSearchRule::FuncContains, pattern ) ); + } + } + it++; + } + virusFilter->setApplyOnOutbound( FALSE); + virusFilter->setApplyOnInbound(); + virusFilter->setApplyOnExplicit(); + virusFilter->setStopProcessingHere( TRUE ); + virusFilter->setConfigureShortcut( FALSE ); + + KMKernel::self()->filterMgr()->appendFilter( virusFilter ); + } + + it = mToolList.begin(); + while ( it != mToolList.end() ) + { + if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) && + ( mSpamRulesPage->pipeRulesSelected() && (*it).isSpamTool() ) ) + { + // pipe messages through the anti-spam tools, + // one single filter for each tool + // (could get combined but so it's easier to understand for the user) + KMFilter* pipeFilter = new KMFilter(); + QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions(); + KMFilterAction* pipeFilterAction = dict["filter app"]->create(); + pipeFilterAction->argsFromString( (*it).getDetectCmd() ); + pipeFilterActions->append( pipeFilterAction ); + KMSearchPattern* pipeFilterPattern = pipeFilter->pattern(); + pipeFilterPattern->setName( (*it).getFilterName() ); + pipeFilterPattern->append( KMSearchRule::createInstance( "<size>", + KMSearchRule::FuncIsGreaterOrEqual, "0" ) ); + pipeFilter->setApplyOnOutbound( FALSE); + pipeFilter->setApplyOnInbound(); + pipeFilter->setApplyOnExplicit(); + pipeFilter->setStopProcessingHere( FALSE ); + pipeFilter->setConfigureShortcut( FALSE ); + + KMKernel::self()->filterMgr()->appendFilter( pipeFilter ); + } + it++; + } + + if ( mSpamRulesPage->moveRulesSelected() ) + { + // Sort out spam depending on header fields set by the tools + KMFilter* spamFilter = new KMFilter(); + QPtrList<KMFilterAction>* spamFilterActions = spamFilter->actions(); + KMFilterAction* spamFilterAction1 = dict["transfer"]->create(); + spamFilterAction1->argsFromString( mSpamRulesPage->selectedFolderName() ); + spamFilterActions->append( spamFilterAction1 ); + KMFilterAction* spamFilterAction2 = dict["set status"]->create(); + spamFilterAction2->argsFromString( "P" ); // Spam + spamFilterActions->append( spamFilterAction2 ); + if ( mSpamRulesPage->markReadRulesSelected() ) { + KMFilterAction* spamFilterAction3 = dict["set status"]->create(); + spamFilterAction3->argsFromString( "R" ); // Read + spamFilterActions->append( spamFilterAction3 ); + } + KMSearchPattern* spamFilterPattern = spamFilter->pattern(); + spamFilterPattern->setName( i18n( "Spam handling" ) ); + spamFilterPattern->setOp( KMSearchPattern::OpOr ); + it = mToolList.begin(); + while ( it != mToolList.end() ) + { + if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) ) + { + if ( (*it).isSpamTool() ) + { + const QCString header = (*it).getDetectionHeader().ascii(); + const QString & pattern = (*it).getDetectionPattern(); + if ( (*it).isUseRegExp() ) + spamFilterPattern->append( + KMSearchRule::createInstance( header, + KMSearchRule::FuncRegExp, pattern ) ); + else + spamFilterPattern->append( + KMSearchRule::createInstance( header, + KMSearchRule::FuncContains, pattern ) ); + } + } + it++; + } + spamFilter->setApplyOnOutbound( FALSE); + spamFilter->setApplyOnInbound(); + spamFilter->setApplyOnExplicit(); + spamFilter->setStopProcessingHere( TRUE ); + spamFilter->setConfigureShortcut( FALSE ); + + KMKernel::self()->filterMgr()->appendFilter( spamFilter ); + } + + if ( mSpamRulesPage->classifyRulesSelected() ) + { + // Classify messages manually as Spam + KMFilter* classSpamFilter = new KMFilter(); + classSpamFilter->setIcon( "mark_as_spam" ); + QPtrList<KMFilterAction>* classSpamFilterActions = classSpamFilter->actions(); + KMFilterAction* classSpamFilterActionFirst = dict["set status"]->create(); + classSpamFilterActionFirst->argsFromString( "P" ); + classSpamFilterActions->append( classSpamFilterActionFirst ); + it = mToolList.begin(); + while ( it != mToolList.end() ) + { + if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) + && (*it).useBayesFilter() ) + { + KMFilterAction* classSpamFilterAction = dict["execute"]->create(); + classSpamFilterAction->argsFromString( (*it).getSpamCmd() ); + classSpamFilterActions->append( classSpamFilterAction ); + } + it++; + } + KMFilterAction* classSpamFilterActionLast = dict["transfer"]->create(); + classSpamFilterActionLast->argsFromString( mSpamRulesPage->selectedFolderName() ); + classSpamFilterActions->append( classSpamFilterActionLast ); + + KMSearchPattern* classSpamFilterPattern = classSpamFilter->pattern(); + classSpamFilterPattern->setName( i18n( "Classify as spam" ) ); + classSpamFilterPattern->append( KMSearchRule::createInstance( "<size>", + KMSearchRule::FuncIsGreaterOrEqual, "0" ) ); + classSpamFilter->setApplyOnOutbound( FALSE); + classSpamFilter->setApplyOnInbound( FALSE ); + classSpamFilter->setApplyOnExplicit( FALSE ); + classSpamFilter->setStopProcessingHere( TRUE ); + classSpamFilter->setConfigureShortcut( TRUE ); + KMKernel::self()->filterMgr()->appendFilter( classSpamFilter ); + + // Classify messages manually as not Spam / as Ham + KMFilter* classHamFilter = new KMFilter(); + QPtrList<KMFilterAction>* classHamFilterActions = classHamFilter->actions(); + KMFilterAction* classHamFilterActionFirst = dict["set status"]->create(); + classHamFilterActionFirst->argsFromString( "H" ); + classHamFilterActions->append( classHamFilterActionFirst ); + it = mToolList.begin(); + while ( it != mToolList.end() ) + { + if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) + && (*it).useBayesFilter() ) + { + KMFilterAction* classHamFilterAction = dict["execute"]->create(); + classHamFilterAction->argsFromString( (*it).getHamCmd() ); + classHamFilterActions->append( classHamFilterAction ); + } + it++; + } + KMSearchPattern* classHamFilterPattern = classHamFilter->pattern(); + classHamFilterPattern->setName( i18n( "Classify as NOT spam" ) ); + classHamFilterPattern->append( KMSearchRule::createInstance( "<size>", + KMSearchRule::FuncIsGreaterOrEqual, "0" ) ); + classHamFilter->setApplyOnOutbound( FALSE); + classHamFilter->setApplyOnInbound( FALSE ); + classHamFilter->setApplyOnExplicit( FALSE ); + classHamFilter->setStopProcessingHere( TRUE ); + classHamFilter->setConfigureShortcut( TRUE ); + KMKernel::self()->filterMgr()->appendFilter( classHamFilter ); + + // add the classification filter actions to the toolbar + QString filterNameSpam = + QString( "Filter %1" ).arg( classSpamFilterPattern->name() ); + filterNameSpam = filterNameSpam.replace( " ", "_" ); + QString filterNameHam = + QString( "Filter %1" ).arg( classHamFilterPattern->name() ); + filterNameHam = filterNameHam.replace( " ", "_" ); + + // FIXME post KDE 3.2 + // The following code manipulates the kmmainwin.rc file directly. Usuallay + // one would expect to let the toolbar write back it's change from above + // i.e. the new structure including the two added actions. + // In KDE 3.2 there is no API for that so I only fund the way to read in + // the XML file myself, to change it and write it out then. + // As soon as an API is available, the following part can certainly get + // replaced by one or two statements. + // (a.gungl@gmx.de) + + // make the toolbar changes persistent - let's be very conservative here + QString config = + KXMLGUIFactory::readConfigFile( "kmmainwin.rc", KMKernel::self()->xmlGuiInstance() ); +#ifndef NDEBUG + kdDebug(5006) << "Read kmmainwin.rc contents (last 1000 chars printed):" << endl; + kdDebug(5006) << config.right( 1000 ) << endl; + kdDebug(5006) << "#####################################################" << endl; +#endif + QDomDocument domDoc; + domDoc.setContent( config ); + QDomNodeList domNodeList = domDoc.elementsByTagName( "ToolBar" ); + if ( domNodeList.count() > 0 ) + kdDebug(5006) << "ToolBar section found." << endl; + else + kdDebug(5006) << "No ToolBar section found." << endl; + for ( unsigned int i = 0; i < domNodeList.count(); i++ ) + { + QDomNode domNode = domNodeList.item( i ); + QDomNamedNodeMap nodeMap = domNode.attributes(); + kdDebug(5006) << "name=" << nodeMap.namedItem( "name" ).nodeValue() << endl; + if ( nodeMap.namedItem( "name" ).nodeValue() == "mainToolBar" ) + { + kdDebug(5006) << "mainToolBar section found." << endl; + bool spamActionFound = false; + bool hamActionFound = false; + QDomNodeList domNodeChildList = domNode.childNodes(); + for ( unsigned int j = 0; j < domNodeChildList.count(); j++ ) + { + QDomNode innerDomNode = domNodeChildList.item( j ); + QDomNamedNodeMap innerNodeMap = innerDomNode.attributes(); + if ( innerNodeMap.namedItem( "name" ).nodeValue() == filterNameSpam ) + spamActionFound = true; + if ( innerNodeMap.namedItem( "name" ).nodeValue() == filterNameHam ) + hamActionFound = true; + } + + // append the new actions if not yet existing + if ( !spamActionFound ) + { + QDomElement domElemSpam = domDoc.createElement( "Action" ); + domElemSpam.setAttribute( "name", filterNameSpam ); + domNode.appendChild( domElemSpam ); + kdDebug(5006) << "Spam action added to toolbar." << endl; + } + if ( !hamActionFound ) + { + QDomElement domElemHam = domDoc.createElement( "Action" ); + domElemHam.setAttribute( "name", filterNameHam ); + domNode.appendChild( domElemHam ); + kdDebug(5006) << "Ham action added to toolbar." << endl; + } + if ( !spamActionFound || !hamActionFound ) + { +#ifndef NDEBUG + kdDebug(5006) << "New kmmainwin.rc structur (last 1000 chars printed):" << endl; + kdDebug(5006) << domDoc.toString().right( 1000 ) << endl; + kdDebug(5006) << "####################################################" << endl; +#endif + // write back the modified resource file + KXMLGUIFactory::saveConfigFile( domDoc, "kmmainwin.rc", + KMKernel::self()->xmlGuiInstance() ); + } + } + else + kdDebug(5006) << "No mainToolBar section found." << endl; + } + } + + QDialog::accept(); +} + + +void AntiSpamWizard::checkProgramsSelections() +{ + bool status = false; + bool canClassify = false; + QValueListIterator<SpamToolConfig> it = mToolList.begin(); + mSpamToolsUsed = false; + mVirusToolsUsed = false; + while ( it != mToolList.end() ) + { + if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) ) + { + status = true; + if ( (*it).isSpamTool() ) + mSpamToolsUsed = true; + if ( (*it).isVirusTool() ) + mVirusToolsUsed = true; + } + if ( (*it).useBayesFilter() ) + canClassify = true; + it++; + } + + mSpamRulesPage->allowClassification( canClassify ); + + removePage( mSpamRulesPage ); + removePage( mVirusRulesPage ); + if ( mSpamToolsUsed ) + { + addPage( mSpamRulesPage, i18n( "Please select the spam filters to be created inside KMail." )); + checkSpamRulesSelections(); + } + if ( mVirusToolsUsed ) + { + addPage( mVirusRulesPage, i18n( "Please select the virus filters to be created inside KMail." )); + checkVirusRulesSelections(); + } + + setNextEnabled( mProgramsPage, status ); +} + + +void AntiSpamWizard::checkSpamRulesSelections() +{ + if ( anySpamOptionChecked() ) + { + if ( mVirusToolsUsed ) + setNextEnabled( mSpamRulesPage, true ); + else + setFinishEnabled( mSpamRulesPage, true ); + } + else + { + setNextEnabled( mSpamRulesPage, mVirusToolsUsed ); + setFinishEnabled( mSpamRulesPage, false ); + } + if ( mVirusToolsUsed ) + checkVirusRulesSelections(); +} + +void AntiSpamWizard::checkVirusRulesSelections() +{ + if ( anyVirusOptionChecked() ) + setFinishEnabled( mVirusRulesPage, true ); + else + setFinishEnabled( mVirusRulesPage, + anySpamOptionChecked() && mSpamToolsUsed ); +} + + +void AntiSpamWizard::checkToolAvailability() +{ + KCursorSaver busy(KBusyPtr::busy()); // this can take some time to find the tools + + // checkboxes for the tools + QValueListIterator<SpamToolConfig> it = mToolList.begin(); + while ( it != mToolList.end() ) + { + QString text( i18n("Scanning for %1...").arg( (*it).getId() ) ); + mInfoPage->setScanProgressText( text ); + KApplication::kApplication()->processEvents( 200 ); + int rc = checkForProgram( (*it).getExecutable() ); + mProgramsPage->setProgramAsFound( (*it).getVisibleName(), !rc ); + it++; + } + mInfoPage->setScanProgressText( i18n("Scanning for anti-spam/virus tools finished.") ); + setNextEnabled( mInfoPage, true ); +} + + +int AntiSpamWizard::checkForProgram( QString executable ) +{ + kdDebug(5006) << "Testing for executable:" << executable << endl; + KProcess process; + process << executable; + process.setUseShell( true ); + process.start( KProcess::Block ); + return process.exitStatus(); +} + + +void AntiSpamWizard::slotHelpClicked() +{ + KApplication::kApplication()->invokeHelp( "the-anti-spam-wizard", "kmail" ); +} + + +bool AntiSpamWizard::anySpamOptionChecked() +{ + return ( mSpamRulesPage->moveRulesSelected() + || mSpamRulesPage->pipeRulesSelected() + || mSpamRulesPage->classifyRulesSelected() ); +} + +bool AntiSpamWizard::anyVirusOptionChecked() +{ + return ( mVirusRulesPage->moveRulesSelected() || mVirusRulesPage->pipeRulesSelected() ); +} + + +//--------------------------------------------------------------------------- +AntiSpamWizard::SpamToolConfig::SpamToolConfig(QString toolId, + int configVersion,QString name, QString exec, + QString url, QString filter, QString detection, QString spam, QString ham, + QString header, QString pattern, bool regExp, bool bayesFilter, QString type) + : mId( toolId ), mVersion( configVersion ), + mVisibleName( name ), mExecutable( exec ), mWhatsThisText( url ), + mFilterName( filter ), mDetectCmd( detection ), mSpamCmd( spam ), + mHamCmd( ham ), mDetectionHeader( header ), mDetectionPattern( pattern ), + mUseRegExp( regExp ), mSupportsBayesFilter( bayesFilter ), mType( type ) +{ +} + + +//--------------------------------------------------------------------------- +AntiSpamWizard::ConfigReader::ConfigReader( QValueList<SpamToolConfig> & configList ) + : mToolList( configList ), + mConfig( "kmail.antispamrc", true ) +{} + + +void AntiSpamWizard::ConfigReader::readAndMergeConfig() +{ + // read the configuration from the global config file + mConfig.setReadDefaults( true ); + KConfigGroup general( &mConfig, "General" ); + int registeredTools = general.readNumEntry( "tools", 0 ); + for (int i = 1; i <= registeredTools; i++) + { + KConfigGroup toolConfig( &mConfig, + QCString("Spamtool #") + QCString().setNum(i) ); + mToolList.append( readToolConfig( toolConfig ) ); + } + + // read the configuration from the user config file + // and merge newer config data + mConfig.setReadDefaults( false ); + KConfigGroup user_general( &mConfig, "General" ); + int user_registeredTools = user_general.readNumEntry( "tools", 0 ); + for (int i = 1; i <= user_registeredTools; i++) + { + KConfigGroup toolConfig( &mConfig, + QCString("Spamtool #") + QCString().setNum(i) ); + mergeToolConfig( readToolConfig( toolConfig ) ); + } + // Make sure to have add least one tool listed even when the + // config file was not found or whatever went wrong + if ( registeredTools < 1 && user_registeredTools < 1) + mToolList.append( createDummyConfig() ); +} + + +AntiSpamWizard::SpamToolConfig + AntiSpamWizard::ConfigReader::readToolConfig( KConfigGroup & configGroup ) +{ + QString id = configGroup.readEntry( "Ident" ); + int version = configGroup.readNumEntry( "Version" ); +#ifndef NDEBUG + kdDebug(5006) << "Found predefined tool: " << id << endl; + kdDebug(5006) << "With config version : " << version << endl; +#endif + QString name = configGroup.readEntry( "VisibleName" ); + QString executable = configGroup.readEntry( "Executable" ); + QString url = configGroup.readEntry( "URL" ); + QString filterName = configGroup.readEntry( "PipeFilterName" ); + QString detectCmd = configGroup.readEntry( "PipeCmdDetect" ); + QString spamCmd = configGroup.readEntry( "ExecCmdSpam" ); + QString hamCmd = configGroup.readEntry( "ExecCmdHam" ); + QString header = configGroup.readEntry( "DetectionHeader" ); + QString pattern = configGroup.readEntry( "DetectionPattern" ); + bool useRegExp = configGroup.readBoolEntry( "UseRegExp" ); + bool supportsBayes = configGroup.readBoolEntry( "SupportsBayes" ); + QString type = configGroup.readEntry( "Type" ); + return SpamToolConfig( id, version, name, executable, url, + filterName, detectCmd, spamCmd, hamCmd, + header, pattern, useRegExp, supportsBayes, type ); +} + + +AntiSpamWizard::SpamToolConfig AntiSpamWizard::ConfigReader::createDummyConfig() +{ + return SpamToolConfig( "spamassassin", 0, + "&SpamAssassin", "spamassassin -V", + "http://spamassassin.org", "SpamAssassin Check", + "spamassassin -L", + "sa-learn -L --spam --no-rebuild --single", + "sa-learn -L --ham --no-rebuild --single", + "X-Spam-Flag", "yes", + false, true, "spam" ); +} + + +void AntiSpamWizard::ConfigReader::mergeToolConfig( AntiSpamWizard::SpamToolConfig config ) +{ + bool found = false; + QValueListIterator<SpamToolConfig> it = mToolList.begin(); + while ( it != mToolList.end() && !found) + { +#ifndef NDEBUG + kdDebug(5006) << "Check against tool: " << (*it).getId() << endl; + kdDebug(5006) << "Against version : " << (*it).getVersion() << endl; +#endif + if ( (*it).getId() == config.getId() ) + { + found = true; + if ( (*it).getVersion() < config.getVersion() ) + { +#ifndef NDEBUG + kdDebug(5006) << "Replacing config ..." << endl; +#endif + mToolList.remove( it ); + mToolList.append( config ); + } + } + else it++; + } + if ( !found ) + mToolList.append( config ); +} + + +//--------------------------------------------------------------------------- +ASWizInfoPage::ASWizInfoPage( QWidget * parent, const char * name ) + : QWidget( parent, name ) +{ + QGridLayout *grid = new QGridLayout( this, 1, 1, KDialog::marginHint(), + KDialog::spacingHint() ); + grid->setColStretch( 1, 10 ); + + mIntroText = new QLabel( this ); + mIntroText->setText( i18n( + "<p>Here you get some assistance in setting up KMail's filter " + "rules to use some commonly-known anti-spam/virus tools.</p>" + "<p>The wizard can detect those tools on your computer as " + "well as create filter rules to classify messages using these " + "tools and to separate messages classified as spam, or which " + "contain viruses. The wizard will not take any existing filter " + "rules into consideration but will append new rules in any" + "case.</p>" + "<p><b>WARNING:</b> As KMail is blocked during the scan of the " + "messages for spam or viruses, you may encounter problems with " + "the responsivness of KMail because anti-spam/virus tool " + "operations are usually time consuming. Please consider " + "deleting the filter rules created by the wizard to get " + "back to the former behavior." + ) ); + grid->addWidget( mIntroText, 0, 0 ); + + mScanProgressText = new QLabel( this ); + mScanProgressText->setText( "" ) ; + grid->addWidget( mScanProgressText, 1, 0 ); +} + +void ASWizInfoPage::setScanProgressText( const QString &toolName ) +{ + mScanProgressText->setText( toolName ); +} + +//--------------------------------------------------------------------------- +ASWizProgramsPage::ASWizProgramsPage( QWidget * parent, const char * name, + QStringList &checkBoxTextList, + QStringList &checkBoxWhatsThisList ) + : QWidget( parent, name ) +{ + QGridLayout *grid = new QGridLayout( this, 3, 1, KDialog::marginHint(), + KDialog::spacingHint() ); + // checkboxes for the tools + int row = 0; + QStringList::Iterator it1 = checkBoxTextList.begin(); + QStringList::Iterator it2 = checkBoxWhatsThisList.begin(); + while ( it1 != checkBoxTextList.end() ) + { + QCheckBox *box = new QCheckBox( *it1, this ); + if ( it2 != checkBoxWhatsThisList.end() ) + { + QWhatsThis::add( box, *it2 ); + QToolTip::add( box, *it2 ); + ++it2; + } + grid->addWidget( box, row++, 0 ); + connect( box, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + mProgramDict.insert( *it1, box ); + ++it1; + } + + // hint text + QLabel *introText = new QLabel( this ); + introText->setText( i18n( + "<p>For these tools it is possible to let the " + "wizard create filter rules. KMail tried to find the tools " + "in the PATH of your system; the wizard does not allow you " + "to create rules for tools which were not found: " + "this is to keep your configuration consistent and " + "to minimize the risk of unpredicted behavior.</p>" + ) ); + grid->addWidget( introText, row++, 0 ); +} + + +bool ASWizProgramsPage::isProgramSelected( const QString &visibleName ) +{ + if ( mProgramDict[visibleName] ) + return mProgramDict[visibleName]->isChecked(); + else + return false; +} + + +void ASWizProgramsPage::setProgramAsFound( const QString &visibleName, bool found ) +{ + QCheckBox * box = mProgramDict[visibleName]; + if ( box ) + { + QString foundText( i18n("(found on this system)") ); + QString notFoundText( i18n("(not found on this system)") ); + QString labelText = visibleName; + labelText += " "; + if ( found ) + labelText += foundText; + else + { + labelText += notFoundText; + box->setEnabled( false ); + } + box->setText( labelText ); + } +} + + +void ASWizProgramsPage::processSelectionChange() +{ + emit selectionChanged(); +} + +//--------------------------------------------------------------------------- +ASWizSpamRulesPage::ASWizSpamRulesPage( QWidget * parent, const char * name, + KMFolderTree * mainFolderTree ) + : QWidget( parent, name ) +{ + QGridLayout *grid = new QGridLayout( this, 5, 1, KDialog::marginHint(), + KDialog::spacingHint() ); + + mClassifyRules = new QCheckBox( i18n("Classify messages manually as spam"), this ); + QWhatsThis::add( mClassifyRules, + i18n( "Sometimes messages are classified wrongly or even not at all; " + "the latter might be by intention, because you perhaps filter " + "out messages from mailing lists before you let the anti-spam " + "tools classify the rest of the messages. You can correct these " + "wrong or missing classifications manually by using the " + "appropriate toolbar buttons which trigger special filters " + "created by this wizard." ) ); + grid->addWidget( mClassifyRules, 0, 0 ); + + mPipeRules = new QCheckBox( i18n("Classify messages using the anti-spam tools"), this ); + QWhatsThis::add( mPipeRules, + i18n( "Let the anti-spam tools classify your messages. The wizard " + "will create appropriate filters. The messages are usually " + "marked by the tools so that following filters can react " + "on this and, for example, move spam messages to a special folder.") ); + grid->addWidget( mPipeRules, 1, 0 ); + + mMoveRules = new QCheckBox( i18n("Move detected spam messages to the selected folder"), this ); + QWhatsThis::add( mMoveRules, + i18n( "A filter to detect messages classified as spam and to move " + "those messages into a predefined folder is created. The " + "default folder is the trash folder, but you may change that " + "in the folder view.") ); + grid->addWidget( mMoveRules, 2, 0 ); + + mMarkRules = new QCheckBox( i18n("Additionally, mark detected spam messages as read"), this ); + mMarkRules->setEnabled( false ); + QWhatsThis::add( mMarkRules, + i18n( "Mark messages which have been classified as " + "spam as read, as well as moving them to the selected " + "folder.") ); + grid->addWidget( mMarkRules, 3, 0 ); + + QString s = "trash"; + mFolderTree = new SimpleFolderTree( this, mainFolderTree, s, true ); + grid->addWidget( mFolderTree, 4, 0 ); + + connect( mPipeRules, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + connect( mClassifyRules, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + connect( mMoveRules, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + connect( mMarkRules, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + connect( mMoveRules, SIGNAL( toggled( bool ) ), + mMarkRules, SLOT( setEnabled( bool ) ) ); +} + +bool ASWizSpamRulesPage::pipeRulesSelected() const +{ + return mPipeRules->isChecked(); +} + + +bool ASWizSpamRulesPage::classifyRulesSelected() const +{ + return mClassifyRules->isChecked(); +} + + +bool ASWizSpamRulesPage::moveRulesSelected() const +{ + return mMoveRules->isChecked(); +} + +bool ASWizSpamRulesPage::markReadRulesSelected() const +{ + return mMarkRules->isChecked(); +} + + +QString ASWizSpamRulesPage::selectedFolderName() const +{ + QString name = "trash"; + if ( mFolderTree->folder() ) + name = mFolderTree->folder()->idString(); + return name; +} + +void ASWizSpamRulesPage::processSelectionChange() +{ + emit selectionChanged(); +} + + +void ASWizSpamRulesPage::allowClassification( bool enabled ) +{ + if ( enabled ) + mClassifyRules->setEnabled( true ); + else + { + mClassifyRules->setChecked( false ); + mClassifyRules->setEnabled( false ); + } +} + +//--------------------------------------------------------------------------- +ASWizVirusRulesPage::ASWizVirusRulesPage( QWidget * parent, const char * name, + KMFolderTree * mainFolderTree ) + : QWidget( parent, name ) +{ + QGridLayout *grid = new QGridLayout( this, 5, 1, KDialog::marginHint(), + KDialog::spacingHint() ); + + mPipeRules = new QCheckBox( i18n("Classify messages using the anti-virus tools"), this ); + QWhatsThis::add( mPipeRules, + i18n( "Let the anti-virus tools classify your messages. The wizard " + "will create appropriate filters. The messages are usually " + "marked by the tools so that following filters can react " + "on this and, for example, move virus messages to a special folder.") ); + grid->addWidget( mPipeRules, 0, 0 ); + + mMoveRules = new QCheckBox( i18n("Move detected viral messages to the selected folder"), this ); + QWhatsThis::add( mMoveRules, + i18n( "A filter to detect messages classified as virus-infected and to move " + "those messages into a predefined folder is created. The " + "default folder is the trash folder, but you may change that " + "in the folder view.") ); + grid->addWidget( mMoveRules, 1, 0 ); + + mMarkRules = new QCheckBox( i18n("Additionally, mark detected viral messages as read"), this ); + mMarkRules->setEnabled( false ); + QWhatsThis::add( mMarkRules, + i18n( "Mark messages which have been classified as " + "virus-infected as read, as well as moving them " + "to the selected folder.") ); + grid->addWidget( mMarkRules, 2, 0 ); + + QString s = "trash"; + mFolderTree = new SimpleFolderTree( this, mainFolderTree, s, true ); + grid->addWidget( mFolderTree, 3, 0 ); + + connect( mPipeRules, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + connect( mMoveRules, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + connect( mMarkRules, SIGNAL(clicked()), + this, SLOT(processSelectionChange(void)) ); + connect( mMoveRules, SIGNAL( toggled( bool ) ), + mMarkRules, SLOT( setEnabled( bool ) ) ); +} + +bool ASWizVirusRulesPage::pipeRulesSelected() const +{ + return mPipeRules->isChecked(); +} + + +bool ASWizVirusRulesPage::moveRulesSelected() const +{ + return mMoveRules->isChecked(); +} + +bool ASWizVirusRulesPage::markReadRulesSelected() const +{ + return mMarkRules->isChecked(); +} + + +QString ASWizVirusRulesPage::selectedFolderName() const +{ + QString name = "trash"; + if ( mFolderTree->folder() ) + name = mFolderTree->folder()->idString(); + return name; +} + +void ASWizVirusRulesPage::processSelectionChange() +{ + emit selectionChanged(); +} + +#include "antispamwizard.moc" --- /dev/null 1970-01-01 01:00:00.000000000 +0100 +++ kdepim/kmail/kmail.antispamrc 2004-06-08 13:57:46.000000000 +0200 @@ -0,0 +1,114 @@ +[General] +tools=7 + +[Spamtool #1] +Ident=spamassassin +Version=1 +VisibleName=&Spamassassin +Executable=spamassassin -V +URL=http://spamassassin.org +PipeFilterName=SpamAssassin Check +PipeCmdDetect=spamassassin -L +ExecCmdSpam=sa-learn -L --spam --no-rebuild --single +ExecCmdHam=sa-learn -L --ham --no-rebuild --single +DetectionHeader=X-Spam-Flag +DetectionPattern=yes +UseRegExp=0 +SupportsBayes=1 +Type=spam + +[Spamtool #2] +Ident=bogofilter +Version=1 +VisibleName=&Bogofilter +Executable=bogofilter -V +URL=http://bogofilter.sourceforge.net +PipeFilterName=Bogofilter Check +PipeCmdDetect=bogofilter -p -e -u +ExecCmdSpam=bogofilter -N -s +ExecCmdHam=bogofilter -S -n +DetectionHeader=X-Bogosity +DetectionPattern=yes +UseRegExp=0 +SupportsBayes=1 +Type=spam + +[Spamtool #3] +Ident=annoyance-filter +Version=1 +VisibleName=&Annoyance-Filter +Executable=$HOME/.annoyance-filter/annoyance-filter --version +URL=http://www.fourmilab.ch/annoyance-filter +PipeFilterName=Annoyance-Filter Check +PipeCmdDetect=$HOME/.annoyance-filter/annoyance-filter --fread $HOME/.annoyance-filter/FastDict.bin --phrasemin 1 --phrasemax 2 --transcript - --test - +ExecCmdSpam=$HOME/.annoyance-filter/annoyance-filter --read $HOME/.annoyance-filter/Dict.bin --phrasemin 1 --phrasemax 2 --junk - --prune --write $HOME/.annoyance-filter/Dict.bin --fwrite $HOME/.annoyance-filter/FastDict.bin +ExecCmdHam=$HOME/.annoyance-filter/annoyance-filter --read $HOME/.annoyance-filter/Dict.bin --phrasemin 1 --phrasemax 2 --mail - --prune --write $HOME/.annoyance-filter/Dict.bin --fwrite $HOME/.annoyance-filter/FastDict.bin +DetectionHeader=X-Annoyance-Filter-Classification +DetectionPattern=Junk +UseRegExp=0 +SupportsBayes=1 +Type=spam + +[Spamtool #4] +Ident=ClamAV +Version=1 +VisibleName=&Clam Anti-Virus +Executable=clamscan -V +URL=http://clamav.sf.net +PipeFilterName=Clam Anti-Virus Check +PipeCmdDetect=kmail_clamav.sh +ExecCmdSpam= +ExecCmdHam= +DetectionHeader=X-Virus-Flag +DetectionPattern=yes +UseRegExp=0 +SupportsBayes=0 +Type=av + +[Spamtool #5] +Ident=SophosAV +Version=1 +VisibleName=Sophos Anti&Virus +Executable=sweep -v +URL=http://www.sophos.com +PipeFilterName=Sophos Anti-Virus Check +PipeCmdDetect=kmail_sav.sh +ExecCmdSpam= +ExecCmdHam= +DetectionHeader=X-Virus-Flag +DetectionPattern=yes +UseRegExp=0 +SupportsBayes=0 +Type=av + +[Spamtool #6] +Ident=FProt +Version=1 +VisibleName=&F-Prot AntiVirus +Executable=f-prot -verno +URL=http://www.f-prot.com +PipeFilterName=F-Prot Anti-Virus Check +PipeCmdDetect=kmail_fprot.sh +ExecCmdSpam= +ExecCmdHam= +DetectionHeader=X-Virus-Flag +DetectionPattern=yes +UseRegExp=0 +SupportsBayes=0 +Type=av + +[Spamtool #7] +Ident=AntiVir +Version=1 +VisibleName=H+BEDV AntiVir +Executable= antivir --version +URL=http://www.antivir.de +PipeFilterName=AntiVir Anti-Virus Check +PipeCmdDetect=kmail_antivir.sh +ExecCmdSpam= +ExecCmdHam= +DetectionHeader=X-Virus-Flag +DetectionPattern=yes +UseRegExp=0 +SupportsBayes=0 +Type=av --- kdepim-3.2.3/kmail/kmfolderseldlg.cpp 2004-06-17 10:40:43.329748572 +0200 +++ kdepim-3.2.3/kmail/kmfolderseldlg.cpp-- 2004-06-17 10:37:51.917954856 +0200 @@ -54,7 +54,7 @@ FolderItem::FolderItem( QListViewItem * //----------------------------------------------------------------------------- SimpleFolderTree::SimpleFolderTree( QWidget * parent, + KMFolderTree * folderTree, QString & preSelection , bool mustBeReadWrite) - KMFolderTree * folderTree, QString & preSelection ) : KListView( parent ) { assert( folderTree ); @@ -119,7 +119,7 @@ SimpleFolderTree::SimpleFolderTree( QWid item->setText( columnIdx, fti->text( 0 ) ); // Make items without folders and top level items unselectable // (i.e. root item Local Folders and IMAP accounts) + if ( !fti->folder() || depth == 0 || ( mustBeReadWrite && fti->folder()->isReadOnly() )) - if ( !fti->folder() || depth == 0 ) item->setSelectable( false ); else { item->setFolder( fti->folder() ); @@ -154,14 +154,14 @@ const KMFolder * SimpleFolderTree::folde QString KMFolderSelDlg::oldSelection; //----------------------------------------------------------------------------- +KMFolderSelDlg::KMFolderSelDlg( KMMainWidget * parent, const QString& caption, bool mustBeReadWrite ) -KMFolderSelDlg::KMFolderSelDlg( KMMainWidget * parent, const QString& caption ) : KDialogBase( parent, "folder dialog", true, caption, Ok|Cancel, Ok, true ) // mainwin as parent, modal { KMFolderTree * ft = parent->folderTree(); assert( ft ); + mTreeView = new KMail::SimpleFolderTree( makeVBoxMainWidget(), ft, oldSelection,mustBeReadWrite ); - mTreeView = new KMail::SimpleFolderTree( makeVBoxMainWidget(), ft, oldSelection ); mTreeView->setFocus(); connect( mTreeView, SIGNAL( doubleClicked( QListViewItem*, const QPoint&, int ) ), this, SLOT( slotSelect() ) ); --- kdepim-3.2.3/kmail/kmfolderseldlg.h 2004-06-17 10:41:21.465770507 +0200 +++ kdepim-3.2.3/kmail/kmfolderseldlg.h-- 2004-06-17 10:37:56.718196334 +0200 @@ -19,7 +19,7 @@ namespace KMail { class SimpleFolderTree : public KListView { public: + SimpleFolderTree( QWidget * parent, KMFolderTree * folderTree, QString & preSelection, bool mustBeReadWrite ); - SimpleFolderTree( QWidget * parent, KMFolderTree * folderTree, QString & preSelection ); const KMFolder * folder() const; }; @@ -34,7 +34,7 @@ class KMFolderSelDlg: public KDialogBase public: /** Constructor. @p parent @em must be a @ref KMMainWin, because we need it's foldertree. */ + KMFolderSelDlg( KMMainWidget * parent, const QString& caption, bool mustBeReadWrite ); - KMFolderSelDlg( KMMainWidget * parent, const QString& caption ); virtual ~KMFolderSelDlg(); /** Returns selected folder */ --- kdepim-3.2.3/kmail/kmmainwidget.cpp-- 2004-06-17 10:42:09.953333793 +0200 +++ kdepim-3.2.3/kmail/kmmainwidget.cpp 2004-06-17 10:43:11.875595424 +0200 @@ -1329,7 +1329,7 @@ void KMMainWidget::slotToggleTotalColumn //----------------------------------------------------------------------------- void KMMainWidget::slotMoveMsg() { - KMFolderSelDlg dlg(this,i18n("Move Message to Folder")); + KMFolderSelDlg dlg(this,i18n("Move Message to Folder"),true); KMFolder* dest; if (!dlg.exec()) return; @@ -1380,7 +1380,7 @@ void KMMainWidget::slotEditVacation() //----------------------------------------------------------------------------- void KMMainWidget::slotCopyMsg() { - KMFolderSelDlg dlg(this,i18n("Copy Message to Folder")); + KMFolderSelDlg dlg(this,i18n("Copy Message to Folder"),true); KMFolder* dest; if (!dlg.exec()) return; --- kdepim/kmail/kmail_part.cpp-- 2004-06-17 11:47:33.861908672 +0200 +++ kdepim/kmail/kmail_part.cpp 2004-06-17 11:56:53.340629869 +0200 @@ -43,6 +43,7 @@ #include <kapplication.h> #include <kparts/genericfactory.h> +#include <kparts/mainwindow.h> #include <knotifyclient.h> #include <dcopclient.h> #include <kiconloader.h> @@ -144,6 +145,8 @@ KMailPart::KMailPart(QWidget *parentWidg this, SLOT(slotIconChanged(KMFolderTreeItem*)) ); connect( mainWidget->folderTree(), SIGNAL(nameChanged(KMFolderTreeItem*)), this, SLOT(slotNameChanged(KMFolderTreeItem*)) ); + connect( mainWidget, SIGNAL(modifiedToolBarConfig()), + this, SLOT(slotToolbarChanged()) ); connect( this, SIGNAL(textChanged(const QString&)), ie, SIGNAL(textChanged(const QString&)) ); connect( this, SIGNAL(iconChanged(const QPixmap&)), ie, SIGNAL(iconChanged(const QPixmap&)) ); @@ -204,6 +207,36 @@ void KMailPart::slotNameChanged( KMFolde emit textChanged( fti->folder()->label() ); } +// The sole purpose of the following class is to publicize the protected +// method KParts::MainWindow::createGUI() since we need to call it so that +// the toolbar is redrawn when necessary. +// It can be removed once createGUI() has been made public _and_ we don't +// longer rely on kdelibs 3.2. +class KPartsMainWindowWithPublicizedCreateGUI : public KParts::MainWindow +{ +public: + void createGUIPublic( KParts::Part *part ) { + createGUI( part ); + } +}; + +void KMailPart::slotToolbarChanged() +{ + kdDebug(5006) << "KMailPart - need to reload the toolbar" << endl; + reloadXML(); + KParts::MainWindow *win = + dynamic_cast<KParts::MainWindow*>( mainWidget->topLevelWidget() ); + if ( win ) { + ( static_cast<KPartsMainWindowWithPublicizedCreateGUI*>( win ) ) + ->createGUIPublic( this ); + } + else { + kdDebug(5006) << "KMailPart::slotToolbarChanged() - " + << "dynamic_cast<KPart::MainWindow*>( toplevelWidget() ) " + << "failed" << endl; + } +} + void KMailPart::guiActivateEvent(KParts::GUIActivateEvent *e) { --- kdepim/kmail/kmail_part.h-- 2004-06-17 11:47:37.646667879 +0200 +++ kdepim/kmail/kmail_part.h 2004-06-17 11:53:53.105141207 +0200 @@ -67,7 +67,7 @@ class KMailPart: public KParts::ReadOnly void exportFolder( KMFolder* folder ); void slotIconChanged( KMFolderTreeItem *fti ); void slotNameChanged( KMFolderTreeItem *fti ); - + void slotToolbarChanged(); signals: void textChanged( const QString& ); void iconChanged( const QPixmap& ); --- kdepim/kmail/kmmainwidget.cpp-- 2004-06-17 11:48:35.272837799 +0200 +++ kdepim/kmail/kmmainwidget.cpp 2004-06-17 11:51:55.001465499 +0200 @@ -3271,6 +3271,7 @@ void KMMainWidget::slotAntiSpamWizard() { AntiSpamWizard wiz( this, folderTree(), actionCollection() ); wiz.exec(); + emit modifiedToolBarConfig(); } //----------------------------------------------------------------------------- --- kdepim/kmail/kmmainwidget.h-- 2004-06-17 11:49:15.853175195 +0200 +++ kdepim/kmail/kmmainwidget.h 2004-06-17 11:52:16.533944974 +0200 @@ -176,6 +176,7 @@ public slots: signals: void messagesTransfered(bool); void captionChangeRequest( const QString & caption ); + void modifiedToolBarConfig( void ); protected: void setupActions();