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 mPixmap = new QPixmap( UserIcon(banner) );
00843 mBannerLabel = new QLabel( this );
00844 mBannerLabel->setPixmap( *mPixmap );
00845 mBannerLabel->setScaledContents( false );
00846 mBannerLabel->setFrameShape( QFrame::StyledPanel );
00847 mBannerLabel->setFrameShadow( QFrame::Sunken );
00848
00849 mLayout->addWidget( mBannerLabel );
00850 mLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
00851 }
00852
00853
00854
00855 ASWizInfoPage::ASWizInfoPage( AntiSpamWizard::WizardMode mode,
00856 QWidget * parent, const char * name )
00857 : ASWizPage( parent, name )
00858 {
00859 QBoxLayout * layout = new QVBoxLayout( mLayout );
00860
00861 mIntroText = new QLabel( this );
00862 mIntroText->setText(
00863 ( mode == AntiSpamWizard::AntiSpam )
00864 ? i18n(
00865 "The wizard will search for any tools to do spam detection\n"
00866 "and setup KMail to work with them."
00867 )
00868 : i18n(
00869 "<p>Here you can get some assistance in setting up KMail's filter "
00870 "rules to use some commonly-known anti-virus tools.</p>"
00871 "<p>The wizard can detect those tools on your computer as "
00872 "well as create filter rules to classify messages using these "
00873 "tools and to separate messages containing viruses. "
00874 "The wizard will not take any existing filter "
00875 "rules into consideration: it will always append the new rules.</p>"
00876 "<p><b>Warning:</b> As KMail appears to be frozen during the scan of the "
00877 "messages for viruses, you may encounter problems with "
00878 "the responsiveness of KMail because anti-virus tool "
00879 "operations are usually time consuming; please consider "
00880 "deleting the filter rules created by the wizard to get "
00881 "back to the former behavior."
00882 ) );
00883 layout->addWidget( mIntroText );
00884
00885 mScanProgressText = new QLabel( this );
00886 mScanProgressText->setText( "" ) ;
00887 layout->addWidget( mScanProgressText );
00888
00889 mToolsList = new KListBox( this );
00890 mToolsList->hide();
00891 mToolsList->setSelectionMode( QListBox::Multi );
00892 mToolsList->setRowMode( QListBox::FixedNumber );
00893 mToolsList->setRowMode( 10 );
00894 layout->addWidget( mToolsList );
00895 connect( mToolsList, SIGNAL(selectionChanged()),
00896 this, SLOT(processSelectionChange(void)) );
00897
00898 mSelectionHint = new QLabel( this );
00899 mSelectionHint->setText( "" );
00900 layout->addWidget( mSelectionHint );
00901
00902 layout->addStretch();
00903 }
00904
00905
00906 void ASWizInfoPage::setScanProgressText( const QString &toolName )
00907 {
00908 mScanProgressText->setText( toolName );
00909 }
00910
00911
00912 void ASWizInfoPage::addAvailableTool( const QString &visibleName )
00913 {
00914 QString listName = visibleName;
00915 mToolsList->insertItem( listName );
00916 if ( !mToolsList->isVisible() )
00917 {
00918 mToolsList->show();
00919 mToolsList->setSelected( 0, true );
00920 mSelectionHint->setText( i18n("<p>Please select the tools to be used "
00921 "for the detection and go "
00922 "to the next page.</p>") );
00923 }
00924 }
00925
00926 bool ASWizInfoPage::isProgramSelected( const QString &visibleName )
00927 {
00928 QString listName = visibleName;
00929 return mToolsList->isSelected( mToolsList->findItem( listName ) );
00930 }
00931
00932
00933 void ASWizInfoPage::processSelectionChange()
00934 {
00935 emit selectionChanged();
00936 }
00937
00938
00939
00940 ASWizSpamRulesPage::ASWizSpamRulesPage( QWidget * parent, const char * name,
00941 KMFolderTree * mainFolderTree )
00942 : ASWizPage( parent, name )
00943 {
00944 QVBoxLayout *layout = new QVBoxLayout( mLayout );
00945
00946 mMarkRules = new QCheckBox( i18n("&Mark detected spam messages as read"), this );
00947 QWhatsThis::add( mMarkRules,
00948 i18n( "Mark messages which have been classified as spam as read.") );
00949 layout->addWidget( mMarkRules);
00950
00951 mMoveSpamRules = new QCheckBox( i18n("Move &known spam to:"), this );
00952 QWhatsThis::add( mMoveSpamRules,
00953 i18n( "The default folder for spam messages is the trash folder, "
00954 "but you may change that in the folder view below.") );
00955 layout->addWidget( mMoveSpamRules );
00956
00957 mFolderReqForSpamFolder = new FolderRequester( this, mainFolderTree );
00958 mFolderReqForSpamFolder->setFolder( "trash" );
00959 mFolderReqForSpamFolder->setMustBeReadWrite( true );
00960 mFolderReqForSpamFolder->setShowOutbox( false );
00961 mFolderReqForSpamFolder->setShowImapFolders( false );
00962
00963 QHBoxLayout *hLayout1 = new QHBoxLayout( layout );
00964 hLayout1->addSpacing( KDialog::spacingHint() * 3 );
00965 hLayout1->addWidget( mFolderReqForSpamFolder );
00966
00967 mMoveUnsureRules = new QCheckBox( i18n("Move &probable spam to:"), this );
00968 QWhatsThis::add( mMoveUnsureRules,
00969 i18n( "The default folder is the inbox folder, but you may change that "
00970 "in the folder view below.<p>"
00971 "Not all tools support a classification as unsure. If you haven't "
00972 "selected a capable tool, you can't select a folder as well.") );
00973 layout->addWidget( mMoveUnsureRules );
00974
00975 mFolderReqForUnsureFolder = new FolderRequester( this, mainFolderTree );
00976 mFolderReqForUnsureFolder->setFolder( "inbox" );
00977 mFolderReqForUnsureFolder->setMustBeReadWrite( true );
00978 mFolderReqForUnsureFolder->setShowOutbox( false );
00979 mFolderReqForUnsureFolder->setShowImapFolders( false );
00980
00981 QHBoxLayout *hLayout2 = new QHBoxLayout( layout );
00982 hLayout2->addSpacing( KDialog::spacingHint() * 3 );
00983 hLayout2->addWidget( mFolderReqForUnsureFolder );
00984
00985 layout->addStretch();
00986
00987 connect( mMarkRules, SIGNAL(clicked()),
00988 this, SLOT(processSelectionChange(void)) );
00989 connect( mMoveSpamRules, SIGNAL(clicked()),
00990 this, SLOT(processSelectionChange(void)) );
00991 connect( mMoveUnsureRules, SIGNAL(clicked()),
00992 this, SLOT(processSelectionChange(void)) );
00993 connect( mFolderReqForSpamFolder, SIGNAL(folderChanged(KMFolder*)),
00994 this, SLOT(processSelectionChange(KMFolder*)) );
00995 connect( mFolderReqForUnsureFolder, SIGNAL(folderChanged(KMFolder*)),
00996 this, SLOT(processSelectionChange(KMFolder*)) );
00997
00998 mMarkRules->setChecked( true );
00999 mMoveSpamRules->setChecked( true );
01000 }
01001
01002
01003 bool ASWizSpamRulesPage::markAsReadSelected() const
01004 {
01005 return mMarkRules->isChecked();
01006 }
01007
01008
01009 bool ASWizSpamRulesPage::moveSpamSelected() const
01010 {
01011 return mMoveSpamRules->isChecked();
01012 }
01013
01014
01015 bool ASWizSpamRulesPage::moveUnsureSelected() const
01016 {
01017 return mMoveUnsureRules->isChecked();
01018 }
01019
01020
01021 QString ASWizSpamRulesPage::selectedSpamFolderName() const
01022 {
01023 QString name = "trash";
01024 if ( mFolderReqForSpamFolder->folder() )
01025 name = mFolderReqForSpamFolder->folder()->idString();
01026 return name;
01027 }
01028
01029
01030 QString ASWizSpamRulesPage::selectedUnsureFolderName() const
01031 {
01032 QString name = "inbox";
01033 if ( mFolderReqForUnsureFolder->folder() )
01034 name = mFolderReqForUnsureFolder->folder()->idString();
01035 return name;
01036 }
01037
01038
01039 void ASWizSpamRulesPage::processSelectionChange()
01040 {
01041 mFolderReqForSpamFolder->setEnabled( mMoveSpamRules->isChecked() );
01042 mFolderReqForUnsureFolder->setEnabled( mMoveUnsureRules->isChecked() );
01043 emit selectionChanged();
01044 }
01045
01046
01047 void ASWizSpamRulesPage::processSelectionChange( KMFolder* )
01048 {
01049 processSelectionChange();
01050 }
01051
01052
01053 void ASWizSpamRulesPage::allowUnsureFolderSelection( bool enabled )
01054 {
01055 mMoveUnsureRules->setEnabled( enabled );
01056 mMoveUnsureRules->setShown( enabled );
01057 mFolderReqForUnsureFolder->setEnabled( enabled );
01058 mFolderReqForUnsureFolder->setShown( enabled );
01059 }
01060
01061
01062
01063 ASWizVirusRulesPage::ASWizVirusRulesPage( QWidget * parent, const char * name,
01064 KMFolderTree * mainFolderTree )
01065 : ASWizPage( parent, name )
01066 {
01067 QGridLayout *grid = new QGridLayout( mLayout, 5, 1, KDialog::spacingHint() );
01068
01069 mPipeRules = new QCheckBox( i18n("Check messages using the anti-virus tools"), this );
01070 QWhatsThis::add( mPipeRules,
01071 i18n( "Let the anti-virus tools check your messages. The wizard "
01072 "will create appropriate filters. The messages are usually "
01073 "marked by the tools so that following filters can react "
01074 "on this and, for example, move virus messages to a special folder.") );
01075 grid->addWidget( mPipeRules, 0, 0 );
01076
01077 mMoveRules = new QCheckBox( i18n("Move detected viral messages to the selected folder"), this );
01078 QWhatsThis::add( mMoveRules,
01079 i18n( "A filter to detect messages classified as virus-infected and to move "
01080 "those messages into a predefined folder is created. The "
01081 "default folder is the trash folder, but you may change that "
01082 "in the folder view.") );
01083 grid->addWidget( mMoveRules, 1, 0 );
01084
01085 mMarkRules = new QCheckBox( i18n("Additionally, mark detected viral messages as read"), this );
01086 mMarkRules->setEnabled( false );
01087 QWhatsThis::add( mMarkRules,
01088 i18n( "Mark messages which have been classified as "
01089 "virus-infected as read, as well as moving them "
01090 "to the selected folder.") );
01091 grid->addWidget( mMarkRules, 2, 0 );
01092
01093 QString s = "trash";
01094 mFolderTree = new SimpleFolderTree( this, mainFolderTree, s, true );
01095 grid->addWidget( mFolderTree, 3, 0 );
01096
01097 connect( mPipeRules, SIGNAL(clicked()),
01098 this, SLOT(processSelectionChange(void)) );
01099 connect( mMoveRules, SIGNAL(clicked()),
01100 this, SLOT(processSelectionChange(void)) );
01101 connect( mMarkRules, SIGNAL(clicked()),
01102 this, SLOT(processSelectionChange(void)) );
01103 connect( mMoveRules, SIGNAL( toggled( bool ) ),
01104 mMarkRules, SLOT( setEnabled( bool ) ) );
01105 }
01106
01107 bool ASWizVirusRulesPage::pipeRulesSelected() const
01108 {
01109 return mPipeRules->isChecked();
01110 }
01111
01112
01113 bool ASWizVirusRulesPage::moveRulesSelected() const
01114 {
01115 return mMoveRules->isChecked();
01116 }
01117
01118 bool ASWizVirusRulesPage::markReadRulesSelected() const
01119 {
01120 return mMarkRules->isChecked();
01121 }
01122
01123
01124 QString ASWizVirusRulesPage::selectedFolderName() const
01125 {
01126 QString name = "trash";
01127 if ( mFolderTree->folder() )
01128 name = mFolderTree->folder()->idString();
01129 return name;
01130 }
01131
01132 void ASWizVirusRulesPage::processSelectionChange()
01133 {
01134 emit selectionChanged();
01135 }
01136
01137
01138
01139 ASWizSummaryPage::ASWizSummaryPage( QWidget * parent, const char * name )
01140 : ASWizPage( parent, name )
01141 {
01142 QBoxLayout * layout = new QVBoxLayout( mLayout );
01143
01144 mSummaryText = new QLabel( this );
01145 layout->addWidget( mSummaryText );
01146 layout->addStretch();
01147 }
01148
01149
01150 void ASWizSummaryPage::setSummaryText( const QString & text )
01151 {
01152 mSummaryText->setText( text );
01153 }
01154
01155
01156 #include "antispamwizard.moc"