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