kmail Library API Documentation

antispamwizard.cpp

00001 /* 00002 This file is part of KMail. 00003 Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de> 00004 00005 KMail is free software; you can redistribute it and/or modify it 00006 under the terms of the GNU General Public License, version 2, as 00007 published by the Free Software Foundation. 00008 00009 KMail is distributed in the hope that it will be useful, but 00010 WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 In addition, as a special exception, the copyright holders give 00019 permission to link the code of this program with any edition of 00020 the Qt library by Trolltech AS, Norway (or with modified versions 00021 of Qt that use the same license as Qt), and distribute linked 00022 combinations including the two. You must obey the GNU General 00023 Public License in all respects for all of the code used other than 00024 Qt. If you modify this file, you may extend this exception to 00025 your version of the file, but you are not obligated to do so. If 00026 you do not wish to do so, delete this exception statement from 00027 your version. 00028 */ 00029 00030 #include "antispamwizard.h" 00031 #include "kcursorsaver.h" 00032 #include "kmfilter.h" 00033 #include "kmfilteraction.h" 00034 #include "kmfiltermgr.h" 00035 #include "kmkernel.h" 00036 #include "kmfolderseldlg.h" 00037 #include "kmfoldertree.h" 00038 #include "kmmainwin.h" 00039 00040 #include <kaction.h> 00041 #include <kapplication.h> 00042 #include <kdebug.h> 00043 #include <kdialog.h> 00044 #include <klocale.h> 00045 #include <kmessagebox.h> 00046 #include <kprocess.h> 00047 00048 #include <qdom.h> 00049 #include <qlabel.h> 00050 #include <qlayout.h> 00051 #include <qtooltip.h> 00052 #include <qwhatsthis.h> 00053 00054 using namespace KMail; 00055 00056 AntiSpamWizard::AntiSpamWizard( WizardMode mode, 00057 QWidget* parent, KMFolderTree * mainFolderTree, 00058 KActionCollection * collection ) 00059 : KWizard( parent ), 00060 mSpamRulesPage( 0 ), 00061 mVirusRulesPage( 0 ), 00062 mMode( mode ) 00063 { 00064 // read the configuration for the anti-spam tools 00065 ConfigReader reader( mMode, mToolList ); 00066 reader.readAndMergeConfig(); 00067 mToolList = reader.getToolList(); 00068 00069 #ifndef NDEBUG 00070 if ( mMode == AntiSpam ) 00071 kdDebug(5006) << endl << "Considered anti-spam tools: " << endl; 00072 else 00073 kdDebug(5006) << endl << "Considered anti-virus tools: " << endl; 00074 #endif 00075 QStringList descriptionList; 00076 QStringList whatsThisList; 00077 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00078 it != mToolList.end(); ++it ) { 00079 descriptionList.append( (*it).getVisibleName() ); 00080 whatsThisList.append( (*it).getWhatsThisText() ); 00081 #ifndef NDEBUG 00082 kdDebug(5006) << "Predefined tool: " << (*it).getId() << endl; 00083 kdDebug(5006) << "Config version: " << (*it).getVersion() << endl; 00084 kdDebug(5006) << "Displayed name: " << (*it).getVisibleName() << endl; 00085 kdDebug(5006) << "Executable: " << (*it).getExecutable() << endl; 00086 kdDebug(5006) << "WhatsThis URL: " << (*it).getWhatsThisText() << endl; 00087 kdDebug(5006) << "Filter name: " << (*it).getFilterName() << endl; 00088 kdDebug(5006) << "Detection command: " << (*it).getDetectCmd() << endl; 00089 kdDebug(5006) << "Learn spam command: " << (*it).getSpamCmd() << endl; 00090 kdDebug(5006) << "Learn ham command: " << (*it).getHamCmd() << endl; 00091 kdDebug(5006) << "Detection header: " << (*it).getDetectionHeader() << endl; 00092 kdDebug(5006) << "Detection pattern: " << (*it).getDetectionPattern() << endl; 00093 kdDebug(5006) << "Use as RegExp: " << (*it).isUseRegExp() << endl; 00094 kdDebug(5006) << "Supports Bayes Filter: " << (*it).useBayesFilter() << endl; 00095 kdDebug(5006) << "Type: " << (*it).getType() << endl << endl; 00096 #endif 00097 } 00098 00099 mActionCollection = collection; 00100 00101 setCaption( ( mMode == AntiSpam ) ? i18n( "Anti-Spam Wizard" ) 00102 : i18n( "Anti-Virus Wizard" ) ); 00103 mInfoPage = new ASWizInfoPage( mMode, 0, "" ); 00104 addPage( mInfoPage, 00105 ( mMode == AntiSpam ) 00106 ? i18n( "Welcome to the KMail Anti-Spam Wizard" ) 00107 : i18n( "Welcome to the KMail Anti-Virus Wizard" ) ); 00108 mProgramsPage = new ASWizProgramsPage( 0, "", descriptionList, whatsThisList ); 00109 addPage( mProgramsPage, i18n( "Please select the tools to be used by KMail" )); 00110 connect( mProgramsPage, SIGNAL( selectionChanged( void ) ), 00111 this, SLOT( checkProgramsSelections( void ) ) ); 00112 00113 if ( mMode == AntiSpam ) { 00114 mSpamRulesPage = new ASWizSpamRulesPage( 0, "", mainFolderTree ); 00115 connect( mSpamRulesPage, SIGNAL( selectionChanged( void ) ), 00116 this, SLOT( checkSpamRulesSelections( void ) ) ); 00117 } 00118 else { 00119 mVirusRulesPage = new ASWizVirusRulesPage( 0, "", mainFolderTree ); 00120 connect( mVirusRulesPage, SIGNAL( selectionChanged( void ) ), 00121 this, SLOT( checkVirusRulesSelections( void ) ) ); 00122 } 00123 00124 connect( this, SIGNAL( helpClicked( void) ), 00125 this, SLOT( slotHelpClicked( void ) ) ); 00126 00127 setNextEnabled( mInfoPage, false ); 00128 setNextEnabled( mProgramsPage, false ); 00129 00130 QTimer::singleShot( 0, this, SLOT( checkToolAvailability( void ) ) ); 00131 } 00132 00133 00134 void AntiSpamWizard::accept() 00135 { 00136 if ( mSpamRulesPage ) 00137 kdDebug( 5006 ) << "Folder name for spam is " 00138 << mSpamRulesPage->selectedFolderName() << endl; 00139 if ( mVirusRulesPage ) 00140 kdDebug( 5006 ) << "Folder name for viruses is " 00141 << mVirusRulesPage->selectedFolderName() << endl; 00142 00143 KMFilterActionDict dict; 00144 00145 // Let's start with virus detection and handling, 00146 // so we can avoid spam checks for viral messages 00147 if ( mMode == AntiVirus ) { 00148 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00149 it != mToolList.end(); ++it ) { 00150 if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) && 00151 ( mVirusRulesPage->pipeRulesSelected() && (*it).isVirusTool() ) ) 00152 { 00153 // pipe messages through the anti-virus tools, 00154 // one single filter for each tool 00155 // (could get combined but so it's easier to understand for the user) 00156 KMFilter* pipeFilter = new KMFilter(); 00157 QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions(); 00158 KMFilterAction* pipeFilterAction = dict["filter app"]->create(); 00159 pipeFilterAction->argsFromString( (*it).getDetectCmd() ); 00160 pipeFilterActions->append( pipeFilterAction ); 00161 KMSearchPattern* pipeFilterPattern = pipeFilter->pattern(); 00162 pipeFilterPattern->setName( (*it).getFilterName() ); 00163 pipeFilterPattern->append( KMSearchRule::createInstance( "<size>", 00164 KMSearchRule::FuncIsGreaterOrEqual, "0" ) ); 00165 pipeFilter->setApplyOnOutbound( FALSE); 00166 pipeFilter->setApplyOnInbound(); 00167 pipeFilter->setApplyOnExplicit(); 00168 pipeFilter->setStopProcessingHere( FALSE ); 00169 pipeFilter->setConfigureShortcut( FALSE ); 00170 00171 KMKernel::self()->filterMgr()->appendFilter( pipeFilter ); 00172 } 00173 } 00174 00175 if ( mVirusRulesPage->moveRulesSelected() ) 00176 { 00177 // Sort out viruses depending on header fields set by the tools 00178 KMFilter* virusFilter = new KMFilter(); 00179 QPtrList<KMFilterAction>* virusFilterActions = virusFilter->actions(); 00180 KMFilterAction* virusFilterAction1 = dict["transfer"]->create(); 00181 virusFilterAction1->argsFromString( mVirusRulesPage->selectedFolderName() ); 00182 virusFilterActions->append( virusFilterAction1 ); 00183 if ( mVirusRulesPage->markReadRulesSelected() ) { 00184 KMFilterAction* virusFilterAction2 = dict["set status"]->create(); 00185 virusFilterAction2->argsFromString( "R" ); // Read 00186 virusFilterActions->append( virusFilterAction2 ); 00187 } 00188 KMSearchPattern* virusFilterPattern = virusFilter->pattern(); 00189 virusFilterPattern->setName( i18n( "Virus handling" ) ); 00190 virusFilterPattern->setOp( KMSearchPattern::OpOr ); 00191 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00192 it != mToolList.end(); ++it ) { 00193 if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() )) 00194 { 00195 if ( (*it).isVirusTool() ) 00196 { 00197 const QCString header = (*it).getDetectionHeader().ascii(); 00198 const QString & pattern = (*it).getDetectionPattern(); 00199 if ( (*it).isUseRegExp() ) 00200 virusFilterPattern->append( 00201 KMSearchRule::createInstance( header, 00202 KMSearchRule::FuncRegExp, pattern ) ); 00203 else 00204 virusFilterPattern->append( 00205 KMSearchRule::createInstance( header, 00206 KMSearchRule::FuncContains, pattern ) ); 00207 } 00208 } 00209 } 00210 virusFilter->setApplyOnOutbound( FALSE); 00211 virusFilter->setApplyOnInbound(); 00212 virusFilter->setApplyOnExplicit(); 00213 virusFilter->setStopProcessingHere( TRUE ); 00214 virusFilter->setConfigureShortcut( FALSE ); 00215 00216 KMKernel::self()->filterMgr()->appendFilter( virusFilter ); 00217 } 00218 } 00219 else { // AntiSpam mode 00220 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00221 it != mToolList.end(); ++it ) { 00222 if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) && 00223 ( mSpamRulesPage->pipeRulesSelected() && (*it).isSpamTool() ) ) 00224 { 00225 // pipe messages through the anti-spam tools, 00226 // one single filter for each tool 00227 // (could get combined but so it's easier to understand for the user) 00228 KMFilter* pipeFilter = new KMFilter(); 00229 QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions(); 00230 KMFilterAction* pipeFilterAction = dict["filter app"]->create(); 00231 pipeFilterAction->argsFromString( (*it).getDetectCmd() ); 00232 pipeFilterActions->append( pipeFilterAction ); 00233 KMSearchPattern* pipeFilterPattern = pipeFilter->pattern(); 00234 pipeFilterPattern->setName( (*it).getFilterName() ); 00235 pipeFilterPattern->append( KMSearchRule::createInstance( "<size>", 00236 KMSearchRule::FuncIsLessOrEqual, "256000" ) ); 00237 pipeFilter->setApplyOnOutbound( FALSE); 00238 pipeFilter->setApplyOnInbound(); 00239 pipeFilter->setApplyOnExplicit(); 00240 pipeFilter->setStopProcessingHere( FALSE ); 00241 pipeFilter->setConfigureShortcut( FALSE ); 00242 00243 KMKernel::self()->filterMgr()->appendFilter( pipeFilter ); 00244 } 00245 } 00246 00247 if ( mSpamRulesPage->moveRulesSelected() ) 00248 { 00249 // Sort out spam depending on header fields set by the tools 00250 KMFilter* spamFilter = new KMFilter(); 00251 QPtrList<KMFilterAction>* spamFilterActions = spamFilter->actions(); 00252 KMFilterAction* spamFilterAction1 = dict["transfer"]->create(); 00253 spamFilterAction1->argsFromString( mSpamRulesPage->selectedFolderName() ); 00254 spamFilterActions->append( spamFilterAction1 ); 00255 KMFilterAction* spamFilterAction2 = dict["set status"]->create(); 00256 spamFilterAction2->argsFromString( "P" ); // Spam 00257 spamFilterActions->append( spamFilterAction2 ); 00258 if ( mSpamRulesPage->markReadRulesSelected() ) { 00259 KMFilterAction* spamFilterAction3 = dict["set status"]->create(); 00260 spamFilterAction3->argsFromString( "R" ); // Read 00261 spamFilterActions->append( spamFilterAction3 ); 00262 } 00263 KMSearchPattern* spamFilterPattern = spamFilter->pattern(); 00264 spamFilterPattern->setName( i18n( "Spam handling" ) ); 00265 spamFilterPattern->setOp( KMSearchPattern::OpOr ); 00266 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00267 it != mToolList.end(); ++it ) { 00268 if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) ) 00269 { 00270 if ( (*it).isSpamTool() ) 00271 { 00272 const QCString header = (*it).getDetectionHeader().ascii(); 00273 const QString & pattern = (*it).getDetectionPattern(); 00274 if ( (*it).isUseRegExp() ) 00275 spamFilterPattern->append( 00276 KMSearchRule::createInstance( header, 00277 KMSearchRule::FuncRegExp, pattern ) ); 00278 else 00279 spamFilterPattern->append( 00280 KMSearchRule::createInstance( header, 00281 KMSearchRule::FuncContains, pattern ) ); 00282 } 00283 } 00284 } 00285 spamFilter->setApplyOnOutbound( FALSE); 00286 spamFilter->setApplyOnInbound(); 00287 spamFilter->setApplyOnExplicit(); 00288 spamFilter->setStopProcessingHere( TRUE ); 00289 spamFilter->setConfigureShortcut( FALSE ); 00290 00291 KMKernel::self()->filterMgr()->appendFilter( spamFilter ); 00292 } 00293 00294 if ( mSpamRulesPage->classifyRulesSelected() ) 00295 { 00296 // Classify messages manually as Spam 00297 KMFilter* classSpamFilter = new KMFilter(); 00298 classSpamFilter->setIcon( "mark_as_spam" ); 00299 QPtrList<KMFilterAction>* classSpamFilterActions = classSpamFilter->actions(); 00300 KMFilterAction* classSpamFilterActionFirst = dict["set status"]->create(); 00301 classSpamFilterActionFirst->argsFromString( "P" ); 00302 classSpamFilterActions->append( classSpamFilterActionFirst ); 00303 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00304 it != mToolList.end(); ++it ) { 00305 if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) 00306 && (*it).useBayesFilter() ) 00307 { 00308 KMFilterAction* classSpamFilterAction = dict["execute"]->create(); 00309 classSpamFilterAction->argsFromString( (*it).getSpamCmd() ); 00310 classSpamFilterActions->append( classSpamFilterAction ); 00311 } 00312 } 00313 KMFilterAction* classSpamFilterActionLast = dict["transfer"]->create(); 00314 classSpamFilterActionLast->argsFromString( mSpamRulesPage->selectedFolderName() ); 00315 classSpamFilterActions->append( classSpamFilterActionLast ); 00316 00317 KMSearchPattern* classSpamFilterPattern = classSpamFilter->pattern(); 00318 classSpamFilterPattern->setName( i18n( "Classify as spam" ) ); 00319 classSpamFilterPattern->append( KMSearchRule::createInstance( "<size>", 00320 KMSearchRule::FuncIsGreaterOrEqual, "0" ) ); 00321 classSpamFilter->setApplyOnOutbound( FALSE); 00322 classSpamFilter->setApplyOnInbound( FALSE ); 00323 classSpamFilter->setApplyOnExplicit( FALSE ); 00324 classSpamFilter->setStopProcessingHere( TRUE ); 00325 classSpamFilter->setConfigureShortcut( TRUE ); 00326 KMKernel::self()->filterMgr()->appendFilter( classSpamFilter ); 00327 00328 // Classify messages manually as not Spam / as Ham 00329 KMFilter* classHamFilter = new KMFilter(); 00330 QPtrList<KMFilterAction>* classHamFilterActions = classHamFilter->actions(); 00331 KMFilterAction* classHamFilterActionFirst = dict["set status"]->create(); 00332 classHamFilterActionFirst->argsFromString( "H" ); 00333 classHamFilterActions->append( classHamFilterActionFirst ); 00334 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00335 it != mToolList.end(); ++it ) { 00336 if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) 00337 && (*it).useBayesFilter() ) 00338 { 00339 KMFilterAction* classHamFilterAction = dict["execute"]->create(); 00340 classHamFilterAction->argsFromString( (*it).getHamCmd() ); 00341 classHamFilterActions->append( classHamFilterAction ); 00342 } 00343 } 00344 KMSearchPattern* classHamFilterPattern = classHamFilter->pattern(); 00345 classHamFilterPattern->setName( i18n( "Classify as NOT spam" ) ); 00346 classHamFilterPattern->append( KMSearchRule::createInstance( "<size>", 00347 KMSearchRule::FuncIsGreaterOrEqual, "0" ) ); 00348 classHamFilter->setApplyOnOutbound( FALSE); 00349 classHamFilter->setApplyOnInbound( FALSE ); 00350 classHamFilter->setApplyOnExplicit( FALSE ); 00351 classHamFilter->setStopProcessingHere( TRUE ); 00352 classHamFilter->setConfigureShortcut( TRUE ); 00353 KMKernel::self()->filterMgr()->appendFilter( classHamFilter ); 00354 00355 // add the classification filter actions to the toolbar 00356 QString filterNameSpam = 00357 QString( "Filter %1" ).arg( classSpamFilterPattern->name() ); 00358 filterNameSpam = filterNameSpam.replace( " ", "_" ); 00359 QString filterNameHam = 00360 QString( "Filter %1" ).arg( classHamFilterPattern->name() ); 00361 filterNameHam = filterNameHam.replace( " ", "_" ); 00362 00363 // FIXME post KDE 3.2 00364 // The following code manipulates the kmmainwin.rc file directly. Usuallay 00365 // one would expect to let the toolbar write back it's change from above 00366 // i.e. the new structure including the two added actions. 00367 // In KDE 3.2 there is no API for that so I only fund the way to read in 00368 // the XML file myself, to change it and write it out then. 00369 // As soon as an API is available, the following part can certainly get 00370 // replaced by one or two statements. 00371 // (a.gungl@gmx.de) 00372 00373 // make the toolbar changes persistent - let's be very conservative here 00374 QString config = 00375 KXMLGUIFactory::readConfigFile( "kmmainwin.rc", KMKernel::self()->xmlGuiInstance() ); 00376 #ifndef NDEBUG 00377 kdDebug(5006) << "Read kmmainwin.rc contents (last 1000 chars printed):" << endl; 00378 kdDebug(5006) << config.right( 1000 ) << endl; 00379 kdDebug(5006) << "#####################################################" << endl; 00380 #endif 00381 QDomDocument domDoc; 00382 domDoc.setContent( config ); 00383 QDomNodeList domNodeList = domDoc.elementsByTagName( "ToolBar" ); 00384 if ( domNodeList.count() > 0 ) 00385 kdDebug(5006) << "ToolBar section found." << endl; 00386 else 00387 kdDebug(5006) << "No ToolBar section found." << endl; 00388 for ( unsigned int i = 0; i < domNodeList.count(); i++ ) 00389 { 00390 QDomNode domNode = domNodeList.item( i ); 00391 QDomNamedNodeMap nodeMap = domNode.attributes(); 00392 kdDebug(5006) << "name=" << nodeMap.namedItem( "name" ).nodeValue() << endl; 00393 if ( nodeMap.namedItem( "name" ).nodeValue() == "mainToolBar" ) 00394 { 00395 kdDebug(5006) << "mainToolBar section found." << endl; 00396 bool spamActionFound = false; 00397 bool hamActionFound = false; 00398 QDomNodeList domNodeChildList = domNode.childNodes(); 00399 for ( unsigned int j = 0; j < domNodeChildList.count(); j++ ) 00400 { 00401 QDomNode innerDomNode = domNodeChildList.item( j ); 00402 QDomNamedNodeMap innerNodeMap = innerDomNode.attributes(); 00403 if ( innerNodeMap.namedItem( "name" ).nodeValue() == filterNameSpam ) 00404 spamActionFound = true; 00405 if ( innerNodeMap.namedItem( "name" ).nodeValue() == filterNameHam ) 00406 hamActionFound = true; 00407 } 00408 00409 // append the new actions if not yet existing 00410 if ( !spamActionFound ) 00411 { 00412 QDomElement domElemSpam = domDoc.createElement( "Action" ); 00413 domElemSpam.setAttribute( "name", filterNameSpam ); 00414 domNode.appendChild( domElemSpam ); 00415 kdDebug(5006) << "Spam action added to toolbar." << endl; 00416 } 00417 if ( !hamActionFound ) 00418 { 00419 QDomElement domElemHam = domDoc.createElement( "Action" ); 00420 domElemHam.setAttribute( "name", filterNameHam ); 00421 domNode.appendChild( domElemHam ); 00422 kdDebug(5006) << "Ham action added to toolbar." << endl; 00423 } 00424 if ( !spamActionFound || !hamActionFound ) 00425 { 00426 #ifndef NDEBUG 00427 kdDebug(5006) << "New kmmainwin.rc structur (last 1000 chars printed):" << endl; 00428 kdDebug(5006) << domDoc.toString().right( 1000 ) << endl; 00429 kdDebug(5006) << "####################################################" << endl; 00430 #endif 00431 // write back the modified resource file 00432 KXMLGUIFactory::saveConfigFile( domDoc, "kmmainwin.rc", 00433 KMKernel::self()->xmlGuiInstance() ); 00434 } 00435 } 00436 else 00437 kdDebug(5006) << "No mainToolBar section found." << endl; 00438 } 00439 } 00440 } 00441 00442 QDialog::accept(); 00443 } 00444 00445 00446 void AntiSpamWizard::checkProgramsSelections() 00447 { 00448 bool status = false; 00449 bool canClassify = false; 00450 mSpamToolsUsed = false; 00451 mVirusToolsUsed = false; 00452 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00453 it != mToolList.end(); ++it ) { 00454 if ( mProgramsPage->isProgramSelected( (*it).getVisibleName() ) ) 00455 { 00456 status = true; 00457 if ( (*it).isSpamTool() ) 00458 mSpamToolsUsed = true; 00459 if ( (*it).isVirusTool() ) 00460 mVirusToolsUsed = true; 00461 } 00462 if ( (*it).useBayesFilter() ) 00463 canClassify = true; 00464 } 00465 00466 if ( mSpamRulesPage ) 00467 mSpamRulesPage->allowClassification( canClassify ); 00468 00469 if ( mSpamRulesPage ) 00470 removePage( mSpamRulesPage ); 00471 if ( mVirusRulesPage ) 00472 removePage( mVirusRulesPage ); 00473 if ( ( mMode == AntiSpam ) && mSpamToolsUsed ) 00474 { 00475 addPage( mSpamRulesPage, i18n( "Please select the spam filters to be created inside KMail." )); 00476 checkSpamRulesSelections(); 00477 } 00478 if ( ( mMode == AntiVirus ) && mVirusToolsUsed ) 00479 { 00480 addPage( mVirusRulesPage, i18n( "Please select the virus filters to be created inside KMail." )); 00481 checkVirusRulesSelections(); 00482 } 00483 00484 setNextEnabled( mProgramsPage, status ); 00485 } 00486 00487 00488 void AntiSpamWizard::checkSpamRulesSelections() 00489 { 00490 setFinishEnabled( mSpamRulesPage, anySpamOptionChecked() ); 00491 } 00492 00493 void AntiSpamWizard::checkVirusRulesSelections() 00494 { 00495 setFinishEnabled( mVirusRulesPage, anyVirusOptionChecked() ); 00496 } 00497 00498 00499 void AntiSpamWizard::checkToolAvailability() 00500 { 00501 KCursorSaver busy(KBusyPtr::busy()); // this can take some time to find the tools 00502 00503 // checkboxes for the tools 00504 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00505 it != mToolList.end(); ++it ) { 00506 QString text( i18n("Scanning for %1...").arg( (*it).getId() ) ); 00507 mInfoPage->setScanProgressText( text ); 00508 KApplication::kApplication()->processEvents( 200 ); 00509 int rc = checkForProgram( (*it).getExecutable() ); 00510 mProgramsPage->setProgramAsFound( (*it).getVisibleName(), !rc ); 00511 } 00512 mInfoPage->setScanProgressText( ( mMode == AntiSpam ) 00513 ? i18n("Scanning for anti-spam tools finished.") 00514 : i18n("Scanning for anti-virus tools finished.") ); 00515 setNextEnabled( mInfoPage, true ); 00516 } 00517 00518 00519 int AntiSpamWizard::checkForProgram( QString executable ) 00520 { 00521 kdDebug(5006) << "Testing for executable:" << executable << endl; 00522 KProcess process; 00523 process << executable; 00524 process.setUseShell( true ); 00525 process.start( KProcess::Block ); 00526 return process.exitStatus(); 00527 } 00528 00529 00530 void AntiSpamWizard::slotHelpClicked() 00531 { 00532 if ( mMode == AntiSpam ) 00533 kapp->invokeHelp( "the-anti-spam-wizard", "kmail" ); 00534 else 00535 kapp->invokeHelp( "the-anti-virus-wizard", "kmail" ); 00536 } 00537 00538 00539 bool AntiSpamWizard::anySpamOptionChecked() 00540 { 00541 return ( mSpamRulesPage->moveRulesSelected() 00542 || mSpamRulesPage->pipeRulesSelected() 00543 || mSpamRulesPage->classifyRulesSelected() ); 00544 } 00545 00546 bool AntiSpamWizard::anyVirusOptionChecked() 00547 { 00548 return ( mVirusRulesPage->moveRulesSelected() 00549 || mVirusRulesPage->pipeRulesSelected() ); 00550 } 00551 00552 00553 //--------------------------------------------------------------------------- 00554 AntiSpamWizard::SpamToolConfig::SpamToolConfig(QString toolId, 00555 int configVersion,QString name, QString exec, 00556 QString url, QString filter, QString detection, QString spam, QString ham, 00557 QString header, QString pattern, bool regExp, bool bayesFilter, WizardMode type) 00558 : mId( toolId ), mVersion( configVersion ), 00559 mVisibleName( name ), mExecutable( exec ), mWhatsThisText( url ), 00560 mFilterName( filter ), mDetectCmd( detection ), mSpamCmd( spam ), 00561 mHamCmd( ham ), mDetectionHeader( header ), mDetectionPattern( pattern ), 00562 mUseRegExp( regExp ), mSupportsBayesFilter( bayesFilter ), mType( type ) 00563 { 00564 } 00565 00566 00567 //--------------------------------------------------------------------------- 00568 AntiSpamWizard::ConfigReader::ConfigReader( WizardMode mode, 00569 QValueList<SpamToolConfig> & configList ) 00570 : mToolList( configList ), 00571 mMode( mode ) 00572 { 00573 if ( mMode == AntiSpam ) 00574 mConfig = new KConfig( "kmail.antispamrc", true ); 00575 else 00576 mConfig = new KConfig( "kmail.antivirusrc", true ); 00577 } 00578 00579 00580 void AntiSpamWizard::ConfigReader::readAndMergeConfig() 00581 { 00582 QString groupName = ( mMode == AntiSpam ) 00583 ? QString("Spamtool #%1") 00584 : QString("Virustool #%1"); 00585 // read the configuration from the global config file 00586 mConfig->setReadDefaults( true ); 00587 KConfigGroup general( mConfig, "General" ); 00588 int registeredTools = general.readNumEntry( "tools", 0 ); 00589 for (int i = 1; i <= registeredTools; i++) 00590 { 00591 KConfigGroup toolConfig( mConfig, groupName.arg( i ) ); 00592 mToolList.append( readToolConfig( toolConfig ) ); 00593 } 00594 00595 // read the configuration from the user config file 00596 // and merge newer config data 00597 mConfig->setReadDefaults( false ); 00598 KConfigGroup user_general( mConfig, "General" ); 00599 int user_registeredTools = user_general.readNumEntry( "tools", 0 ); 00600 for (int i = 1; i <= user_registeredTools; i++) 00601 { 00602 KConfigGroup toolConfig( mConfig, groupName.arg( i ) ); 00603 mergeToolConfig( readToolConfig( toolConfig ) ); 00604 } 00605 // Make sure to have add least one tool listed even when the 00606 // config file was not found or whatever went wrong 00607 // Currently only works for spam tools 00608 if ( mMode == AntiSpam ) { 00609 if ( registeredTools < 1 && user_registeredTools < 1 ) 00610 mToolList.append( createDummyConfig() ); 00611 } 00612 } 00613 00614 00615 AntiSpamWizard::SpamToolConfig 00616 AntiSpamWizard::ConfigReader::readToolConfig( KConfigGroup & configGroup ) 00617 { 00618 QString id = configGroup.readEntry( "Ident" ); 00619 int version = configGroup.readNumEntry( "Version" ); 00620 #ifndef NDEBUG 00621 kdDebug(5006) << "Found predefined tool: " << id << endl; 00622 kdDebug(5006) << "With config version : " << version << endl; 00623 #endif 00624 QString name = configGroup.readEntry( "VisibleName" ); 00625 QString executable = configGroup.readEntry( "Executable" ); 00626 QString url = configGroup.readEntry( "URL" ); 00627 QString filterName = configGroup.readEntry( "PipeFilterName" ); 00628 QString detectCmd = configGroup.readEntry( "PipeCmdDetect" ); 00629 QString spamCmd = configGroup.readEntry( "ExecCmdSpam" ); 00630 QString hamCmd = configGroup.readEntry( "ExecCmdHam" ); 00631 QString header = configGroup.readEntry( "DetectionHeader" ); 00632 QString pattern = configGroup.readEntry( "DetectionPattern" ); 00633 bool useRegExp = configGroup.readBoolEntry( "UseRegExp" ); 00634 bool supportsBayes = configGroup.readBoolEntry( "SupportsBayes", false ); 00635 return SpamToolConfig( id, version, name, executable, url, 00636 filterName, detectCmd, spamCmd, hamCmd, 00637 header, pattern, useRegExp, supportsBayes, mMode ); 00638 } 00639 00640 00641 AntiSpamWizard::SpamToolConfig AntiSpamWizard::ConfigReader::createDummyConfig() 00642 { 00643 return SpamToolConfig( "spamassassin", 0, 00644 "&SpamAssassin", "spamassassin -V", 00645 "http://spamassassin.org", "SpamAssassin Check", 00646 "spamassassin -L", 00647 "sa-learn -L --spam --no-rebuild --single", 00648 "sa-learn -L --ham --no-rebuild --single", 00649 "X-Spam-Flag", "yes", 00650 false, true, AntiSpam ); 00651 } 00652 00653 00654 void AntiSpamWizard::ConfigReader::mergeToolConfig( AntiSpamWizard::SpamToolConfig config ) 00655 { 00656 bool found = false; 00657 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin(); 00658 it != mToolList.end(); ++it ) { 00659 #ifndef NDEBUG 00660 kdDebug(5006) << "Check against tool: " << (*it).getId() << endl; 00661 kdDebug(5006) << "Against version : " << (*it).getVersion() << endl; 00662 #endif 00663 if ( (*it).getId() == config.getId() ) 00664 { 00665 found = true; 00666 if ( (*it).getVersion() < config.getVersion() ) 00667 { 00668 #ifndef NDEBUG 00669 kdDebug(5006) << "Replacing config ..." << endl; 00670 #endif 00671 mToolList.remove( it ); 00672 mToolList.append( config ); 00673 } 00674 break; 00675 } 00676 } 00677 if ( !found ) 00678 mToolList.append( config ); 00679 } 00680 00681 00682 //--------------------------------------------------------------------------- 00683 ASWizInfoPage::ASWizInfoPage( AntiSpamWizard::WizardMode mode, 00684 QWidget * parent, const char * name ) 00685 : QWidget( parent, name ) 00686 { 00687 QGridLayout *grid = new QGridLayout( this, 1, 1, KDialog::marginHint(), 00688 KDialog::spacingHint() ); 00689 grid->setColStretch( 1, 10 ); 00690 00691 mIntroText = new QLabel( this ); 00692 mIntroText->setText( 00693 ( mode == AntiSpamWizard::AntiSpam ) 00694 ? i18n( 00695 "<p>Here you can get some assistance in setting up KMail's filter " 00696 "rules to use some commonly-known anti-spam tools.</p>" 00697 "<p>The wizard can detect those tools on your computer as " 00698 "well as create filter rules to classify messages using these " 00699 "tools and to separate messages classified as spam. " 00700 "The wizard will not take any existing filter " 00701 "rules into consideration: it will always append the new rules.</p>" 00702 "<p><b>Warning:</b> As KMail is blocked during the scan of the " 00703 "messages for spam, you may encounter problems with " 00704 "the responsiveness of KMail because anti-spam tool " 00705 "operations are usually time consuming; please consider " 00706 "deleting the filter rules created by the wizard to get " 00707 "back to the former behavior." 00708 ) 00709 : i18n( 00710 "<p>Here you can get some assistance in setting up KMail's filter " 00711 "rules to use some commonly-known anti-virus tools.</p>" 00712 "<p>The wizard can detect those tools on your computer as " 00713 "well as create filter rules to classify messages using these " 00714 "tools and to separate messages containing viruses. " 00715 "The wizard will not take any existing filter " 00716 "rules into consideration: it will always append the new rules.</p>" 00717 "<p><b>Warning:</b> As KMail is blocked during the scan of the " 00718 "messages for viruses, you may encounter problems with " 00719 "the responsiveness of KMail because anti-virus tool " 00720 "operations are usually time consuming; please consider " 00721 "deleting the filter rules created by the wizard to get " 00722 "back to the former behavior." 00723 ) ); 00724 grid->addWidget( mIntroText, 0, 0 ); 00725 00726 mScanProgressText = new QLabel( this ); 00727 mScanProgressText->setText( "" ) ; 00728 grid->addWidget( mScanProgressText, 1, 0 ); 00729 } 00730 00731 void ASWizInfoPage::setScanProgressText( const QString &toolName ) 00732 { 00733 mScanProgressText->setText( toolName ); 00734 } 00735 00736 //--------------------------------------------------------------------------- 00737 ASWizProgramsPage::ASWizProgramsPage( QWidget * parent, const char * name, 00738 QStringList &checkBoxTextList, 00739 QStringList &checkBoxWhatsThisList ) 00740 : QWidget( parent, name ) 00741 { 00742 QGridLayout *grid = new QGridLayout( this, 3, 1, KDialog::marginHint(), 00743 KDialog::spacingHint() ); 00744 // checkboxes for the tools 00745 int row = 0; 00746 QStringList::Iterator it1 = checkBoxTextList.begin(); 00747 QStringList::Iterator it2 = checkBoxWhatsThisList.begin(); 00748 while ( it1 != checkBoxTextList.end() ) 00749 { 00750 QCheckBox *box = new QCheckBox( *it1, this ); 00751 if ( it2 != checkBoxWhatsThisList.end() ) 00752 { 00753 QWhatsThis::add( box, *it2 ); 00754 QToolTip::add( box, *it2 ); 00755 ++it2; 00756 } 00757 grid->addWidget( box, row++, 0 ); 00758 connect( box, SIGNAL(clicked()), 00759 this, SLOT(processSelectionChange(void)) ); 00760 mProgramDict.insert( *it1, box ); 00761 ++it1; 00762 } 00763 00764 // hint text 00765 QLabel *introText = new QLabel( this ); 00766 introText->setText( i18n( 00767 "<p>For these tools it is possible to let the " 00768 "wizard create filter rules. KMail tried to find the tools " 00769 "in the PATH of your system; the wizard does not allow you " 00770 "to create rules for tools which were not found: " 00771 "this is to keep your configuration consistent and " 00772 "to minimize the risk of unpredicted behavior.</p>" 00773 ) ); 00774 grid->addWidget( introText, row++, 0 ); 00775 } 00776 00777 00778 bool ASWizProgramsPage::isProgramSelected( const QString &visibleName ) 00779 { 00780 if ( mProgramDict[visibleName] ) 00781 return mProgramDict[visibleName]->isChecked(); 00782 else 00783 return false; 00784 } 00785 00786 00787 void ASWizProgramsPage::setProgramAsFound( const QString &visibleName, bool found ) 00788 { 00789 QCheckBox * box = mProgramDict[visibleName]; 00790 if ( box ) 00791 { 00792 QString foundText( i18n("(found on this system)") ); 00793 QString notFoundText( i18n("(not found on this system)") ); 00794 QString labelText = visibleName; 00795 labelText += " "; 00796 if ( found ) 00797 labelText += foundText; 00798 else 00799 { 00800 labelText += notFoundText; 00801 box->setEnabled( false ); 00802 } 00803 box->setText( labelText ); 00804 } 00805 } 00806 00807 00808 void ASWizProgramsPage::processSelectionChange() 00809 { 00810 emit selectionChanged(); 00811 } 00812 00813 //--------------------------------------------------------------------------- 00814 ASWizSpamRulesPage::ASWizSpamRulesPage( QWidget * parent, const char * name, 00815 KMFolderTree * mainFolderTree ) 00816 : QWidget( parent, name ) 00817 { 00818 QGridLayout *grid = new QGridLayout( this, 5, 1, KDialog::marginHint(), 00819 KDialog::spacingHint() ); 00820 00821 mClassifyRules = new QCheckBox( i18n("Classify messages manually as spam"), this ); 00822 QWhatsThis::add( mClassifyRules, 00823 i18n( "Sometimes messages are classified wrongly or even not at all; " 00824 "the latter might be by intention, because you perhaps filter " 00825 "out messages from mailing lists before you let the anti-spam " 00826 "tools classify the rest of the messages. You can correct these " 00827 "wrong or missing classifications manually by using the " 00828 "appropriate toolbar buttons which trigger special filters " 00829 "created by this wizard." ) ); 00830 grid->addWidget( mClassifyRules, 0, 0 ); 00831 00832 mPipeRules = new QCheckBox( i18n("Classify messages using the anti-spam tools"), this ); 00833 QWhatsThis::add( mPipeRules, 00834 i18n( "Let the anti-spam tools classify your messages. The wizard " 00835 "will create appropriate filters. The messages are usually " 00836 "marked by the tools so that following filters can react " 00837 "on this and, for example, move spam messages to a special folder.") ); 00838 grid->addWidget( mPipeRules, 1, 0 ); 00839 00840 mMoveRules = new QCheckBox( i18n("Move detected spam messages to the selected folder"), this ); 00841 QWhatsThis::add( mMoveRules, 00842 i18n( "A filter to detect messages classified as spam and to move " 00843 "those messages into a predefined folder is created. The " 00844 "default folder is the trash folder, but you may change that " 00845 "in the folder view.") ); 00846 grid->addWidget( mMoveRules, 2, 0 ); 00847 00848 mMarkRules = new QCheckBox( i18n("Additionally, mark detected spam messages as read"), this ); 00849 mMarkRules->setEnabled( false ); 00850 QWhatsThis::add( mMarkRules, 00851 i18n( "Mark messages which have been classified as " 00852 "spam as read, as well as moving them to the selected " 00853 "folder.") ); 00854 grid->addWidget( mMarkRules, 3, 0 ); 00855 00856 QString s = "trash"; 00857 mFolderTree = new SimpleFolderTree( this, mainFolderTree, s, true ); 00858 grid->addWidget( mFolderTree, 4, 0 ); 00859 00860 connect( mPipeRules, SIGNAL(clicked()), 00861 this, SLOT(processSelectionChange(void)) ); 00862 connect( mClassifyRules, SIGNAL(clicked()), 00863 this, SLOT(processSelectionChange(void)) ); 00864 connect( mMoveRules, SIGNAL(clicked()), 00865 this, SLOT(processSelectionChange(void)) ); 00866 connect( mMarkRules, SIGNAL(clicked()), 00867 this, SLOT(processSelectionChange(void)) ); 00868 connect( mMoveRules, SIGNAL( toggled( bool ) ), 00869 mMarkRules, SLOT( setEnabled( bool ) ) ); 00870 } 00871 00872 bool ASWizSpamRulesPage::pipeRulesSelected() const 00873 { 00874 return mPipeRules->isChecked(); 00875 } 00876 00877 00878 bool ASWizSpamRulesPage::classifyRulesSelected() const 00879 { 00880 return mClassifyRules->isChecked(); 00881 } 00882 00883 00884 bool ASWizSpamRulesPage::moveRulesSelected() const 00885 { 00886 return mMoveRules->isChecked(); 00887 } 00888 00889 bool ASWizSpamRulesPage::markReadRulesSelected() const 00890 { 00891 return mMarkRules->isChecked(); 00892 } 00893 00894 00895 QString ASWizSpamRulesPage::selectedFolderName() const 00896 { 00897 QString name = "trash"; 00898 if ( mFolderTree->folder() ) 00899 name = mFolderTree->folder()->idString(); 00900 return name; 00901 } 00902 00903 void ASWizSpamRulesPage::processSelectionChange() 00904 { 00905 emit selectionChanged(); 00906 } 00907 00908 00909 void ASWizSpamRulesPage::allowClassification( bool enabled ) 00910 { 00911 if ( enabled ) 00912 mClassifyRules->setEnabled( true ); 00913 else 00914 { 00915 mClassifyRules->setChecked( false ); 00916 mClassifyRules->setEnabled( false ); 00917 } 00918 } 00919 00920 //--------------------------------------------------------------------------- 00921 ASWizVirusRulesPage::ASWizVirusRulesPage( QWidget * parent, const char * name, 00922 KMFolderTree * mainFolderTree ) 00923 : QWidget( parent, name ) 00924 { 00925 QGridLayout *grid = new QGridLayout( this, 5, 1, KDialog::marginHint(), 00926 KDialog::spacingHint() ); 00927 00928 mPipeRules = new QCheckBox( i18n("Check messages using the anti-virus tools"), this ); 00929 QWhatsThis::add( mPipeRules, 00930 i18n( "Let the anti-virus tools check your messages. The wizard " 00931 "will create appropriate filters. The messages are usually " 00932 "marked by the tools so that following filters can react " 00933 "on this and, for example, move virus messages to a special folder.") ); 00934 grid->addWidget( mPipeRules, 0, 0 ); 00935 00936 mMoveRules = new QCheckBox( i18n("Move detected viral messages to the selected folder"), this ); 00937 QWhatsThis::add( mMoveRules, 00938 i18n( "A filter to detect messages classified as virus-infected and to move " 00939 "those messages into a predefined folder is created. The " 00940 "default folder is the trash folder, but you may change that " 00941 "in the folder view.") ); 00942 grid->addWidget( mMoveRules, 1, 0 ); 00943 00944 mMarkRules = new QCheckBox( i18n("Additionally, mark detected viral messages as read"), this ); 00945 mMarkRules->setEnabled( false ); 00946 QWhatsThis::add( mMarkRules, 00947 i18n( "Mark messages which have been classified as " 00948 "virus-infected as read, as well as moving them " 00949 "to the selected folder.") ); 00950 grid->addWidget( mMarkRules, 2, 0 ); 00951 00952 QString s = "trash"; 00953 mFolderTree = new SimpleFolderTree( this, mainFolderTree, s, true ); 00954 grid->addWidget( mFolderTree, 3, 0 ); 00955 00956 connect( mPipeRules, SIGNAL(clicked()), 00957 this, SLOT(processSelectionChange(void)) ); 00958 connect( mMoveRules, SIGNAL(clicked()), 00959 this, SLOT(processSelectionChange(void)) ); 00960 connect( mMarkRules, SIGNAL(clicked()), 00961 this, SLOT(processSelectionChange(void)) ); 00962 connect( mMoveRules, SIGNAL( toggled( bool ) ), 00963 mMarkRules, SLOT( setEnabled( bool ) ) ); 00964 } 00965 00966 bool ASWizVirusRulesPage::pipeRulesSelected() const 00967 { 00968 return mPipeRules->isChecked(); 00969 } 00970 00971 00972 bool ASWizVirusRulesPage::moveRulesSelected() const 00973 { 00974 return mMoveRules->isChecked(); 00975 } 00976 00977 bool ASWizVirusRulesPage::markReadRulesSelected() const 00978 { 00979 return mMarkRules->isChecked(); 00980 } 00981 00982 00983 QString ASWizVirusRulesPage::selectedFolderName() const 00984 { 00985 QString name = "trash"; 00986 if ( mFolderTree->folder() ) 00987 name = mFolderTree->folder()->idString(); 00988 return name; 00989 } 00990 00991 void ASWizVirusRulesPage::processSelectionChange() 00992 { 00993 emit selectionChanged(); 00994 } 00995 00996 #include "antispamwizard.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:52:01 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003