00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "antispamwizard.h"
00031 #include "kcursorsaver.h"
00032 #include "accountmanager.h"
00033 #include "kmfilter.h"
00034 #include "kmfilteraction.h"
00035 #include "kmfiltermgr.h"
00036 #include "kmkernel.h"
00037 #include "kmfoldertree.h"
00038 #include "kmmainwin.h"
00039 #include "networkaccount.h"
00040 #include "folderrequester.h"
00041
00042 #include <kaction.h>
00043 #include <kapplication.h>
00044 #include <kdebug.h>
00045 #include <kdialog.h>
00046 #include <kiconloader.h>
00047 #include <klocale.h>
00048 #include <kmessagebox.h>
00049 #include <kprocess.h>
00050
00051 #include <qdom.h>
00052 #include <qlabel.h>
00053 #include <qlayout.h>
00054 #include <qtooltip.h>
00055 #include <qwhatsthis.h>
00056
00057 using namespace KMail;
00058
00059 AntiSpamWizard::AntiSpamWizard( WizardMode mode,
00060 QWidget* parent, KMFolderTree * mainFolderTree )
00061 : KWizard( parent ),
00062 mInfoPage( 0 ),
00063 mSpamRulesPage( 0 ),
00064 mVirusRulesPage( 0 ),
00065 mSummaryPage( 0 ),
00066 mMode( mode )
00067 {
00068
00069 ConfigReader reader( mMode, mToolList );
00070 reader.readAndMergeConfig();
00071 mToolList = reader.getToolList();
00072
00073 #ifndef NDEBUG
00074 if ( mMode == AntiSpam )
00075 kdDebug(5006) << endl << "Considered anti-spam tools: " << endl;
00076 else
00077 kdDebug(5006) << endl << "Considered anti-virus tools: " << endl;
00078 #endif
00079 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00080 it != mToolList.end(); ++it ) {
00081 #ifndef NDEBUG
00082 kdDebug(5006) << "Predefined tool: " << (*it).getId() << endl;
00083 kdDebug(5006) << "Config version: " << (*it).getVersion() << endl;
00084 kdDebug(5006) << "Selection priority: " << (*it).getPrio() << endl;
00085 kdDebug(5006) << "Displayed name: " << (*it).getVisibleName() << endl;
00086 kdDebug(5006) << "Executable: " << (*it).getExecutable() << endl;
00087 kdDebug(5006) << "WhatsThis URL: " << (*it).getWhatsThisText() << endl;
00088 kdDebug(5006) << "Filter name: " << (*it).getFilterName() << endl;
00089 kdDebug(5006) << "Detection command: " << (*it).getDetectCmd() << endl;
00090 kdDebug(5006) << "Learn spam command: " << (*it).getSpamCmd() << endl;
00091 kdDebug(5006) << "Learn ham command: " << (*it).getHamCmd() << endl;
00092 kdDebug(5006) << "Detection header: " << (*it).getDetectionHeader() << endl;
00093 kdDebug(5006) << "Detection pattern: " << (*it).getDetectionPattern() << endl;
00094 kdDebug(5006) << "Use as RegExp: " << (*it).isUseRegExp() << endl;
00095 kdDebug(5006) << "Supports Bayes Filter: " << (*it).useBayesFilter() << endl;
00096 kdDebug(5006) << "Type: " << (*it).getType() << endl << endl;
00097 #endif
00098 }
00099
00100 setCaption( ( mMode == AntiSpam ) ? i18n( "Anti-Spam Wizard" )
00101 : i18n( "Anti-Virus Wizard" ) );
00102 mInfoPage = new ASWizInfoPage( mMode, 0, "" );
00103 addPage( mInfoPage,
00104 ( mMode == AntiSpam )
00105 ? i18n( "Welcome to the KMail Anti-Spam Wizard" )
00106 : i18n( "Welcome to the KMail Anti-Virus Wizard" ) );
00107 connect( mInfoPage, SIGNAL( selectionChanged( void ) ),
00108 this, SLOT( checkProgramsSelections( void ) ) );
00109
00110 if ( mMode == AntiSpam ) {
00111 mSpamRulesPage = new ASWizSpamRulesPage( 0, "", mainFolderTree );
00112 addPage( mSpamRulesPage, i18n( "Options to fine-tune the handling of spam messages" ));
00113 connect( mSpamRulesPage, SIGNAL( selectionChanged( void ) ),
00114 this, SLOT( slotBuildSummary( void ) ) );
00115 }
00116 else {
00117 mVirusRulesPage = new ASWizVirusRulesPage( 0, "", mainFolderTree );
00118 addPage( mVirusRulesPage, i18n( "Options to fine-tune the handling of virus messages" ));
00119 connect( mVirusRulesPage, SIGNAL( selectionChanged( void ) ),
00120 this, SLOT( checkVirusRulesSelections( void ) ) );
00121 }
00122
00123 connect( this, SIGNAL( helpClicked( void) ),
00124 this, SLOT( slotHelpClicked( void ) ) );
00125
00126 setNextEnabled( mInfoPage, false );
00127
00128 if ( mMode == AntiSpam ) {
00129 mSummaryPage = new ASWizSummaryPage( 0, "" );
00130 addPage( mSummaryPage, i18n( "Summary of changes to be made by this wizard" ) );
00131 setNextEnabled( mSpamRulesPage, true );
00132 setFinishEnabled( mSummaryPage, true );
00133 }
00134
00135 QTimer::singleShot( 0, this, SLOT( checkToolAvailability( void ) ) );
00136 }
00137
00138
00139 void AntiSpamWizard::accept()
00140 {
00141 if ( mSpamRulesPage ) {
00142 kdDebug( 5006 ) << "Folder name for messages classified as spam is "
00143 << mSpamRulesPage->selectedSpamFolderName() << endl;
00144 kdDebug( 5006 ) << "Folder name for messages classified as unsure is "
00145 << mSpamRulesPage->selectedUnsureFolderName() << endl;
00146 }
00147 if ( mVirusRulesPage )
00148 kdDebug( 5006 ) << "Folder name for viruses is "
00149 << mVirusRulesPage->selectedFolderName() << endl;
00150
00151 KMFilterActionDict dict;
00152 QValueList<KMFilter*> filterList;
00153 bool replaceExistingFilters = false;
00154
00155
00156
00157 if ( mMode == AntiVirus ) {
00158 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00159 it != mToolList.end(); ++it ) {
00160 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) &&
00161 ( mVirusRulesPage->pipeRulesSelected() && (*it).isVirusTool() ) )
00162 {
00163
00164
00165
00166 KMFilter* pipeFilter = new KMFilter();
00167 QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions();
00168 KMFilterAction* pipeFilterAction = dict["filter app"]->create();
00169 pipeFilterAction->argsFromString( (*it).getDetectCmd() );
00170 pipeFilterActions->append( pipeFilterAction );
00171 KMSearchPattern* pipeFilterPattern = pipeFilter->pattern();
00172 pipeFilterPattern->setName( uniqueNameFor( (*it).getFilterName() ) );
00173 pipeFilterPattern->append( KMSearchRule::createInstance( "<size>",
00174 KMSearchRule::FuncIsGreaterOrEqual, "0" ) );
00175 pipeFilter->setApplyOnOutbound( false);
00176 pipeFilter->setApplyOnInbound();
00177 pipeFilter->setApplyOnExplicit();
00178 pipeFilter->setStopProcessingHere( false );
00179 pipeFilter->setConfigureShortcut( false );
00180
00181 filterList.append( pipeFilter );
00182 }
00183 }
00184
00185 if ( mVirusRulesPage->moveRulesSelected() )
00186 {
00187
00188 KMFilter* virusFilter = new KMFilter();
00189 QPtrList<KMFilterAction>* virusFilterActions = virusFilter->actions();
00190 KMFilterAction* virusFilterAction1 = dict["transfer"]->create();
00191 virusFilterAction1->argsFromString( mVirusRulesPage->selectedFolderName() );
00192 virusFilterActions->append( virusFilterAction1 );
00193 if ( mVirusRulesPage->markReadRulesSelected() ) {
00194 KMFilterAction* virusFilterAction2 = dict["set status"]->create();
00195 virusFilterAction2->argsFromString( "R" );
00196 virusFilterActions->append( virusFilterAction2 );
00197 }
00198 KMSearchPattern* virusFilterPattern = virusFilter->pattern();
00199 virusFilterPattern->setName( uniqueNameFor( i18n( "Virus handling" ) ) );
00200 virusFilterPattern->setOp( KMSearchPattern::OpOr );
00201 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00202 it != mToolList.end(); ++it ) {
00203 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ))
00204 {
00205 if ( (*it).isVirusTool() )
00206 {
00207 const QCString header = (*it).getDetectionHeader().ascii();
00208 const QString & pattern = (*it).getDetectionPattern();
00209 if ( (*it).isUseRegExp() )
00210 virusFilterPattern->append(
00211 KMSearchRule::createInstance( header,
00212 KMSearchRule::FuncRegExp, pattern ) );
00213 else
00214 virusFilterPattern->append(
00215 KMSearchRule::createInstance( header,
00216 KMSearchRule::FuncContains, pattern ) );
00217 }
00218 }
00219 }
00220 virusFilter->setApplyOnOutbound( false);
00221 virusFilter->setApplyOnInbound();
00222 virusFilter->setApplyOnExplicit();
00223 virusFilter->setStopProcessingHere( true );
00224 virusFilter->setConfigureShortcut( false );
00225
00226 filterList.append( virusFilter );
00227 }
00228 }
00229 else {
00230
00231
00232
00233 replaceExistingFilters = true;
00234 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00235 it != mToolList.end(); ++it ) {
00236 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) &&
00237 (*it).isSpamTool() && !(*it).isDetectionOnly() )
00238 {
00239
00240
00241
00242 KMFilter* pipeFilter = new KMFilter();
00243 QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions();
00244 KMFilterAction* pipeFilterAction = dict["filter app"]->create();
00245 pipeFilterAction->argsFromString( (*it).getDetectCmd() );
00246 pipeFilterActions->append( pipeFilterAction );
00247 KMSearchPattern* pipeFilterPattern = pipeFilter->pattern();
00248 if ( replaceExistingFilters )
00249 pipeFilterPattern->setName( (*it).getFilterName() );
00250 else
00251 pipeFilterPattern->setName( uniqueNameFor( (*it).getFilterName() ) );
00252 pipeFilterPattern->append( KMSearchRule::createInstance( "<size>",
00253 KMSearchRule::FuncIsLessOrEqual, "256000" ) );
00254 pipeFilter->setApplyOnOutbound( false);
00255 pipeFilter->setApplyOnInbound();
00256 pipeFilter->setApplyOnExplicit();
00257 pipeFilter->setStopProcessingHere( false );
00258 pipeFilter->setConfigureShortcut( false );
00259
00260 filterList.append( pipeFilter );
00261 }
00262 }
00263
00264
00265 KMFilter* spamFilter = new KMFilter();
00266 QPtrList<KMFilterAction>* spamFilterActions = spamFilter->actions();
00267 if ( mSpamRulesPage->moveSpamSelected() )
00268 {
00269 KMFilterAction* spamFilterAction1 = dict["transfer"]->create();
00270 spamFilterAction1->argsFromString( mSpamRulesPage->selectedSpamFolderName() );
00271 spamFilterActions->append( spamFilterAction1 );
00272 }
00273 KMFilterAction* spamFilterAction2 = dict["set status"]->create();
00274 spamFilterAction2->argsFromString( "P" );
00275 spamFilterActions->append( spamFilterAction2 );
00276 if ( mSpamRulesPage->markAsReadSelected() ) {
00277 KMFilterAction* spamFilterAction3 = dict["set status"]->create();
00278 spamFilterAction3->argsFromString( "R" );
00279 spamFilterActions->append( spamFilterAction3 );
00280 }
00281 KMSearchPattern* spamFilterPattern = spamFilter->pattern();
00282 if ( replaceExistingFilters )
00283 spamFilterPattern->setName( i18n( "Spam handling" ) );
00284 else
00285 spamFilterPattern->setName( uniqueNameFor( i18n( "Spam handling" ) ) );
00286 spamFilterPattern->setOp( KMSearchPattern::OpOr );
00287 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00288 it != mToolList.end(); ++it ) {
00289 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) )
00290 {
00291 if ( (*it).isSpamTool() )
00292 {
00293 const QCString header = (*it).getDetectionHeader().ascii();
00294 const QString & pattern = (*it).getDetectionPattern();
00295 if ( (*it).isUseRegExp() )
00296 spamFilterPattern->append(
00297 KMSearchRule::createInstance( header,
00298 KMSearchRule::FuncRegExp, pattern ) );
00299 else
00300 spamFilterPattern->append(
00301 KMSearchRule::createInstance( header,
00302 KMSearchRule::FuncContains, pattern ) );
00303 }
00304 }
00305 }
00306 spamFilter->setApplyOnOutbound( false);
00307 spamFilter->setApplyOnInbound();
00308 spamFilter->setApplyOnExplicit();
00309 spamFilter->setStopProcessingHere( true );
00310 spamFilter->setConfigureShortcut( false );
00311 filterList.append( spamFilter );
00312
00313 if ( mSpamRulesPage->moveUnsureSelected() )
00314 {
00315
00316 bool atLeastOneUnsurePattern = false;
00317 KMFilter* unsureFilter = new KMFilter();
00318 QPtrList<KMFilterAction>* unsureFilterActions = unsureFilter->actions();
00319 KMFilterAction* unsureFilterAction1 = dict["transfer"]->create();
00320 unsureFilterAction1->argsFromString( mSpamRulesPage->selectedUnsureFolderName() );
00321 unsureFilterActions->append( unsureFilterAction1 );
00322 KMSearchPattern* unsureFilterPattern = unsureFilter->pattern();
00323 if ( replaceExistingFilters )
00324 unsureFilterPattern->setName( i18n( "Semi spam (unsure) handling" ) );
00325 else
00326 unsureFilterPattern->setName( uniqueNameFor( i18n( "Semi spam (unsure) handling" ) ) );
00327 unsureFilterPattern->setOp( KMSearchPattern::OpOr );
00328 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00329 it != mToolList.end(); ++it ) {
00330 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) )
00331 {
00332 if ( (*it).isSpamTool() && (*it).hasTristateDetection())
00333 {
00334 atLeastOneUnsurePattern = true;
00335 const QCString header = (*it).getDetectionHeader().ascii();
00336 const QString & pattern = (*it).getDetectionPattern2();
00337 if ( (*it).isUseRegExp() )
00338 unsureFilterPattern->append(
00339 KMSearchRule::createInstance( header,
00340 KMSearchRule::FuncRegExp, pattern ) );
00341 else
00342 unsureFilterPattern->append(
00343 KMSearchRule::createInstance( header,
00344 KMSearchRule::FuncContains, pattern ) );
00345 }
00346 }
00347 }
00348 unsureFilter->setApplyOnOutbound( false);
00349 unsureFilter->setApplyOnInbound();
00350 unsureFilter->setApplyOnExplicit();
00351 unsureFilter->setStopProcessingHere( true );
00352 unsureFilter->setConfigureShortcut( false );
00353
00354 if ( atLeastOneUnsurePattern )
00355 filterList.append( unsureFilter );
00356 else
00357 delete unsureFilter;
00358 }
00359
00360
00361 KMFilter* classSpamFilter = new KMFilter();
00362 classSpamFilter->setIcon( "mail_spam" );
00363 QPtrList<KMFilterAction>* classSpamFilterActions = classSpamFilter->actions();
00364 KMFilterAction* classSpamFilterActionFirst = dict["set status"]->create();
00365 classSpamFilterActionFirst->argsFromString( "P" );
00366 classSpamFilterActions->append( classSpamFilterActionFirst );
00367 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00368 it != mToolList.end(); ++it ) {
00369 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() )
00370 && (*it).useBayesFilter() && !(*it).isDetectionOnly() )
00371 {
00372 KMFilterAction* classSpamFilterAction = dict["execute"]->create();
00373 classSpamFilterAction->argsFromString( (*it).getSpamCmd() );
00374 classSpamFilterActions->append( classSpamFilterAction );
00375 }
00376 }
00377 if ( mSpamRulesPage->moveSpamSelected() )
00378 {
00379 KMFilterAction* classSpamFilterActionLast = dict["transfer"]->create();
00380 classSpamFilterActionLast->argsFromString( mSpamRulesPage->selectedSpamFolderName() );
00381 classSpamFilterActions->append( classSpamFilterActionLast );
00382 }
00383
00384 KMSearchPattern* classSpamFilterPattern = classSpamFilter->pattern();
00385 if ( replaceExistingFilters )
00386 classSpamFilterPattern->setName( i18n( "Classify as spam" ) );
00387 else
00388 classSpamFilterPattern->setName( uniqueNameFor( i18n( "Classify as spam" ) ) );
00389 classSpamFilterPattern->append( KMSearchRule::createInstance( "<size>",
00390 KMSearchRule::FuncIsGreaterOrEqual, "0" ) );
00391 classSpamFilter->setApplyOnOutbound( false);
00392 classSpamFilter->setApplyOnInbound( false );
00393 classSpamFilter->setApplyOnExplicit( false );
00394 classSpamFilter->setStopProcessingHere( true );
00395 classSpamFilter->setConfigureShortcut( true );
00396 classSpamFilter->setConfigureToolbar( true );
00397 filterList.append( classSpamFilter );
00398
00399
00400 KMFilter* classHamFilter = new KMFilter();
00401 classHamFilter->setIcon( "mail_ham" );
00402 QPtrList<KMFilterAction>* classHamFilterActions = classHamFilter->actions();
00403 KMFilterAction* classHamFilterActionFirst = dict["set status"]->create();
00404 classHamFilterActionFirst->argsFromString( "H" );
00405 classHamFilterActions->append( classHamFilterActionFirst );
00406 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00407 it != mToolList.end(); ++it ) {
00408 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() )
00409 && (*it).useBayesFilter() && !(*it).isDetectionOnly() )
00410 {
00411 KMFilterAction* classHamFilterAction = dict["execute"]->create();
00412 classHamFilterAction->argsFromString( (*it).getHamCmd() );
00413 classHamFilterActions->append( classHamFilterAction );
00414 }
00415 }
00416 KMSearchPattern* classHamFilterPattern = classHamFilter->pattern();
00417 if ( replaceExistingFilters )
00418 classHamFilterPattern->setName( i18n( "Classify as NOT spam" ) );
00419 else
00420 classHamFilterPattern->setName( uniqueNameFor( i18n( "Classify as NOT spam" ) ) );
00421 classHamFilterPattern->append( KMSearchRule::createInstance( "<size>",
00422 KMSearchRule::FuncIsGreaterOrEqual, "0" ) );
00423 classHamFilter->setApplyOnOutbound( false);
00424 classHamFilter->setApplyOnInbound( false );
00425 classHamFilter->setApplyOnExplicit( false );
00426 classHamFilter->setStopProcessingHere( true );
00427 classHamFilter->setConfigureShortcut( true );
00428 classHamFilter->setConfigureToolbar( true );
00429 filterList.append( classHamFilter );
00430 }
00431
00432
00433
00434
00435
00436 KMKernel::self()->filterMgr()->appendFilters( filterList );
00437
00438
00439
00440
00441
00442 if ( !filterList.isEmpty() )
00443 KMKernel::self()->filterMgr()->appendFilters(
00444 filterList, replaceExistingFilters );
00445
00446 QDialog::accept();
00447 }
00448
00449
00450 void AntiSpamWizard::checkProgramsSelections()
00451 {
00452 bool status = false;
00453 bool supportUnsure = false;
00454
00455 mSpamToolsUsed = false;
00456 mVirusToolsUsed = false;
00457 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00458 it != mToolList.end(); ++it ) {
00459 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) )
00460 {
00461 status = true;
00462 if ( (*it).isSpamTool() ) {
00463 mSpamToolsUsed = true;
00464 if ( (*it).hasTristateDetection() )
00465 supportUnsure = true;
00466 }
00467 if ( (*it).isVirusTool() )
00468 mVirusToolsUsed = true;
00469 }
00470 }
00471
00472 if ( mMode == AntiSpam ) {
00473 mSpamRulesPage->allowUnsureFolderSelection( supportUnsure );
00474 slotBuildSummary();
00475 }
00476
00477 if ( ( mMode == AntiVirus ) && mVirusToolsUsed )
00478 checkVirusRulesSelections();
00479
00480 setNextEnabled( mInfoPage, status );
00481 }
00482
00483
00484 void AntiSpamWizard::checkVirusRulesSelections()
00485 {
00486 setFinishEnabled( mVirusRulesPage, anyVirusOptionChecked() );
00487 }
00488
00489
00490 void AntiSpamWizard::checkToolAvailability()
00491 {
00492
00493 KCursorSaver busy( KBusyPtr::busy() );
00494
00495 bool found = false;
00496 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00497 it != mToolList.end(); ++it ) {
00498 QString text( i18n("Scanning for %1...").arg( (*it).getId() ) );
00499 mInfoPage->setScanProgressText( text );
00500 if ( (*it).isSpamTool() && (*it).isServerBased() ) {
00501
00502 QString pattern = (*it).getServerPattern();
00503 kdDebug(5006) << "Testing for server pattern:" << pattern << endl;
00504
00505 AccountManager* mgr = kmkernel->acctMgr();
00506 KMAccount* account = mgr->first();
00507 while ( account ) {
00508 if ( account->type() == "pop" || account->type().contains( "imap" ) ) {
00509 const NetworkAccount * n = dynamic_cast<const NetworkAccount*>( account );
00510 if ( n && n->host().lower().contains( pattern.lower() ) ) {
00511 mInfoPage->addAvailableTool( (*it).getVisibleName() );
00512 found = true;
00513 }
00514 }
00515 account = mgr->next();
00516 }
00517 }
00518 else {
00519
00520 KApplication::kApplication()->processEvents( 200 );
00521 if ( !checkForProgram( (*it).getExecutable() ) ) {
00522 mInfoPage->addAvailableTool( (*it).getVisibleName() );
00523 found = true;
00524 }
00525 }
00526 }
00527 if ( found )
00528 mInfoPage->setScanProgressText( ( mMode == AntiSpam )
00529 ? i18n("Scanning for anti-spam tools finished.")
00530 : i18n("Scanning for anti-virus tools finished.") );
00531 else
00532 mInfoPage->setScanProgressText( ( mMode == AntiSpam )
00533 ? i18n("<p>No spam detection tools have been found. "
00534 "Install your spam detection software and "
00535 "re-run this wizard.</p>")
00536 : i18n("Scanning complete. No anti-virus tools found.") );
00537 }
00538
00539
00540 void AntiSpamWizard::slotHelpClicked()
00541 {
00542 if ( mMode == AntiSpam )
00543 kapp->invokeHelp( "the-anti-spam-wizard", "kmail" );
00544 else
00545 kapp->invokeHelp( "the-anti-virus-wizard", "kmail" );
00546 }
00547
00548
00549 void AntiSpamWizard::slotBuildSummary()
00550 {
00551 QString text;
00552 QString newFilters;
00553 QString replaceFilters;
00554
00555 if ( mMode == AntiVirus ) {
00556 text = "";
00557 }
00558 else {
00559 if ( mSpamRulesPage->markAsReadSelected() )
00560 text = i18n( "<p>Messages classified as spam are marked as read." );
00561 else
00562 text = i18n( "<p>Messages classified as spam are not marked as read." );
00563
00564 if ( mSpamRulesPage->moveSpamSelected() )
00565 text += i18n( "<br>Spam messages are moved into the folder named <i>" )
00566 + mSpamRulesPage->selectedSpamFolderName() + "</i>.</p>";
00567 else
00568 text += i18n( "<br>Spam messages are not moved into a certain folder.</p>" );
00569
00570 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00571 it != mToolList.end(); ++it ) {
00572 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) &&
00573 (*it).isSpamTool() && !(*it).isDetectionOnly() ) {
00574 sortFilterOnExistance( (*it).getFilterName(), newFilters, replaceFilters );
00575 }
00576 }
00577 sortFilterOnExistance( i18n( "Spam handling" ), newFilters, replaceFilters );
00578
00579
00580 if ( mSpamRulesPage->moveUnsureSelected() ) {
00581 bool atLeastOneUnsurePattern = false;
00582 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00583 it != mToolList.end(); ++it ) {
00584 if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) ) {
00585 if ( (*it).isSpamTool() && (*it).hasTristateDetection())
00586 atLeastOneUnsurePattern = true;
00587 }
00588 }
00589 if ( atLeastOneUnsurePattern ) {
00590 sortFilterOnExistance( i18n( "Semi spam (unsure) handling" ),
00591 newFilters, replaceFilters );
00592 text += i18n( "<p>The folder for messages classified as unsure (probably spam) is <i>" )
00593 + mSpamRulesPage->selectedUnsureFolderName() + "</i>.</p>";
00594 }
00595 }
00596
00597
00598 sortFilterOnExistance( i18n( "Classify as spam" ),
00599 newFilters, replaceFilters );
00600 sortFilterOnExistance( i18n( "Classify as NOT spam" ),
00601 newFilters, replaceFilters );
00602
00603
00604 if ( !newFilters.isEmpty() )
00605 text += i18n( "<p>The wizard will create the following filters:<ul>" )
00606 + newFilters + "</ul></p>";
00607 if ( !replaceFilters.isEmpty() )
00608 text += i18n( "<p>The wizard will replace the following filters:<ul>" )
00609 + replaceFilters + "</ul></p>";
00610 }
00611
00612 mSummaryPage->setSummaryText( text );
00613 }
00614
00615
00616 int AntiSpamWizard::checkForProgram( const QString &executable )
00617 {
00618 kdDebug(5006) << "Testing for executable:" << executable << endl;
00619 KProcess process;
00620 process << executable;
00621 process.setUseShell( true );
00622 process.start( KProcess::Block );
00623 return process.exitStatus();
00624 }
00625
00626
00627 bool AntiSpamWizard::anyVirusOptionChecked()
00628 {
00629 return ( mVirusRulesPage->moveRulesSelected()
00630 || mVirusRulesPage->pipeRulesSelected() );
00631 }
00632
00633
00634 const QString AntiSpamWizard::uniqueNameFor( const QString & name )
00635 {
00636 return KMKernel::self()->filterMgr()->createUniqueName( name );
00637 }
00638
00639
00640 void AntiSpamWizard::sortFilterOnExistance(
00641 const QString & intendedFilterName,
00642 QString & newFilters, QString & replaceFilters )
00643 {
00644 if ( uniqueNameFor( intendedFilterName ) == intendedFilterName )
00645 newFilters += "<li>" + intendedFilterName + "</li>";
00646 else
00647 replaceFilters += "<li>" + intendedFilterName + "</li>";
00648 }
00649
00650
00651
00652 AntiSpamWizard::SpamToolConfig::SpamToolConfig( QString toolId,
00653 int configVersion, int prio, QString name, QString exec,
00654 QString url, QString filter, QString detection, QString spam, QString ham,
00655 QString header, QString pattern, QString pattern2, QString serverPattern,
00656 bool detectionOnly, bool regExp, bool bayesFilter, bool tristateDetection,
00657 WizardMode type )
00658 : mId( toolId ), mVersion( configVersion ), mPrio( prio ),
00659 mVisibleName( name ), mExecutable( exec ), mWhatsThisText( url ),
00660 mFilterName( filter ), mDetectCmd( detection ), mSpamCmd( spam ),
00661 mHamCmd( ham ), mDetectionHeader( header ), mDetectionPattern( pattern ),
00662 mDetectionPattern2( pattern2 ), mServerPattern( serverPattern ),
00663 mDetectionOnly( detectionOnly ),
00664 mUseRegExp( regExp ), mSupportsBayesFilter( bayesFilter ),
00665 mSupportsUnsure( tristateDetection ), mType( type )
00666 {
00667 }
00668
00669
00670 bool AntiSpamWizard::SpamToolConfig::isServerBased() const
00671 {
00672 return !mServerPattern.isEmpty();
00673 }
00674
00675
00676
00677 AntiSpamWizard::ConfigReader::ConfigReader( WizardMode mode,
00678 QValueList<SpamToolConfig> & configList )
00679 : mToolList( configList ),
00680 mMode( mode )
00681 {
00682 if ( mMode == AntiSpam )
00683 mConfig = new KConfig( "kmail.antispamrc", true );
00684 else
00685 mConfig = new KConfig( "kmail.antivirusrc", true );
00686 }
00687
00688 AntiSpamWizard::ConfigReader::~ConfigReader( )
00689 {
00690 delete mConfig;
00691 }
00692
00693
00694 void AntiSpamWizard::ConfigReader::readAndMergeConfig()
00695 {
00696 QString groupName = ( mMode == AntiSpam )
00697 ? QString("Spamtool #%1")
00698 : QString("Virustool #%1");
00699
00700 mConfig->setReadDefaults( true );
00701 KConfigGroup general( mConfig, "General" );
00702 int registeredTools = general.readNumEntry( "tools", 0 );
00703 for (int i = 1; i <= registeredTools; i++)
00704 {
00705 KConfigGroup toolConfig( mConfig, groupName.arg( i ) );
00706 if( !toolConfig.readBoolEntry( "HeadersOnly", false ) )
00707 mToolList.append( readToolConfig( toolConfig ) );
00708 }
00709
00710
00711
00712 mConfig->setReadDefaults( false );
00713 KConfigGroup user_general( mConfig, "General" );
00714 int user_registeredTools = user_general.readNumEntry( "tools", 0 );
00715 for (int i = 1; i <= user_registeredTools; i++)
00716 {
00717 KConfigGroup toolConfig( mConfig, groupName.arg( i ) );
00718 if( !toolConfig.readBoolEntry( "HeadersOnly", false ) )
00719 mergeToolConfig( readToolConfig( toolConfig ) );
00720 }
00721
00722
00723
00724 if ( mMode == AntiSpam ) {
00725 if ( registeredTools < 1 && user_registeredTools < 1 )
00726 mToolList.append( createDummyConfig() );
00727 sortToolList();
00728 }
00729 }
00730
00731
00732 AntiSpamWizard::SpamToolConfig
00733 AntiSpamWizard::ConfigReader::readToolConfig( KConfigGroup & configGroup )
00734 {
00735 QString id = configGroup.readEntry( "Ident" );
00736 int version = configGroup.readNumEntry( "Version" );
00737 #ifndef NDEBUG
00738 kdDebug(5006) << "Found predefined tool: " << id << endl;
00739 kdDebug(5006) << "With config version : " << version << endl;
00740 #endif
00741 int prio = configGroup.readNumEntry( "Priority", 1 );
00742 QString name = configGroup.readEntry( "VisibleName" );
00743 QString executable = configGroup.readEntry( "Executable" );
00744 QString url = configGroup.readEntry( "URL" );
00745 QString filterName = configGroup.readEntry( "PipeFilterName" );
00746 QString detectCmd = configGroup.readEntry( "PipeCmdDetect" );
00747 QString spamCmd = configGroup.readEntry( "ExecCmdSpam" );
00748 QString hamCmd = configGroup.readEntry( "ExecCmdHam" );
00749 QString header = configGroup.readEntry( "DetectionHeader" );
00750 QString pattern = configGroup.readEntry( "DetectionPattern" );
00751 QString pattern2 = configGroup.readEntry( "DetectionPattern2" );
00752 QString serverPattern = configGroup.readEntry( "ServerPattern" );
00753 bool detectionOnly = configGroup.readBoolEntry( "DetectionOnly", false );
00754 bool useRegExp = configGroup.readBoolEntry( "UseRegExp" );
00755 bool supportsBayes = configGroup.readBoolEntry( "SupportsBayes", false );
00756 bool supportsUnsure = configGroup.readBoolEntry( "SupportsUnsure", false );
00757 return SpamToolConfig( id, version, prio, name, executable, url,
00758 filterName, detectCmd, spamCmd, hamCmd,
00759 header, pattern, pattern2, serverPattern,
00760 detectionOnly, useRegExp,
00761 supportsBayes, supportsUnsure, mMode );
00762 }
00763
00764
00765 AntiSpamWizard::SpamToolConfig AntiSpamWizard::ConfigReader::createDummyConfig()
00766 {
00767 return SpamToolConfig( "spamassassin", 0, 1,
00768 "SpamAssassin", "spamassassin -V",
00769 "http://spamassassin.org", "SpamAssassin Check",
00770 "spamassassin -L",
00771 "sa-learn -L --spam --no-rebuild --single",
00772 "sa-learn -L --ham --no-rebuild --single",
00773 "X-Spam-Flag", "yes", "", "",
00774 false, false, true, false, AntiSpam );
00775 }
00776
00777
00778 void AntiSpamWizard::ConfigReader::mergeToolConfig( AntiSpamWizard::SpamToolConfig config )
00779 {
00780 bool found = false;
00781 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00782 it != mToolList.end(); ++it ) {
00783 #ifndef NDEBUG
00784 kdDebug(5006) << "Check against tool: " << (*it).getId() << endl;
00785 kdDebug(5006) << "Against version : " << (*it).getVersion() << endl;
00786 #endif
00787 if ( (*it).getId() == config.getId() )
00788 {
00789 found = true;
00790 if ( (*it).getVersion() < config.getVersion() )
00791 {
00792 #ifndef NDEBUG
00793 kdDebug(5006) << "Replacing config ..." << endl;
00794 #endif
00795 mToolList.remove( it );
00796 mToolList.append( config );
00797 }
00798 break;
00799 }
00800 }
00801 if ( !found )
00802 mToolList.append( config );
00803 }
00804
00805
00806 void AntiSpamWizard::ConfigReader::sortToolList()
00807 {
00808 QValueList<SpamToolConfig> tmpList;
00809 SpamToolConfig config;
00810
00811 while ( !mToolList.isEmpty() ) {
00812 QValueListIterator<SpamToolConfig> highest;
00813 int priority = 0;
00814 for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
00815 it != mToolList.end(); ++it ) {
00816 if ( (*it).getPrio() > priority ) {
00817 priority = (*it).getPrio();
00818 highest = it;
00819 }
00820 }
00821 config = (*highest);
00822 tmpList.append( config );
00823 mToolList.remove( highest );
00824 }
00825 for ( QValueListIterator<SpamToolConfig> it = tmpList.begin();
00826 it != tmpList.end(); ++it ) {
00827 mToolList.append( (*it) );
00828 }
00829 }
00830
00831
00832
00833 ASWizPage::ASWizPage( QWidget * parent, const char * name,
00834 const QString *bannerName )
00835 : QWidget( parent, name )
00836 {
00837 QString banner = "kmwizard.png";
00838 if ( bannerName && !bannerName->isEmpty() )
00839 banner = *bannerName;
00840
00841 mLayout = new QHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
00842 mBannerLabel = new QLabel( this );
00843 mBannerLabel->setPixmap( UserIcon(banner) );
00844 mBannerLabel->setScaledContents( false );
00845 mBannerLabel->setFrameShape( QFrame::StyledPanel );
00846 mBannerLabel->setFrameShadow( QFrame::Sunken );
00847
00848 mLayout->addWidget( mBannerLabel );
00849 mLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
00850 }
00851
00852
00853
00854 ASWizInfoPage::ASWizInfoPage( AntiSpamWizard::WizardMode mode,
00855 QWidget * parent, const char * name )
00856 : ASWizPage( parent, name )
00857 {
00858 QBoxLayout * layout = new QVBoxLayout( mLayout );
00859
00860 mIntroText = new QLabel( this );
00861 mIntroText->setText(
00862 ( mode == AntiSpamWizard::AntiSpam )
00863 ? i18n(
00864 "The wizard will search for any tools to do spam detection\n"
00865 "and setup KMail to work with them."
00866 )
00867 : i18n(
00868 "<p>Here you can get some assistance in setting up KMail's filter "
00869 "rules to use some commonly-known anti-virus tools.</p>"
00870 "<p>The wizard can detect those tools on your computer as "
00871 "well as create filter rules to classify messages using these "
00872 "tools and to separate messages containing viruses. "
00873 "The wizard will not take any existing filter "
00874 "rules into consideration: it will always append the new rules.</p>"
00875 "<p><b>Warning:</b> As KMail appears to be frozen during the scan of the "
00876 "messages for viruses, you may encounter problems with "
00877 "the responsiveness of KMail because anti-virus tool "
00878 "operations are usually time consuming; please consider "
00879 "deleting the filter rules created by the wizard to get "
00880 "back to the former behavior."
00881 ) );
00882 layout->addWidget( mIntroText );
00883
00884 mScanProgressText = new QLabel( this );
00885 mScanProgressText->setText( "" ) ;
00886 layout->addWidget( mScanProgressText );
00887
00888 mToolsList = new KListBox( this );
00889 mToolsList->hide();
00890 mToolsList->setSelectionMode( QListBox::Multi );
00891 mToolsList->setRowMode( QListBox::FixedNumber );
00892 mToolsList->setRowMode( 10 );
00893 layout->addWidget( mToolsList );
00894 connect( mToolsList, SIGNAL(selectionChanged()),
00895 this, SLOT(processSelectionChange(void)) );
00896
00897 mSelectionHint = new QLabel( this );
00898 mSelectionHint->setText( "" );
00899 layout->addWidget( mSelectionHint );
00900
00901 layout->addStretch();
00902 }
00903
00904
00905 void ASWizInfoPage::setScanProgressText( const QString &toolName )
00906 {
00907 mScanProgressText->setText( toolName );
00908 }
00909
00910
00911 void ASWizInfoPage::addAvailableTool( const QString &visibleName )
00912 {
00913 QString listName = visibleName;
00914 mToolsList->insertItem( listName );
00915 if ( !mToolsList->isVisible() )
00916 {
00917 mToolsList->show();
00918 mToolsList->setSelected( 0, true );
00919 mSelectionHint->setText( i18n("<p>Please select the tools to be used "
00920 "for the detection and go "
00921 "to the next page.</p>") );
00922 }
00923 }
00924
00925 bool ASWizInfoPage::isProgramSelected( const QString &visibleName )
00926 {
00927 QString listName = visibleName;
00928 return mToolsList->isSelected( mToolsList->findItem( listName ) );
00929 }
00930
00931
00932 void ASWizInfoPage::processSelectionChange()
00933 {
00934 emit selectionChanged();
00935 }
00936
00937
00938
00939 ASWizSpamRulesPage::ASWizSpamRulesPage( QWidget * parent, const char * name,
00940 KMFolderTree * mainFolderTree )
00941 : ASWizPage( parent, name )
00942 {
00943 QVBoxLayout *layout = new QVBoxLayout( mLayout );
00944
00945 mMarkRules = new QCheckBox( i18n("&Mark detected spam messages as read"), this );
00946 QWhatsThis::add( mMarkRules,
00947 i18n( "Mark messages which have been classified as spam as read.") );
00948 layout->addWidget( mMarkRules);
00949
00950 mMoveSpamRules = new QCheckBox( i18n("Move &known spam to:"), this );
00951 QWhatsThis::add( mMoveSpamRules,
00952 i18n( "The default folder for spam messages is the trash folder, "
00953 "but you may change that in the folder view below.") );
00954 layout->addWidget( mMoveSpamRules );
00955
00956 mFolderReqForSpamFolder = new FolderRequester( this, mainFolderTree );
00957 mFolderReqForSpamFolder->setFolder( "trash" );
00958 mFolderReqForSpamFolder->setMustBeReadWrite( true );
00959 mFolderReqForSpamFolder->setShowOutbox( false );
00960 mFolderReqForSpamFolder->setShowImapFolders( false );
00961
00962 QHBoxLayout *hLayout1 = new QHBoxLayout( layout );
00963 hLayout1->addSpacing( KDialog::spacingHint() * 3 );
00964 hLayout1->addWidget( mFolderReqForSpamFolder );
00965
00966 mMoveUnsureRules = new QCheckBox( i18n("Move &probable spam to:"), this );
00967 QWhatsThis::add( mMoveUnsureRules,
00968 i18n( "The default folder is the inbox folder, but you may change that "
00969 "in the folder view below.<p>"
00970 "Not all tools support a classification as unsure. If you haven't "
00971 "selected a capable tool, you can't select a folder as well.") );
00972 layout->addWidget( mMoveUnsureRules );
00973
00974 mFolderReqForUnsureFolder = new FolderRequester( this, mainFolderTree );
00975 mFolderReqForUnsureFolder->setFolder( "inbox" );
00976 mFolderReqForUnsureFolder->setMustBeReadWrite( true );
00977 mFolderReqForUnsureFolder->setShowOutbox( false );
00978 mFolderReqForUnsureFolder->setShowImapFolders( false );
00979
00980 QHBoxLayout *hLayout2 = new QHBoxLayout( layout );
00981 hLayout2->addSpacing( KDialog::spacingHint() * 3 );
00982 hLayout2->addWidget( mFolderReqForUnsureFolder );
00983
00984 layout->addStretch();
00985
00986 connect( mMarkRules, SIGNAL(clicked()),
00987 this, SLOT(processSelectionChange(void)) );
00988 connect( mMoveSpamRules, SIGNAL(clicked()),
00989 this, SLOT(processSelectionChange(void)) );
00990 connect( mMoveUnsureRules, SIGNAL(clicked()),
00991 this, SLOT(processSelectionChange(void)) );
00992 connect( mFolderReqForSpamFolder, SIGNAL(folderChanged(KMFolder*)),
00993 this, SLOT(processSelectionChange(KMFolder*)) );
00994 connect( mFolderReqForUnsureFolder, SIGNAL(folderChanged(KMFolder*)),
00995 this, SLOT(processSelectionChange(KMFolder*)) );
00996
00997 mMarkRules->setChecked( true );
00998 mMoveSpamRules->setChecked( true );
00999 }
01000
01001
01002 bool ASWizSpamRulesPage::markAsReadSelected() const
01003 {
01004 return mMarkRules->isChecked();
01005 }
01006
01007
01008 bool ASWizSpamRulesPage::moveSpamSelected() const
01009 {
01010 return mMoveSpamRules->isChecked();
01011 }
01012
01013
01014 bool ASWizSpamRulesPage::moveUnsureSelected() const
01015 {
01016 return mMoveUnsureRules->isChecked();
01017 }
01018
01019
01020 QString ASWizSpamRulesPage::selectedSpamFolderName() const
01021 {
01022 QString name = "trash";
01023 if ( mFolderReqForSpamFolder->folder() )
01024 name = mFolderReqForSpamFolder->folder()->idString();
01025 return name;
01026 }
01027
01028
01029 QString ASWizSpamRulesPage::selectedUnsureFolderName() const
01030 {
01031 QString name = "inbox";
01032 if ( mFolderReqForUnsureFolder->folder() )
01033 name = mFolderReqForUnsureFolder->folder()->idString();
01034 return name;
01035 }
01036
01037
01038 void ASWizSpamRulesPage::processSelectionChange()
01039 {
01040 mFolderReqForSpamFolder->setEnabled( mMoveSpamRules->isChecked() );
01041 mFolderReqForUnsureFolder->setEnabled( mMoveUnsureRules->isChecked() );
01042 emit selectionChanged();
01043 }
01044
01045
01046 void ASWizSpamRulesPage::processSelectionChange( KMFolder* )
01047 {
01048 processSelectionChange();
01049 }
01050
01051
01052 void ASWizSpamRulesPage::allowUnsureFolderSelection( bool enabled )
01053 {
01054 mMoveUnsureRules->setEnabled( enabled );
01055 mMoveUnsureRules->setShown( enabled );
01056 mFolderReqForUnsureFolder->setEnabled( enabled );
01057 mFolderReqForUnsureFolder->setShown( enabled );
01058 }
01059
01060
01061
01062 ASWizVirusRulesPage::ASWizVirusRulesPage( QWidget * parent, const char * name,
01063 KMFolderTree * mainFolderTree )
01064 : ASWizPage( parent, name )
01065 {
01066 QGridLayout *grid = new QGridLayout( mLayout, 5, 1, KDialog::spacingHint() );
01067
01068 mPipeRules = new QCheckBox( i18n("Check messages using the anti-virus tools"), this );
01069 QWhatsThis::add( mPipeRules,
01070 i18n( "Let the anti-virus tools check your messages. The wizard "
01071 "will create appropriate filters. The messages are usually "
01072 "marked by the tools so that following filters can react "
01073 "on this and, for example, move virus messages to a special folder.") );
01074 grid->addWidget( mPipeRules, 0, 0 );
01075
01076 mMoveRules = new QCheckBox( i18n("Move detected viral messages to the selected folder"), this );
01077 QWhatsThis::add( mMoveRules,
01078 i18n( "A filter to detect messages classified as virus-infected and to move "
01079 "those messages into a predefined folder is created. The "
01080 "default folder is the trash folder, but you may change that "
01081 "in the folder view.") );
01082 grid->addWidget( mMoveRules, 1, 0 );
01083
01084 mMarkRules = new QCheckBox( i18n("Additionally, mark detected viral messages as read"), this );
01085 mMarkRules->setEnabled( false );
01086 QWhatsThis::add( mMarkRules,
01087 i18n( "Mark messages which have been classified as "
01088 "virus-infected as read, as well as moving them "
01089 "to the selected folder.") );
01090 grid->addWidget( mMarkRules, 2, 0 );
01091
01092 QString s = "trash";
01093 mFolderTree = new SimpleFolderTree( this, mainFolderTree, s, true );
01094 grid->addWidget( mFolderTree, 3, 0 );
01095
01096 connect( mPipeRules, SIGNAL(clicked()),
01097 this, SLOT(processSelectionChange(void)) );
01098 connect( mMoveRules, SIGNAL(clicked()),
01099 this, SLOT(processSelectionChange(void)) );
01100 connect( mMarkRules, SIGNAL(clicked()),
01101 this, SLOT(processSelectionChange(void)) );
01102 connect( mMoveRules, SIGNAL( toggled( bool ) ),
01103 mMarkRules, SLOT( setEnabled( bool ) ) );
01104 }
01105
01106 bool ASWizVirusRulesPage::pipeRulesSelected() const
01107 {
01108 return mPipeRules->isChecked();
01109 }
01110
01111
01112 bool ASWizVirusRulesPage::moveRulesSelected() const
01113 {
01114 return mMoveRules->isChecked();
01115 }
01116
01117 bool ASWizVirusRulesPage::markReadRulesSelected() const
01118 {
01119 return mMarkRules->isChecked();
01120 }
01121
01122
01123 QString ASWizVirusRulesPage::selectedFolderName() const
01124 {
01125 QString name = "trash";
01126 if ( mFolderTree->folder() )
01127 name = mFolderTree->folder()->idString();
01128 return name;
01129 }
01130
01131 void ASWizVirusRulesPage::processSelectionChange()
01132 {
01133 emit selectionChanged();
01134 }
01135
01136
01137
01138 ASWizSummaryPage::ASWizSummaryPage( QWidget * parent, const char * name )
01139 : ASWizPage( parent, name )
01140 {
01141 QBoxLayout * layout = new QVBoxLayout( mLayout );
01142
01143 mSummaryText = new QLabel( this );
01144 layout->addWidget( mSummaryText );
01145 layout->addStretch();
01146 }
01147
01148
01149 void ASWizSummaryPage::setSummaryText( const QString & text )
01150 {
01151 mSummaryText->setText( text );
01152 }
01153
01154
01155 #include "antispamwizard.moc"