2 This file is part of KMail.
3 Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de>
5 KMail is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License, version 2, as
7 published by the Free Software Foundation.
9 KMail is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 In addition, as a special exception, the copyright holders give
19 permission to link the code of this program with any edition of
20 the Qt library by Trolltech AS, Norway (or with modified versions
21 of Qt that use the same license as Qt), and distribute linked
22 combinations including the two. You must obey the GNU General
23 Public License in all respects for all of the code used other than
24 Qt. If you modify this file, you may extend this exception to
25 your version of the file, but you are not obligated to do so. If
26 you do not wish to do so, delete this exception statement from
31 #include "antispamwizard.h"
32 #include "kcursorsaver.h"
33 #include "accountmanager.h"
35 #include "kmfilteraction.h"
36 #include "kmfiltermgr.h"
38 #include "folderselectiontreewidget.h"
39 #include "kmmainwin.h"
40 #include "networkaccount.h"
41 #include "folderrequester.h"
46 #include <kiconloader.h>
48 #include <kmessagebox.h>
50 #include <ktoolinvocation.h>
51 #include <kconfiggroup.h>
53 #include <QApplication>
62 #include <QGridLayout>
63 #include <QHBoxLayout>
65 #include <QVBoxLayout>
67 using namespace KMail
;
69 AntiSpamWizard::AntiSpamWizard( WizardMode mode
,
70 QWidget
* parent
, MainFolderView
* mainFolderTree
)
71 : KAssistantDialog( parent
),
78 // read the configuration for the anti-spam tools
79 ConfigReader
reader( mMode
, mToolList
);
80 reader
.readAndMergeConfig();
81 mToolList
= reader
.getToolList();
84 if ( mMode
== AntiSpam
)
85 kDebug(5006) << endl
<<"Considered anti-spam tools:";
87 kDebug(5006) << endl
<<"Considered anti-virus tools:";
89 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
90 it
!= mToolList
.end(); ++it
) {
92 kDebug(5006) <<"Predefined tool:" << (*it
).getId();
93 kDebug(5006) <<"Config version:" << (*it
).getVersion();
94 kDebug(5006) <<"Selection priority:" << (*it
).getPrio();
95 kDebug(5006) <<"Displayed name:" << (*it
).getVisibleName();
96 kDebug(5006) <<"Executable:" << (*it
).getExecutable();
97 kDebug(5006) <<"WhatsThis URL:" << (*it
).getWhatsThisText();
98 kDebug(5006) <<"Filter name:" << (*it
).getFilterName();
99 kDebug(5006) <<"Detection command:" << (*it
).getDetectCmd();
100 kDebug(5006) <<"Learn spam command:" << (*it
).getSpamCmd();
101 kDebug(5006) <<"Learn ham command:" << (*it
).getHamCmd();
102 kDebug(5006) <<"Detection header:" << (*it
).getDetectionHeader();
103 kDebug(5006) <<"Detection pattern:" << (*it
).getDetectionPattern();
104 kDebug(5006) <<"Use as RegExp:" << (*it
).isUseRegExp();
105 kDebug(5006) <<"Supports Bayes Filter:" << (*it
).useBayesFilter();
106 kDebug(5006) <<"Type:" << (*it
).getType();
110 setWindowTitle( ( mMode
== AntiSpam
) ? i18n( "Anti-Spam Wizard" )
111 : i18n( "Anti-Virus Wizard" ) );
112 mInfoPage
= new ASWizInfoPage( mMode
, 0, "" );
114 ( mMode
== AntiSpam
)
115 ? i18n( "Welcome to the KMail Anti-Spam Wizard" )
116 : i18n( "Welcome to the KMail Anti-Virus Wizard" ) );
117 connect( mInfoPage
, SIGNAL( selectionChanged( void ) ),
118 this, SLOT( checkProgramsSelections( void ) ) );
120 if ( mMode
== AntiSpam
) {
121 mSpamRulesPage
= new ASWizSpamRulesPage( 0, "", mainFolderTree
);
122 addPage( mSpamRulesPage
, i18n( "Options to fine-tune the handling of spam messages" ));
123 connect( mSpamRulesPage
, SIGNAL( selectionChanged( void ) ),
124 this, SLOT( slotBuildSummary( void ) ) );
127 mVirusRulesPage
= new ASWizVirusRulesPage( 0, "", mainFolderTree
);
128 addPage( mVirusRulesPage
, i18n( "Options to fine-tune the handling of virus messages" ));
129 connect( mVirusRulesPage
, SIGNAL( selectionChanged( void ) ),
130 this, SLOT( checkVirusRulesSelections( void ) ) );
133 connect( this, SIGNAL( helpClicked( void) ),
134 this, SLOT( slotHelpClicked( void ) ) );
136 if ( mMode
== AntiSpam
) {
137 mSummaryPage
= new ASWizSummaryPage( 0, "" );
138 addPage( mSummaryPage
, i18n( "Summary of changes to be made by this wizard" ) );
141 QTimer::singleShot( 0, this, SLOT( checkToolAvailability( void ) ) );
145 void AntiSpamWizard::accept()
147 if ( mSpamRulesPage
) {
148 kDebug( 5006 ) <<"Folder name for messages classified as spam is"
149 << mSpamRulesPage
->selectedSpamFolderName();
150 kDebug( 5006 ) <<"Folder name for messages classified as unsure is"
151 << mSpamRulesPage
->selectedUnsureFolderName();
153 if ( mVirusRulesPage
)
154 kDebug( 5006 ) <<"Folder name for viruses is"
155 << mVirusRulesPage
->selectedFolderName();
157 KMFilterActionDict dict
;
158 QList
<KMFilter
*> filterList
;
159 bool replaceExistingFilters
= false;
161 // Let's start with virus detection and handling,
162 // so we can avoid spam checks for viral messages
163 if ( mMode
== AntiVirus
) {
164 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
165 it
!= mToolList
.end(); ++it
) {
166 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ) &&
167 ( mVirusRulesPage
->pipeRulesSelected() && (*it
).isVirusTool() ) )
169 // pipe messages through the anti-virus tools,
170 // one single filter for each tool
171 // (could get combined but so it's easier to understand for the user)
172 KMFilter
* pipeFilter
= new KMFilter();
173 QList
<KMFilterAction
*> *pipeFilterActions
= pipeFilter
->actions();
174 KMFilterAction
* pipeFilterAction
= dict
.value( "filter app" )->create();
175 pipeFilterAction
->argsFromString( (*it
).getDetectCmd() );
176 pipeFilterActions
->append( pipeFilterAction
);
177 KMSearchPattern
* pipeFilterPattern
= pipeFilter
->pattern();
178 pipeFilterPattern
->setName( uniqueNameFor( (*it
).getFilterName() ) );
179 pipeFilterPattern
->append( KMSearchRule::createInstance( "<size>",
180 KMSearchRule::FuncIsGreaterOrEqual
, "0" ) );
181 pipeFilter
->setApplyOnOutbound( false);
182 pipeFilter
->setApplyOnInbound();
183 pipeFilter
->setApplyOnExplicit();
184 pipeFilter
->setStopProcessingHere( false );
185 pipeFilter
->setConfigureShortcut( false );
187 filterList
.append( pipeFilter
);
191 if ( mVirusRulesPage
->moveRulesSelected() )
193 // Sort out viruses depending on header fields set by the tools
194 KMFilter
* virusFilter
= new KMFilter();
195 QList
<KMFilterAction
*> *virusFilterActions
= virusFilter
->actions();
196 KMFilterAction
* virusFilterAction1
= dict
.value( "transfer" )->create();
197 virusFilterAction1
->argsFromString( mVirusRulesPage
->selectedFolderName() );
198 virusFilterActions
->append( virusFilterAction1
);
199 if ( mVirusRulesPage
->markReadRulesSelected() ) {
200 KMFilterAction
* virusFilterAction2
= dict
.value( "set status" )->create();
201 virusFilterAction2
->argsFromString( "R" ); // Read
202 virusFilterActions
->append( virusFilterAction2
);
204 KMSearchPattern
* virusFilterPattern
= virusFilter
->pattern();
205 virusFilterPattern
->setName( uniqueNameFor( i18n( "Virus handling" ) ) );
206 virusFilterPattern
->setOp( KMSearchPattern::OpOr
);
207 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
208 it
!= mToolList
.end(); ++it
) {
209 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ))
211 if ( (*it
).isVirusTool() )
213 const QByteArray header
= (*it
).getDetectionHeader().toAscii();
214 const QString
& pattern
= (*it
).getDetectionPattern();
215 if ( (*it
).isUseRegExp() )
216 virusFilterPattern
->append(
217 KMSearchRule::createInstance( header
,
218 KMSearchRule::FuncRegExp
, pattern
) );
220 virusFilterPattern
->append(
221 KMSearchRule::createInstance( header
,
222 KMSearchRule::FuncContains
, pattern
) );
226 virusFilter
->setApplyOnOutbound( false);
227 virusFilter
->setApplyOnInbound();
228 virusFilter
->setApplyOnExplicit();
229 virusFilter
->setStopProcessingHere( true );
230 virusFilter
->setConfigureShortcut( false );
232 filterList
.append( virusFilter
);
235 else { // AntiSpam mode
236 // TODO Existing filters with same name are replaced. This is hardcoded
237 // ATM and needs to be replaced with a value from a (still missing)
238 // checkbox in the GUI. At least, the replacement is announced in the GUI.
239 replaceExistingFilters
= true;
240 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
241 it
!= mToolList
.end(); ++it
) {
242 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ) &&
243 (*it
).isSpamTool() && !(*it
).isDetectionOnly() )
245 // pipe messages through the anti-spam tools,
246 // one single filter for each tool
247 // (could get combined but so it's easier to understand for the user)
248 KMFilter
* pipeFilter
= new KMFilter();
249 QList
<KMFilterAction
*> *pipeFilterActions
= pipeFilter
->actions();
250 KMFilterAction
* pipeFilterAction
= dict
.value( "filter app" )->create();
251 pipeFilterAction
->argsFromString( (*it
).getDetectCmd() );
252 pipeFilterActions
->append( pipeFilterAction
);
253 KMSearchPattern
* pipeFilterPattern
= pipeFilter
->pattern();
254 if ( replaceExistingFilters
)
255 pipeFilterPattern
->setName( (*it
).getFilterName() );
257 pipeFilterPattern
->setName( uniqueNameFor( (*it
).getFilterName() ) );
258 pipeFilterPattern
->append( KMSearchRule::createInstance( "<size>",
259 KMSearchRule::FuncIsLessOrEqual
, "256000" ) );
260 pipeFilter
->setApplyOnOutbound( false);
261 pipeFilter
->setApplyOnInbound();
262 pipeFilter
->setApplyOnExplicit();
263 pipeFilter
->setStopProcessingHere( false );
264 pipeFilter
->setConfigureShortcut( false );
266 filterList
.append( pipeFilter
);
270 // Sort out spam depending on header fields set by the tools
271 KMFilter
* spamFilter
= new KMFilter();
272 QList
<KMFilterAction
*> *spamFilterActions
= spamFilter
->actions();
273 if ( mSpamRulesPage
->moveSpamSelected() )
275 KMFilterAction
* spamFilterAction1
= dict
.value( "transfer" )->create();
276 spamFilterAction1
->argsFromString( mSpamRulesPage
->selectedSpamFolderName() );
277 spamFilterActions
->append( spamFilterAction1
);
279 KMFilterAction
* spamFilterAction2
= dict
.value( "set status" )->create();
280 spamFilterAction2
->argsFromString( "P" ); // Spam
281 spamFilterActions
->append( spamFilterAction2
);
282 if ( mSpamRulesPage
->markAsReadSelected() ) {
283 KMFilterAction
* spamFilterAction3
= dict
.value( "set status" )->create();
284 spamFilterAction3
->argsFromString( "R" ); // Read
285 spamFilterActions
->append( spamFilterAction3
);
287 KMSearchPattern
* spamFilterPattern
= spamFilter
->pattern();
288 if ( replaceExistingFilters
)
289 spamFilterPattern
->setName( i18n( "Spam Handling" ) );
291 spamFilterPattern
->setName( uniqueNameFor( i18n( "Spam Handling" ) ) );
292 spamFilterPattern
->setOp( KMSearchPattern::OpOr
);
293 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
294 it
!= mToolList
.end(); ++it
) {
295 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ) )
297 if ( (*it
).isSpamTool() )
299 const QByteArray header
= (*it
).getDetectionHeader().toAscii();
300 const QString
& pattern
= (*it
).getDetectionPattern();
301 if ( (*it
).isUseRegExp() )
302 spamFilterPattern
->append(
303 KMSearchRule::createInstance( header
,
304 KMSearchRule::FuncRegExp
, pattern
) );
306 spamFilterPattern
->append(
307 KMSearchRule::createInstance( header
,
308 KMSearchRule::FuncContains
, pattern
) );
312 spamFilter
->setApplyOnOutbound( false);
313 spamFilter
->setApplyOnInbound();
314 spamFilter
->setApplyOnExplicit();
315 spamFilter
->setStopProcessingHere( true );
316 spamFilter
->setConfigureShortcut( false );
317 filterList
.append( spamFilter
);
319 if ( mSpamRulesPage
->moveUnsureSelected() )
321 // Sort out messages classified as unsure
322 bool atLeastOneUnsurePattern
= false;
323 KMFilter
* unsureFilter
= new KMFilter();
324 QList
<KMFilterAction
*> *unsureFilterActions
= unsureFilter
->actions();
325 KMFilterAction
* unsureFilterAction1
= dict
.value( "transfer" )->create();
326 unsureFilterAction1
->argsFromString( mSpamRulesPage
->selectedUnsureFolderName() );
327 unsureFilterActions
->append( unsureFilterAction1
);
328 KMSearchPattern
* unsureFilterPattern
= unsureFilter
->pattern();
329 if ( replaceExistingFilters
)
330 unsureFilterPattern
->setName( i18n( "Semi spam (unsure) handling" ) );
332 unsureFilterPattern
->setName( uniqueNameFor( i18n( "Semi spam (unsure) handling" ) ) );
333 unsureFilterPattern
->setOp( KMSearchPattern::OpOr
);
334 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
335 it
!= mToolList
.end(); ++it
) {
336 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ) )
338 if ( (*it
).isSpamTool() && (*it
).hasTristateDetection())
340 atLeastOneUnsurePattern
= true;
341 const QByteArray header
= (*it
).getDetectionHeader().toAscii();
342 const QString
& pattern
= (*it
).getDetectionPattern2();
343 if ( (*it
).isUseRegExp() )
344 unsureFilterPattern
->append(
345 KMSearchRule::createInstance( header
,
346 KMSearchRule::FuncRegExp
, pattern
) );
348 unsureFilterPattern
->append(
349 KMSearchRule::createInstance( header
,
350 KMSearchRule::FuncContains
, pattern
) );
354 unsureFilter
->setApplyOnOutbound( false);
355 unsureFilter
->setApplyOnInbound();
356 unsureFilter
->setApplyOnExplicit();
357 unsureFilter
->setStopProcessingHere( true );
358 unsureFilter
->setConfigureShortcut( false );
360 if ( atLeastOneUnsurePattern
)
361 filterList
.append( unsureFilter
);
366 // Classify messages manually as Spam
367 KMFilter
* classSpamFilter
= new KMFilter();
368 classSpamFilter
->setIcon( "mail-mark-junk" );
369 QList
<KMFilterAction
*> *classSpamFilterActions
= classSpamFilter
->actions();
370 KMFilterAction
* classSpamFilterActionFirst
= dict
.value( "set status" )->create();
371 classSpamFilterActionFirst
->argsFromString( "P" );
372 classSpamFilterActions
->append( classSpamFilterActionFirst
);
373 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
374 it
!= mToolList
.end(); ++it
) {
375 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() )
376 && (*it
).useBayesFilter() && !(*it
).isDetectionOnly() )
378 KMFilterAction
* classSpamFilterAction
= dict
.value( "execute" )->create();
379 classSpamFilterAction
->argsFromString( (*it
).getSpamCmd() );
380 classSpamFilterActions
->append( classSpamFilterAction
);
383 if ( mSpamRulesPage
->moveSpamSelected() )
385 KMFilterAction
* classSpamFilterActionLast
= dict
.value( "transfer" )->create();
386 classSpamFilterActionLast
->argsFromString( mSpamRulesPage
->selectedSpamFolderName() );
387 classSpamFilterActions
->append( classSpamFilterActionLast
);
390 KMSearchPattern
* classSpamFilterPattern
= classSpamFilter
->pattern();
391 if ( replaceExistingFilters
)
392 classSpamFilterPattern
->setName( i18n( "Classify as Spam" ) );
394 classSpamFilterPattern
->setName( uniqueNameFor( i18n( "Classify as Spam" ) ) );
395 classSpamFilterPattern
->append( KMSearchRule::createInstance( "<size>",
396 KMSearchRule::FuncIsGreaterOrEqual
, "0" ) );
397 classSpamFilter
->setApplyOnOutbound( false);
398 classSpamFilter
->setApplyOnInbound( false );
399 classSpamFilter
->setApplyOnExplicit( false );
400 classSpamFilter
->setStopProcessingHere( true );
401 classSpamFilter
->setConfigureShortcut( true );
402 classSpamFilter
->setConfigureToolbar( true );
403 classSpamFilter
->setToolbarName( i18n( "Spam" ) );
404 filterList
.append( classSpamFilter
);
406 // Classify messages manually as not Spam / as Ham
407 KMFilter
* classHamFilter
= new KMFilter();
408 classHamFilter
->setIcon( "mail-mark-notjunk" );
409 QList
<KMFilterAction
*> *classHamFilterActions
= classHamFilter
->actions();
410 KMFilterAction
* classHamFilterActionFirst
= dict
.value( "set status" )->create();
411 classHamFilterActionFirst
->argsFromString( "H" );
412 classHamFilterActions
->append( classHamFilterActionFirst
);
413 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
414 it
!= mToolList
.end(); ++it
) {
415 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() )
416 && (*it
).useBayesFilter() && !(*it
).isDetectionOnly() )
418 KMFilterAction
* classHamFilterAction
= dict
.value( "execute" )->create();
419 classHamFilterAction
->argsFromString( (*it
).getHamCmd() );
420 classHamFilterActions
->append( classHamFilterAction
);
423 for ( QList
<SpamToolConfig
>::iterator it
= mToolList
.begin();
424 it
!= mToolList
.end(); ++it
) {
425 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() )
426 && (*it
).useBayesFilter() && !(*it
).isDetectionOnly() )
428 KMFilterAction
* classHamFilterAction
= dict
.value( "filter app" )->create();
429 classHamFilterAction
->argsFromString( (*it
).getNoSpamCmd() );
430 classHamFilterActions
->append( classHamFilterAction
);
433 KMSearchPattern
* classHamFilterPattern
= classHamFilter
->pattern();
434 if ( replaceExistingFilters
)
435 classHamFilterPattern
->setName( i18n( "Classify as NOT Spam" ) );
437 classHamFilterPattern
->setName( uniqueNameFor( i18n( "Classify as NOT Spam" ) ) );
438 classHamFilterPattern
->append( KMSearchRule::createInstance( "<size>",
439 KMSearchRule::FuncIsGreaterOrEqual
, "0" ) );
440 classHamFilter
->setApplyOnOutbound( false);
441 classHamFilter
->setApplyOnInbound( false );
442 classHamFilter
->setApplyOnExplicit( false );
443 classHamFilter
->setStopProcessingHere( true );
444 classHamFilter
->setConfigureShortcut( true );
445 classHamFilter
->setConfigureToolbar( true );
446 classHamFilter
->setToolbarName( i18n( "Ham" ) );
447 filterList
.append( classHamFilter
);
450 /* Now that all the filters have been added to the list, tell
451 * the filter manager about it. That will emit filterListUpdate
452 * which will result in the filter list in kmmainwidget being
453 * initialized. This should happend only once. */
454 if ( !filterList
.isEmpty() )
455 KMKernel::self()->filterMgr()->appendFilters(
456 filterList
, replaceExistingFilters
);
462 void AntiSpamWizard::checkProgramsSelections()
465 bool supportUnsure
= false;
467 mSpamToolsUsed
= false;
468 mVirusToolsUsed
= false;
469 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
470 it
!= mToolList
.end(); ++it
) {
471 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ) )
474 if ( (*it
).isSpamTool() ) {
475 mSpamToolsUsed
= true;
476 if ( (*it
).hasTristateDetection() )
477 supportUnsure
= true;
479 if ( (*it
).isVirusTool() )
480 mVirusToolsUsed
= true;
484 if ( mMode
== AntiSpam
) {
485 mSpamRulesPage
->allowUnsureFolderSelection( supportUnsure
);
489 if ( ( mMode
== AntiVirus
) && mVirusToolsUsed
)
490 checkVirusRulesSelections();
492 //setNextEnabled( mInfoPage, status );
496 void AntiSpamWizard::checkVirusRulesSelections()
498 //setFinishEnabled( mVirusRulesPage, anyVirusOptionChecked() );
502 void AntiSpamWizard::checkToolAvailability()
504 // this can take some time to find the tools
505 KCursorSaver
busy( KBusyPtr::busy() );
508 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
509 it
!= mToolList
.end(); ++it
) {
510 QString
text( i18n("Scanning for %1...", (*it
).getId() ) );
511 mInfoPage
->setScanProgressText( text
);
512 if ( (*it
).isSpamTool() && (*it
).isServerBased() ) {
513 // check the configured account for pattern in <server>
514 QString pattern
= (*it
).getServerPattern();
515 kDebug(5006) <<"Testing for server pattern:" << pattern
;
517 AccountManager
* mgr
= kmkernel
->acctMgr();
518 QList
<KMAccount
*>::iterator accountIt
= mgr
->begin();
519 while ( accountIt
!= mgr
->end() ) {
520 KMAccount
*account
= *accountIt
;
522 if ( account
->type() == KAccount::Pop
||
523 account
->type() == KAccount::Imap
||
524 account
->type() == KAccount::DImap
) {
525 const NetworkAccount
* n
= dynamic_cast<const NetworkAccount
*>( account
);
526 if ( n
&& n
->host().toLower().contains( pattern
.toLower() ) ) {
527 mInfoPage
->addAvailableTool( (*it
).getVisibleName() );
534 // check the availability of the application
535 qApp
->processEvents( QEventLoop::ExcludeUserInputEvents
, 200 );
536 if ( !checkForProgram( (*it
).getExecutable() ) ) {
537 mInfoPage
->addAvailableTool( (*it
).getVisibleName() );
543 mInfoPage
->setScanProgressText( ( mMode
== AntiSpam
)
544 ? i18n("Scanning for anti-spam tools finished.")
545 : i18n("Scanning for anti-virus tools finished.") );
547 mInfoPage
->setScanProgressText( ( mMode
== AntiSpam
)
548 ? i18n("<p>Sorry, no spam detection tools have been found. "
549 "Install your spam detection software and "
550 "re-run this wizard.</p>")
551 : i18n("Scanning complete. No anti-virus tools found.") );
555 void AntiSpamWizard::slotHelpClicked()
557 if ( mMode
== AntiSpam
)
558 KToolInvocation::invokeHelp( "the-anti-spam-wizard", "kmail" );
560 KToolInvocation::invokeHelp( "the-anti-virus-wizard", "kmail" );
564 void AntiSpamWizard::slotBuildSummary()
568 QString replaceFilters
;
570 if ( mMode
== AntiVirus
) {
571 text
= ""; // TODO add summary for the virus part
573 else { // AntiSpam mode
574 if ( mSpamRulesPage
->markAsReadSelected() ) {
575 if ( mSpamRulesPage
->moveSpamSelected() )
576 text
= i18n( "<p>Messages classified as spam are marked as read."
577 "<br />Spam messages are moved into the folder named <i>%1</i>.</p>"
578 , mSpamRulesPage
->selectedSpamFolderName() );
580 text
= i18n( "<p>Messages classified as spam are marked as read."
581 "<br />Spam messages are not moved into a certain folder.</p>" );
584 if ( mSpamRulesPage
->moveSpamSelected() )
585 text
= i18n( "<p>Messages classified as spam are not marked as read."
586 "<br />Spam messages are moved into the folder named <i>%1</i>.</p>"
587 , mSpamRulesPage
->selectedSpamFolderName() );
589 text
= i18n( "<p>Messages classified as spam are not marked as read."
590 "<br />Spam messages are not moved into a certain folder.</p>" );
593 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
594 it
!= mToolList
.end(); ++it
) {
595 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ) &&
596 (*it
).isSpamTool() && !(*it
).isDetectionOnly() ) {
597 sortFilterOnExistance( (*it
).getFilterName(), newFilters
, replaceFilters
);
600 sortFilterOnExistance( i18n( "Spam Handling" ), newFilters
, replaceFilters
);
602 // The need for a andling of status "probably spam" depends on the tools chosen
603 if ( mSpamRulesPage
->moveUnsureSelected() ) {
604 bool atLeastOneUnsurePattern
= false;
605 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
606 it
!= mToolList
.end(); ++it
) {
607 if ( mInfoPage
->isProgramSelected( (*it
).getVisibleName() ) ) {
608 if ( (*it
).isSpamTool() && (*it
).hasTristateDetection())
609 atLeastOneUnsurePattern
= true;
612 if ( atLeastOneUnsurePattern
) {
613 sortFilterOnExistance( i18n( "Semi spam (unsure) handling" ),
614 newFilters
, replaceFilters
);
615 text
+= i18n( "<p>The folder for messages classified as unsure (probably spam) is <i>%1</i>.</p>"
616 , mSpamRulesPage
->selectedUnsureFolderName() );
620 // Manual classification via toolbar icon / manually applied filter action
621 sortFilterOnExistance( i18n( "Classify as Spam" ),
622 newFilters
, replaceFilters
);
623 sortFilterOnExistance( i18n( "Classify as NOT Spam" ),
624 newFilters
, replaceFilters
);
626 // Show the filters in the summary
627 if ( !newFilters
.isEmpty() )
628 text
+= i18n( "<p>The wizard will create the following filters:<ul>%1</ul></p>"
630 if ( !replaceFilters
.isEmpty() )
631 text
+= i18n( "<p>The wizard will replace the following filters:<ul>%1</ul></p>"
635 mSummaryPage
->setSummaryText( text
);
639 int AntiSpamWizard::checkForProgram( const QString
&executable
)
641 kDebug(5006) <<"Testing for executable:" << executable
;
643 process
.setShellCommand( executable
);
644 return process
.execute ();
648 bool AntiSpamWizard::anyVirusOptionChecked()
650 return ( mVirusRulesPage
->moveRulesSelected()
651 || mVirusRulesPage
->pipeRulesSelected() );
655 const QString
AntiSpamWizard::uniqueNameFor( const QString
& name
)
657 return KMKernel::self()->filterMgr()->createUniqueName( name
);
661 void AntiSpamWizard::sortFilterOnExistance(
662 const QString
& intendedFilterName
,
663 QString
& newFilters
, QString
& replaceFilters
)
665 if ( uniqueNameFor( intendedFilterName
) == intendedFilterName
)
666 newFilters
+= "<li>" + intendedFilterName
+ "</li>";
668 replaceFilters
+= "<li>" + intendedFilterName
+ "</li>";
672 //---------------------------------------------------------------------------
673 AntiSpamWizard::SpamToolConfig::SpamToolConfig( const QString
&toolId
,
674 int configVersion
, int prio
, const QString
&name
, const QString
&exec
,
675 const QString
&url
, const QString
&filter
, const QString
&detection
,
676 const QString
&spam
, const QString
&ham
, const QString
&noSpam
,
677 const QString
&header
, const QString
&pattern
, const QString
&pattern2
,
678 const QString
&serverPattern
, bool detectionOnly
, bool regExp
,
679 bool bayesFilter
, bool tristateDetection
, WizardMode type
)
680 : mId( toolId
), mVersion( configVersion
), mPrio( prio
),
681 mVisibleName( name
), mExecutable( exec
), mWhatsThisText( url
),
682 mFilterName( filter
), mDetectCmd( detection
), mSpamCmd( spam
),
683 mHamCmd( ham
), mNoSpamCmd( noSpam
), mDetectionHeader( header
),
684 mDetectionPattern( pattern
), mDetectionPattern2( pattern2
),
685 mServerPattern( serverPattern
), mDetectionOnly( detectionOnly
),
686 mUseRegExp( regExp
), mSupportsBayesFilter( bayesFilter
),
687 mSupportsUnsure( tristateDetection
), mType( type
)
692 bool AntiSpamWizard::SpamToolConfig::isServerBased() const
694 return !mServerPattern
.isEmpty();
698 //---------------------------------------------------------------------------
699 AntiSpamWizard::ConfigReader::ConfigReader( WizardMode mode
,
700 QList
<SpamToolConfig
> & configList
)
701 : mToolList( configList
),
704 if ( mMode
== AntiSpam
)
705 mConfig
= new KConfig( "kmail.antispamrc" );
707 mConfig
= new KConfig( "kmail.antivirusrc" );
710 AntiSpamWizard::ConfigReader::~ConfigReader( )
716 void AntiSpamWizard::ConfigReader::readAndMergeConfig()
718 QString groupName
= ( mMode
== AntiSpam
)
719 ? QString("Spamtool #%1")
720 : QString("Virustool #%1");
721 // read the configuration from the global config file
722 mConfig
->setReadDefaults( true );
723 KConfigGroup
general( mConfig
, "General" );
724 int registeredTools
= general
.readEntry( "tools", 0 );
725 for (int i
= 1; i
<= registeredTools
; i
++)
727 KConfigGroup
toolConfig( mConfig
, groupName
.arg( i
) );
728 if( !toolConfig
.readEntry( "HeadersOnly", false ) )
729 mToolList
.append( readToolConfig( toolConfig
) );
732 // read the configuration from the user config file
733 // and merge newer config data
734 mConfig
->setReadDefaults( false );
735 KConfigGroup
user_general( mConfig
, "General" );
736 int user_registeredTools
= user_general
.readEntry( "tools", 0 );
737 for (int i
= 1; i
<= user_registeredTools
; i
++)
739 KConfigGroup
toolConfig( mConfig
, groupName
.arg( i
) );
740 if( !toolConfig
.readEntry( "HeadersOnly", false ) )
741 mergeToolConfig( readToolConfig( toolConfig
) );
743 // Make sure to have add least one tool listed even when the
744 // config file was not found or whatever went wrong
745 // Currently only works for spam tools
746 if ( mMode
== AntiSpam
) {
747 if ( registeredTools
< 1 && user_registeredTools
< 1 )
748 mToolList
.append( createDummyConfig() );
754 AntiSpamWizard::SpamToolConfig
755 AntiSpamWizard::ConfigReader::readToolConfig( KConfigGroup
& configGroup
)
757 QString id
= configGroup
.readEntry( "Ident" );
758 int version
= configGroup
.readEntry( "Version", 0 );
760 kDebug(5006) <<"Found predefined tool:" << id
;
761 kDebug(5006) <<"With config version :" << version
;
763 int prio
= configGroup
.readEntry( "Priority", 1 );
764 QString name
= configGroup
.readEntry( "VisibleName" );
765 QString executable
= configGroup
.readEntry( "Executable" );
766 QString url
= configGroup
.readEntry( "URL" );
767 QString filterName
= configGroup
.readEntry( "PipeFilterName" );
768 QString detectCmd
= configGroup
.readEntry( "PipeCmdDetect" );
769 QString spamCmd
= configGroup
.readEntry( "ExecCmdSpam" );
770 QString hamCmd
= configGroup
.readEntry( "ExecCmdHam" );
771 QString noSpamCmd
= configGroup
.readEntry( "PipeCmdNoSpam" );
772 QString header
= configGroup
.readEntry( "DetectionHeader" );
773 QString pattern
= configGroup
.readEntry( "DetectionPattern" );
774 QString pattern2
= configGroup
.readEntry( "DetectionPattern2" );
775 QString serverPattern
= configGroup
.readEntry( "ServerPattern" );
776 bool detectionOnly
= configGroup
.readEntry( "DetectionOnly", false );
777 bool useRegExp
= configGroup
.readEntry( "UseRegExp", false );
778 bool supportsBayes
= configGroup
.readEntry( "SupportsBayes", false );
779 bool supportsUnsure
= configGroup
.readEntry( "SupportsUnsure", false );
780 return SpamToolConfig( id
, version
, prio
, name
, executable
, url
,
781 filterName
, detectCmd
, spamCmd
, hamCmd
, noSpamCmd
,
782 header
, pattern
, pattern2
, serverPattern
,
783 detectionOnly
, useRegExp
,
784 supportsBayes
, supportsUnsure
, mMode
);
788 AntiSpamWizard::SpamToolConfig
AntiSpamWizard::ConfigReader::createDummyConfig()
790 return SpamToolConfig( "spamassassin", 0, 1,
791 "SpamAssassin", "spamassassin -V",
792 "http://spamassassin.org", "SpamAssassin Check",
794 "sa-learn -L --spam --no-sync --single",
795 "sa-learn -L --ham --no-sync --single",
797 "X-Spam-Flag", "yes", "", "",
798 false, false, true, false, AntiSpam
);
802 void AntiSpamWizard::ConfigReader::mergeToolConfig( AntiSpamWizard::SpamToolConfig config
)
805 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
806 it
!= mToolList
.end(); ++it
) {
808 kDebug(5006) <<"Check against tool:" << (*it
).getId();
809 kDebug(5006) <<"Against version :" << (*it
).getVersion();
811 if ( (*it
).getId() == config
.getId() )
814 if ( (*it
).getVersion() < config
.getVersion() )
817 kDebug(5006) <<"Replacing config ...";
819 mToolList
.erase( it
);
820 mToolList
.append( config
);
826 mToolList
.append( config
);
830 void AntiSpamWizard::ConfigReader::sortToolList()
832 QList
<SpamToolConfig
> tmpList
;
833 SpamToolConfig config
;
835 while ( !mToolList
.isEmpty() ) {
836 QList
<SpamToolConfig
>::Iterator highest
;
837 int priority
= 0; // ascending
838 for ( QList
<SpamToolConfig
>::Iterator it
= mToolList
.begin();
839 it
!= mToolList
.end(); ++it
) {
840 if ( (*it
).getPrio() > priority
) {
841 priority
= (*it
).getPrio();
846 tmpList
.append( config
);
847 mToolList
.erase( highest
);
849 for ( QList
<SpamToolConfig
>::Iterator it
= tmpList
.begin();
850 it
!= tmpList
.end(); ++it
) {
851 mToolList
.append( (*it
) );
856 //---------------------------------------------------------------------------
857 ASWizPage::ASWizPage( QWidget
* parent
, const char * name
,
858 const QString
*bannerName
)
861 setObjectName( name
);
862 QString banner
= "kmwizard.png";
863 if ( bannerName
&& !bannerName
->isEmpty() )
864 banner
= *bannerName
;
866 mLayout
= new QHBoxLayout( this );
867 mLayout
->setSpacing( KDialog::spacingHint() );
868 mLayout
->setMargin( KDialog::marginHint() );
870 QVBoxLayout
* sideLayout
= new QVBoxLayout();
871 mLayout
->addItem( sideLayout
);
872 mLayout
->addItem( new QSpacerItem( 5, 5, QSizePolicy::Minimum
, QSizePolicy::Expanding
) );
874 mPixmap
= new QPixmap( UserIcon(banner
) );
875 mBannerLabel
= new QLabel( this );
876 mBannerLabel
->setPixmap( *mPixmap
);
877 mBannerLabel
->setScaledContents( false );
878 mBannerLabel
->setFrameShape( QFrame::StyledPanel
);
879 mBannerLabel
->setFrameShadow( QFrame::Sunken
);
880 mBannerLabel
->setSizePolicy( QSizePolicy::Fixed
, QSizePolicy::Fixed
);
882 sideLayout
->addWidget( mBannerLabel
);
883 sideLayout
->addItem( new QSpacerItem( 5, 5, QSizePolicy::Minimum
, QSizePolicy::Expanding
) );
887 //---------------------------------------------------------------------------
888 ASWizInfoPage::ASWizInfoPage( AntiSpamWizard::WizardMode mode
,
889 QWidget
* parent
, const char * name
)
890 : ASWizPage( parent
, name
)
892 QBoxLayout
* layout
= new QVBoxLayout();
893 mLayout
->addItem( layout
);
895 mIntroText
= new QLabel( this );
897 ( mode
== AntiSpamWizard::AntiSpam
)
899 "The wizard will search for any tools to do spam detection\n"
900 "and setup KMail to work with them."
903 "<p>Here you can get some assistance in setting up KMail's filter "
904 "rules to use some commonly-known anti-virus tools.</p>"
905 "<p>The wizard can detect those tools on your computer as "
906 "well as create filter rules to classify messages using these "
907 "tools and to separate messages containing viruses. "
908 "The wizard will not take any existing filter "
909 "rules into consideration: it will always append the new rules.</p>"
910 "<p><b>Warning:</b> As KMail appears to be frozen during the scan of the "
911 "messages for viruses, you may encounter problems with "
912 "the responsiveness of KMail because anti-virus tool "
913 "operations are usually time consuming; please consider "
914 "deleting the filter rules created by the wizard to get "
915 "back to the former behavior.</p>"
917 mIntroText
->setWordWrap(true);
918 layout
->addWidget( mIntroText
);
920 mScanProgressText
= new QLabel( this );
921 mScanProgressText
->clear();
922 mScanProgressText
->setWordWrap( true );
923 layout
->addWidget( mScanProgressText
);
925 mToolsList
= new QListWidget( this );
927 mToolsList
->setSelectionMode( QAbstractItemView::MultiSelection
);
928 mToolsList
->setLayoutMode( QListView::Batched
);
929 mToolsList
->setBatchSize( 10 );
930 layout
->addWidget( mToolsList
);
931 connect( mToolsList
->selectionModel(), SIGNAL(selectionChanged(const QItemSelection
&, const QItemSelection
&)),
932 this, SLOT(processSelectionChange(void)) );
934 mSelectionHint
= new QLabel( this );
935 mSelectionHint
->clear();
936 layout
->addWidget( mSelectionHint
);
938 layout
->addStretch();
942 void ASWizInfoPage::setScanProgressText( const QString
&toolName
)
944 mScanProgressText
->setText( toolName
);
948 void ASWizInfoPage::addAvailableTool( const QString
&visibleName
)
950 QString listName
= visibleName
;
951 mToolsList
->addItem( listName
);
952 if ( !mToolsList
->isVisible() )
955 mToolsList
->selectionModel()->clearSelection();
956 mToolsList
->setCurrentRow( 0 );
957 mSelectionHint
->setText( i18n("<p>Please select the tools to be used "
958 "for the detection and go "
959 "to the next page.</p>") );
963 bool ASWizInfoPage::isProgramSelected( const QString
&visibleName
)
965 QString listName
= visibleName
;
967 QList
<QListWidgetItem
*> foundItems
= mToolsList
->findItems( listName
, Qt::MatchFixedString
);
968 return (foundItems
.size() > 0 && foundItems
[0]->isSelected());
972 void ASWizInfoPage::processSelectionChange()
974 emit
selectionChanged();
978 //---------------------------------------------------------------------------
979 ASWizSpamRulesPage::ASWizSpamRulesPage( QWidget
* parent
, const char * name
,
980 MainFolderView
* mainFolderTree
)
981 : ASWizPage( parent
, name
)
983 QVBoxLayout
*layout
= new QVBoxLayout();
984 mLayout
->addItem( layout
);
986 mMarkRules
= new QCheckBox( i18n("&Mark detected spam messages as read"), this );
987 mMarkRules
->setWhatsThis(
988 i18n( "Mark messages which have been classified as spam as read.") );
989 layout
->addWidget( mMarkRules
);
991 mMoveSpamRules
= new QCheckBox( i18n("Move &known spam to:"), this );
992 mMoveSpamRules
->setWhatsThis(
993 i18n( "The default folder for spam messages is the trash folder, "
994 "but you may change that in the folder view below.") );
995 layout
->addWidget( mMoveSpamRules
);
997 mFolderReqForSpamFolder
= new FolderRequester( this, mainFolderTree
);
998 mFolderReqForSpamFolder
->setFolder( "trash" );
999 mFolderReqForSpamFolder
->setMustBeReadWrite( true );
1000 mFolderReqForSpamFolder
->setShowOutbox( false );
1001 mFolderReqForSpamFolder
->setShowImapFolders( false );
1003 QHBoxLayout
*hLayout1
= new QHBoxLayout();
1004 layout
->addItem( hLayout1
);
1005 hLayout1
->addSpacing( KDialog::spacingHint() * 3 );
1006 hLayout1
->addWidget( mFolderReqForSpamFolder
);
1008 mMoveUnsureRules
= new QCheckBox( i18n("Move &probable spam to:"), this );
1009 mMoveUnsureRules
->setWhatsThis(
1010 i18n( "The default folder is the inbox folder, but you may change that "
1011 "in the folder view below.<p>"
1012 "Not all tools support a classification as unsure. If you have not "
1013 "selected a capable tool, you cannot select a folder as well.</p>") );
1014 layout
->addWidget( mMoveUnsureRules
);
1016 mFolderReqForUnsureFolder
= new FolderRequester( this, mainFolderTree
);
1017 mFolderReqForUnsureFolder
->setFolder( "inbox" );
1018 mFolderReqForUnsureFolder
->setMustBeReadWrite( true );
1019 mFolderReqForUnsureFolder
->setShowOutbox( false );
1020 mFolderReqForUnsureFolder
->setShowImapFolders( false );
1022 QHBoxLayout
*hLayout2
= new QHBoxLayout();
1023 layout
->addItem( hLayout2
);
1024 hLayout2
->addSpacing( KDialog::spacingHint() * 3 );
1025 hLayout2
->addWidget( mFolderReqForUnsureFolder
);
1027 layout
->addStretch();
1029 connect( mMarkRules
, SIGNAL(clicked()),
1030 this, SLOT(processSelectionChange(void)) );
1031 connect( mMoveSpamRules
, SIGNAL(clicked()),
1032 this, SLOT(processSelectionChange(void)) );
1033 connect( mMoveUnsureRules
, SIGNAL(clicked()),
1034 this, SLOT(processSelectionChange(void)) );
1035 connect( mFolderReqForSpamFolder
, SIGNAL(folderChanged(KMFolder
*)),
1036 this, SLOT(processSelectionChange(KMFolder
*)) );
1037 connect( mFolderReqForUnsureFolder
, SIGNAL(folderChanged(KMFolder
*)),
1038 this, SLOT(processSelectionChange(KMFolder
*)) );
1040 mMarkRules
->setChecked( true );
1041 mMoveSpamRules
->setChecked( true );
1045 bool ASWizSpamRulesPage::markAsReadSelected() const
1047 return mMarkRules
->isChecked();
1051 bool ASWizSpamRulesPage::moveSpamSelected() const
1053 return mMoveSpamRules
->isChecked();
1057 bool ASWizSpamRulesPage::moveUnsureSelected() const
1059 return mMoveUnsureRules
->isChecked();
1063 QString
ASWizSpamRulesPage::selectedSpamFolderName() const
1065 QString name
= "trash";
1066 if ( mFolderReqForSpamFolder
->folder() )
1067 name
= mFolderReqForSpamFolder
->folder()->idString();
1072 QString
ASWizSpamRulesPage::selectedUnsureFolderName() const
1074 QString name
= "inbox";
1075 if ( mFolderReqForUnsureFolder
->folder() )
1076 name
= mFolderReqForUnsureFolder
->folder()->idString();
1081 void ASWizSpamRulesPage::processSelectionChange()
1083 mFolderReqForSpamFolder
->setEnabled( mMoveSpamRules
->isChecked() );
1084 mFolderReqForUnsureFolder
->setEnabled( mMoveUnsureRules
->isChecked() );
1085 emit
selectionChanged();
1089 void ASWizSpamRulesPage::processSelectionChange( KMFolder
* )
1091 processSelectionChange();
1095 void ASWizSpamRulesPage::allowUnsureFolderSelection( bool enabled
)
1097 mMoveUnsureRules
->setEnabled( enabled
);
1098 mMoveUnsureRules
->setVisible( enabled
);
1099 mFolderReqForUnsureFolder
->setEnabled( enabled
);
1100 mFolderReqForUnsureFolder
->setVisible( enabled
);
1104 //---------------------------------------------------------------------------
1105 ASWizVirusRulesPage::ASWizVirusRulesPage( QWidget
* parent
, const char * name
,
1106 MainFolderView
* mainFolderTree
)
1107 : ASWizPage( parent
, name
)
1109 QGridLayout
*grid
= new QGridLayout();
1110 mLayout
->addItem( grid
);
1111 grid
->setSpacing( KDialog::spacingHint() );
1113 mPipeRules
= new QCheckBox( i18n("Check messages using the anti-virus tools"), this );
1114 mPipeRules
->setWhatsThis(
1115 i18n( "Let the anti-virus tools check your messages. The wizard "
1116 "will create appropriate filters. The messages are usually "
1117 "marked by the tools so that following filters can react "
1118 "on this and, for example, move virus messages to a special folder.") );
1119 grid
->addWidget( mPipeRules
, 0, 0 );
1121 mMoveRules
= new QCheckBox( i18n("Move detected viral messages to the selected folder"), this );
1122 mMoveRules
->setWhatsThis(
1123 i18n( "A filter to detect messages classified as virus-infected and to move "
1124 "those messages into a predefined folder is created. The "
1125 "default folder is the trash folder, but you may change that "
1126 "in the folder view.") );
1127 grid
->addWidget( mMoveRules
, 1, 0 );
1129 mMarkRules
= new QCheckBox( i18n("Additionally, mark detected viral messages as read"), this );
1130 mMarkRules
->setEnabled( false );
1131 mMarkRules
->setWhatsThis(
1132 i18n( "Mark messages which have been classified as "
1133 "virus-infected as read, as well as moving them "
1134 "to the selected folder.") );
1135 grid
->addWidget( mMarkRules
, 2, 0 );
1137 mFolderTree
= new FolderSelectionTreeWidget( this, mainFolderTree
);
1138 mFolderTree
->reload( true, true, true, QString( "trash" ) );
1139 grid
->addWidget( mFolderTree
, 3, 0 );
1141 connect( mPipeRules
, SIGNAL(clicked()),
1142 this, SLOT(processSelectionChange(void)) );
1143 connect( mMoveRules
, SIGNAL(clicked()),
1144 this, SLOT(processSelectionChange(void)) );
1145 connect( mMarkRules
, SIGNAL(clicked()),
1146 this, SLOT(processSelectionChange(void)) );
1147 connect( mMoveRules
, SIGNAL( toggled( bool ) ),
1148 mMarkRules
, SLOT( setEnabled( bool ) ) );
1152 bool ASWizVirusRulesPage::pipeRulesSelected() const
1154 return mPipeRules
->isChecked();
1158 bool ASWizVirusRulesPage::moveRulesSelected() const
1160 return mMoveRules
->isChecked();
1163 bool ASWizVirusRulesPage::markReadRulesSelected() const
1165 return mMarkRules
->isChecked();
1169 QString
ASWizVirusRulesPage::selectedFolderName() const
1171 QString name
= "trash";
1172 if ( mFolderTree
->folder() )
1173 name
= mFolderTree
->folder()->idString();
1177 void ASWizVirusRulesPage::processSelectionChange()
1179 emit
selectionChanged();
1183 //---------------------------------------------------------------------------
1184 ASWizSummaryPage::ASWizSummaryPage( QWidget
* parent
, const char * name
)
1185 : ASWizPage( parent
, name
)
1187 QBoxLayout
* layout
= new QVBoxLayout();
1188 mLayout
->addItem( layout
);
1190 mSummaryText
= new QLabel( this );
1191 layout
->addWidget( mSummaryText
);
1192 layout
->addStretch();
1196 void ASWizSummaryPage::setSummaryText( const QString
& text
)
1198 mSummaryText
->setText( text
);
1202 #include "antispamwizard.moc"