summaryrefslogtreecommitdiffstats
path: root/kmail
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /kmail
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kmail')
-rw-r--r--kmail/COMMITPOLICY13
-rw-r--r--kmail/ChangeLog806
-rw-r--r--kmail/DESIGN1
-rw-r--r--kmail/KMail.desktop93
-rw-r--r--kmail/Mainpage.dox871
-rw-r--r--kmail/Makefile.am237
-rw-r--r--kmail/TODO36
-rw-r--r--kmail/about/Makefile.am6
-rw-r--r--kmail/about/kmail.css26
-rw-r--r--kmail/about/main.html66
-rw-r--r--kmail/about/top-right-kmail.pngbin0 -> 17996 bytes
-rw-r--r--kmail/aboutdata.cpp229
-rw-r--r--kmail/aboutdata.h49
-rw-r--r--kmail/accountcombobox.cpp106
-rw-r--r--kmail/accountcombobox.h61
-rw-r--r--kmail/accountdialog.cpp2352
-rw-r--r--kmail/accountdialog.h340
-rw-r--r--kmail/accountmanager.cpp415
-rw-r--r--kmail/accountmanager.h141
-rw-r--r--kmail/accountwizard.cpp799
-rw-r--r--kmail/accountwizard.h138
-rw-r--r--kmail/acljobs.cpp261
-rw-r--r--kmail/acljobs.h177
-rw-r--r--kmail/actionscheduler.cpp836
-rw-r--r--kmail/actionscheduler.h173
-rw-r--r--kmail/annotationjobs.cpp253
-rw-r--r--kmail/annotationjobs.h199
-rw-r--r--kmail/antispamconfig.cpp98
-rw-r--r--kmail/antispamconfig.h120
-rw-r--r--kmail/antispamwizard.cpp1151
-rw-r--r--kmail/antispamwizard.h398
-rw-r--r--kmail/app_octetstream.cpp66
-rw-r--r--kmail/application_octetstream.desktop85
-rw-r--r--kmail/attachmentcollector.cpp85
-rw-r--r--kmail/attachmentcollector.h75
-rw-r--r--kmail/attachmentlistview.cpp146
-rw-r--r--kmail/attachmentlistview.h59
-rw-r--r--kmail/attachmentstrategy.cpp209
-rw-r--r--kmail/attachmentstrategy.h79
-rw-r--r--kmail/avscripts/Makefile.am2
-rwxr-xr-xkmail/avscripts/kmail_antivir.sh42
-rwxr-xr-xkmail/avscripts/kmail_clamav.sh53
-rwxr-xr-xkmail/avscripts/kmail_fprot.sh55
-rwxr-xr-xkmail/avscripts/kmail_sav.sh42
-rw-r--r--kmail/bodypartformatter.cpp334
-rw-r--r--kmail/bodypartformatter.h58
-rw-r--r--kmail/bodypartformatterfactory.cpp191
-rw-r--r--kmail/bodypartformatterfactory.h72
-rw-r--r--kmail/bodypartformatterfactory_p.h62
-rw-r--r--kmail/bodyvisitor.cpp211
-rw-r--r--kmail/bodyvisitor.h109
-rw-r--r--kmail/cachedimapjob.cpp841
-rw-r--r--kmail/cachedimapjob.h141
-rw-r--r--kmail/callback.cpp219
-rw-r--r--kmail/callback.h91
-rw-r--r--kmail/chiasmuskeyselector.cpp55
-rw-r--r--kmail/chiasmuskeyselector.h27
-rw-r--r--kmail/colorlistbox.cpp198
-rw-r--r--kmail/colorlistbox.h73
-rw-r--r--kmail/compactionjob.cpp292
-rw-r--r--kmail/compactionjob.h114
-rw-r--r--kmail/composer.cpp4
-rw-r--r--kmail/composer.h153
-rw-r--r--kmail/composercryptoconfiguration.ui158
-rw-r--r--kmail/configure.in.bot14
-rw-r--r--kmail/configure.in.in90
-rw-r--r--kmail/configuredialog.cpp5064
-rw-r--r--kmail/configuredialog.h90
-rw-r--r--kmail/configuredialog_p.cpp437
-rw-r--r--kmail/configuredialog_p.h1064
-rw-r--r--kmail/copyfolderjob.cpp283
-rw-r--r--kmail/copyfolderjob.h110
-rw-r--r--kmail/cr22-app-kmaillight.pngbin0 -> 1424 bytes
-rw-r--r--kmail/cr32-app-kmaillight.pngbin0 -> 1744 bytes
-rw-r--r--kmail/csshelper.cpp93
-rw-r--r--kmail/csshelper.h46
-rw-r--r--kmail/custommimeheader.kcfg15
-rw-r--r--kmail/custommimeheader.kcfgc5
-rw-r--r--kmail/customtemplates.cpp376
-rw-r--r--kmail/customtemplates.h92
-rw-r--r--kmail/customtemplates_base.ui303
-rw-r--r--kmail/customtemplates_kfg.kcfg28
-rw-r--r--kmail/customtemplates_kfg.kcfgc5
-rw-r--r--kmail/dcopimap.desktop55
-rw-r--r--kmail/dcopmail.desktop55
-rw-r--r--kmail/dcoptest.cpp40
-rw-r--r--kmail/dictionarycombobox.cpp149
-rw-r--r--kmail/dictionarycombobox.h83
-rw-r--r--kmail/distributionlistdialog.cpp261
-rw-r--r--kmail/distributionlistdialog.h46
-rw-r--r--kmail/editorwatcher.cpp181
-rw-r--r--kmail/editorwatcher.h77
-rw-r--r--kmail/encodingdetector.cpp1377
-rw-r--r--kmail/encodingdetector.h166
-rw-r--r--kmail/encodingdetector_ja.cpp376
-rw-r--r--kmail/encodingdetector_ja_p.h126
-rw-r--r--kmail/eventsrc126
-rw-r--r--kmail/expirejob.cpp252
-rw-r--r--kmail/expirejob.h81
-rw-r--r--kmail/expirypropertiesdialog.cpp197
-rw-r--r--kmail/expirypropertiesdialog.h68
-rw-r--r--kmail/favoritefolderview.cpp517
-rw-r--r--kmail/favoritefolderview.h95
-rw-r--r--kmail/filehtmlwriter.cpp108
-rw-r--r--kmail/filehtmlwriter.h67
-rw-r--r--kmail/filterimporterexporter.cpp216
-rw-r--r--kmail/filterimporterexporter.h70
-rw-r--r--kmail/filterlog.cpp165
-rw-r--r--kmail/filterlog.h161
-rw-r--r--kmail/filterlogdlg.cpp268
-rw-r--r--kmail/filterlogdlg.h80
-rw-r--r--kmail/folderIface.cpp150
-rw-r--r--kmail/folderIface.h71
-rw-r--r--kmail/folderdiaacltab.cpp817
-rw-r--r--kmail/folderdiaacltab.h157
-rw-r--r--kmail/folderdiaquotatab.cpp215
-rw-r--r--kmail/folderdiaquotatab.h91
-rw-r--r--kmail/folderdiaquotatab_p.cpp88
-rw-r--r--kmail/folderdiaquotatab_p.h63
-rw-r--r--kmail/folderjob.cpp130
-rw-r--r--kmail/folderjob.h188
-rw-r--r--kmail/folderpropertiesdialog.ui638
-rw-r--r--kmail/folderpropertiesdialog.ui.h15
-rw-r--r--kmail/folderrequester.cpp127
-rw-r--r--kmail/folderrequester.h112
-rw-r--r--kmail/foldershortcutdialog.cpp108
-rw-r--r--kmail/foldershortcutdialog.h74
-rw-r--r--kmail/folderstorage.cpp1176
-rw-r--r--kmail/folderstorage.h645
-rw-r--r--kmail/foldertreebase.cpp243
-rw-r--r--kmail/foldertreebase.h98
-rw-r--r--kmail/folderviewtooltip.h55
-rw-r--r--kmail/globalsettings.cpp62
-rw-r--r--kmail/globalsettings.h59
-rw-r--r--kmail/globalsettings_base.kcfgc7
-rw-r--r--kmail/headeritem.cpp585
-rw-r--r--kmail/headeritem.h241
-rw-r--r--kmail/headerlistquicksearch.cpp193
-rw-r--r--kmail/headerlistquicksearch.h102
-rw-r--r--kmail/headerstrategy.cpp312
-rw-r--r--kmail/headerstrategy.h80
-rw-r--r--kmail/headerstyle.cpp983
-rw-r--r--kmail/headerstyle.h88
-rw-r--r--kmail/hi128-app-kmail.pngbin0 -> 15605 bytes
-rw-r--r--kmail/hi16-app-kmail.pngbin0 -> 1198 bytes
-rw-r--r--kmail/hi22-app-kmail.pngbin0 -> 1521 bytes
-rw-r--r--kmail/hi32-app-kmail.pngbin0 -> 2946 bytes
-rw-r--r--kmail/hi48-app-kmail.pngbin0 -> 4799 bytes
-rw-r--r--kmail/hi64-app-kmail.pngbin0 -> 6140 bytes
-rw-r--r--kmail/hisc-app-kmail.svgzbin0 -> 2953 bytes
-rw-r--r--kmail/htmlstatusbar.cpp140
-rw-r--r--kmail/htmlstatusbar.h100
-rw-r--r--kmail/identitydialog.cpp700
-rw-r--r--kmail/identitydialog.h118
-rw-r--r--kmail/identitydrag.cpp86
-rw-r--r--kmail/identitydrag.h65
-rw-r--r--kmail/identitylistview.cpp146
-rw-r--r--kmail/identitylistview.h86
-rw-r--r--kmail/imapaccountbase.cpp1446
-rw-r--r--kmail/imapaccountbase.h635
-rw-r--r--kmail/imapjob.cpp711
-rw-r--r--kmail/imapjob.h97
-rw-r--r--kmail/index.cpp594
-rw-r--r--kmail/index.h218
-rw-r--r--kmail/interfaces/Makefile.am8
-rw-r--r--kmail/interfaces/bodypart.h163
-rw-r--r--kmail/interfaces/bodypartformatter.h95
-rw-r--r--kmail/interfaces/bodyparturlhandler.h105
-rw-r--r--kmail/interfaces/htmlwriter.h120
-rw-r--r--kmail/interfaces/observable.h57
-rw-r--r--kmail/interfaces/observer.h55
-rw-r--r--kmail/interfaces/rulewidgethandler.h81
-rw-r--r--kmail/interfaces/urlhandler.h79
-rw-r--r--kmail/isubject.cpp39
-rw-r--r--kmail/isubject.h63
-rw-r--r--kmail/jobscheduler.cpp256
-rw-r--r--kmail/jobscheduler.h156
-rw-r--r--kmail/kcm_kmail.cpp85
-rw-r--r--kmail/kcursorsaver.h61
-rw-r--r--kmail/keyresolver.cpp1615
-rw-r--r--kmail/keyresolver.h319
-rw-r--r--kmail/khtmlparthtmlwriter.cpp154
-rw-r--r--kmail/khtmlparthtmlwriter.h83
-rw-r--r--kmail/kleo_util.h81
-rw-r--r--kmail/klistboxdialog.cpp83
-rw-r--r--kmail/klistboxdialog.h36
-rw-r--r--kmail/klistviewindexedsearchline.cpp74
-rw-r--r--kmail/klistviewindexedsearchline.h76
-rw-r--r--kmail/kmaccount.cpp500
-rw-r--r--kmail/kmaccount.h336
-rw-r--r--kmail/kmacctcachedimap.cpp479
-rw-r--r--kmail/kmacctcachedimap.h230
-rw-r--r--kmail/kmacctfolder.cpp46
-rw-r--r--kmail/kmacctfolder.h55
-rw-r--r--kmail/kmacctimap.cpp621
-rw-r--r--kmail/kmacctimap.h152
-rw-r--r--kmail/kmacctlocal.cpp322
-rw-r--r--kmail/kmacctlocal.h57
-rw-r--r--kmail/kmacctmaildir.cpp234
-rw-r--r--kmail/kmacctmaildir.h37
-rw-r--r--kmail/kmacctseldlg.cpp77
-rw-r--r--kmail/kmacctseldlg.h51
-rw-r--r--kmail/kmaddrbook.cpp135
-rw-r--r--kmail/kmaddrbook.h43
-rwxr-xr-xkmail/kmail-3.1-update-new-mail-notification-settings.pl38
-rwxr-xr-xkmail/kmail-3.1-use-UOID-for-identities.pl93
-rw-r--r--kmail/kmail-3.1.4-dont-use-UOID-0-for-any-identity.pl88
-rwxr-xr-xkmail/kmail-3.2-misc.sh78
-rwxr-xr-xkmail/kmail-3.2-update-loop-on-goto-unread-settings.sh21
-rw-r--r--kmail/kmail-3.3-aegypten.pl28
-rw-r--r--kmail/kmail-3.3-misc.pl27
-rw-r--r--kmail/kmail-3.3-move-identities.pl31
-rwxr-xr-xkmail/kmail-3.3-split-sign-encr-keys.sh31
-rwxr-xr-xkmail/kmail-3.3-use-ID-for-accounts.pl236
-rw-r--r--kmail/kmail-3.3b1-misc.pl38
-rw-r--r--kmail/kmail-3.4-misc.pl27
-rw-r--r--kmail/kmail-3.4.1-update-status-filters.pl42
-rw-r--r--kmail/kmail-3.5-trigger-flag-migration.pl39
-rwxr-xr-xkmail/kmail-pgpidentity.pl34
-rwxr-xr-xkmail/kmail-upd-identities.pl54
-rw-r--r--kmail/kmail.antispamrc237
-rw-r--r--kmail/kmail.antispamrc-HOWTO154
-rw-r--r--kmail/kmail.antivirusrc50
-rw-r--r--kmail/kmail.kcfg670
-rw-r--r--kmail/kmail.upd179
-rw-r--r--kmail/kmailIface.h219
-rw-r--r--kmail/kmail_config_accounts.desktop162
-rw-r--r--kmail/kmail_config_appearance.desktop169
-rw-r--r--kmail/kmail_config_composer.desktop150
-rw-r--r--kmail/kmail_config_identity.desktop170
-rw-r--r--kmail/kmail_config_misc.desktop166
-rw-r--r--kmail/kmail_config_security.desktop172
-rw-r--r--kmail/kmail_options.h31
-rw-r--r--kmail/kmail_part.cpp251
-rw-r--r--kmail/kmail_part.h100
-rw-r--r--kmail/kmail_part.rc199
-rw-r--r--kmail/kmail_view.desktop22
-rw-r--r--kmail/kmailicalIface.h175
-rw-r--r--kmail/kmailicalifaceimpl.cpp2297
-rw-r--r--kmail/kmailicalifaceimpl.h347
-rw-r--r--kmail/kmailpartIface.h35
-rw-r--r--kmail/kmatmlistview.cpp175
-rw-r--r--kmail/kmatmlistview.h71
-rw-r--r--kmail/kmcommands.cpp3559
-rw-r--r--kmail/kmcommands.h1101
-rw-r--r--kmail/kmcomposerui.rc115
-rw-r--r--kmail/kmcomposewin.cpp5233
-rw-r--r--kmail/kmcomposewin.h911
-rw-r--r--kmail/kmdebug.h62
-rw-r--r--kmail/kmdict.cpp117
-rw-r--r--kmail/kmdict.h68
-rw-r--r--kmail/kmedit.cpp766
-rw-r--r--kmail/kmedit.h131
-rw-r--r--kmail/kmfawidgets.cpp157
-rw-r--r--kmail/kmfawidgets.h57
-rw-r--r--kmail/kmfilter.cpp430
-rw-r--r--kmail/kmfilter.h312
-rw-r--r--kmail/kmfilteraction.cpp1930
-rw-r--r--kmail/kmfilteraction.h700
-rw-r--r--kmail/kmfilterdlg.cpp1354
-rw-r--r--kmail/kmfilterdlg.h422
-rw-r--r--kmail/kmfiltermgr.cpp509
-rw-r--r--kmail/kmfiltermgr.h198
-rw-r--r--kmail/kmfolder.cpp881
-rw-r--r--kmail/kmfolder.h694
-rw-r--r--kmail/kmfoldercachedimap.cpp2992
-rw-r--r--kmail/kmfoldercachedimap.h567
-rw-r--r--kmail/kmfoldercombobox.cpp188
-rw-r--r--kmail/kmfoldercombobox.h51
-rw-r--r--kmail/kmfolderdia.cpp792
-rw-r--r--kmail/kmfolderdia.h241
-rw-r--r--kmail/kmfolderdir.cpp313
-rw-r--r--kmail/kmfolderdir.h92
-rw-r--r--kmail/kmfolderimap.cpp2434
-rw-r--r--kmail/kmfolderimap.h548
-rw-r--r--kmail/kmfolderindex.cpp499
-rw-r--r--kmail/kmfolderindex.h130
-rw-r--r--kmail/kmfoldermaildir.cpp1172
-rw-r--r--kmail/kmfoldermaildir.h169
-rw-r--r--kmail/kmfoldermbox.cpp1278
-rw-r--r--kmail/kmfoldermbox.h157
-rw-r--r--kmail/kmfoldermgr.cpp604
-rw-r--r--kmail/kmfoldermgr.h186
-rw-r--r--kmail/kmfoldernode.cpp65
-rw-r--r--kmail/kmfoldernode.h81
-rw-r--r--kmail/kmfoldersearch.cpp1141
-rw-r--r--kmail/kmfoldersearch.h216
-rw-r--r--kmail/kmfolderseldlg.cpp574
-rw-r--r--kmail/kmfolderseldlg.h119
-rw-r--r--kmail/kmfoldertree.cpp2126
-rw-r--r--kmail/kmfoldertree.h350
-rw-r--r--kmail/kmfoldertype.h37
-rw-r--r--kmail/kmglobal.h92
-rw-r--r--kmail/kmgroupware.cpp88
-rw-r--r--kmail/kmgroupware.h46
-rw-r--r--kmail/kmheaders.cpp3569
-rw-r--r--kmail/kmheaders.h465
-rw-r--r--kmail/kmkernel.cpp2401
-rw-r--r--kmail/kmkernel.h504
-rw-r--r--kmail/kmlineeditspell.cpp216
-rw-r--r--kmail/kmlineeditspell.h55
-rw-r--r--kmail/kmmainwidget.cpp3979
-rw-r--r--kmail/kmmainwidget.h564
-rw-r--r--kmail/kmmainwin.cpp222
-rw-r--r--kmail/kmmainwin.h80
-rw-r--r--kmail/kmmainwin.rc205
-rw-r--r--kmail/kmmessage.cpp4373
-rw-r--r--kmail/kmmessage.h916
-rw-r--r--kmail/kmmimeparttree.cpp395
-rw-r--r--kmail/kmmimeparttree.h125
-rw-r--r--kmail/kmmsgbase.cpp1483
-rw-r--r--kmail/kmmsgbase.h472
-rw-r--r--kmail/kmmsgdict.cpp651
-rw-r--r--kmail/kmmsgdict.h168
-rw-r--r--kmail/kmmsginfo.cpp700
-rw-r--r--kmail/kmmsginfo.h126
-rw-r--r--kmail/kmmsglist.cpp186
-rw-r--r--kmail/kmmsglist.h96
-rw-r--r--kmail/kmmsgpart.cpp602
-rw-r--r--kmail/kmmsgpart.h255
-rw-r--r--kmail/kmmsgpartdlg.cpp452
-rw-r--r--kmail/kmmsgpartdlg.h163
-rw-r--r--kmail/kmpopfiltercnfrmdlg.cpp470
-rw-r--r--kmail/kmpopfiltercnfrmdlg.h111
-rw-r--r--kmail/kmpopheaders.cpp75
-rw-r--r--kmail/kmpopheaders.h63
-rw-r--r--kmail/kmreadermainwin.cpp535
-rw-r--r--kmail/kmreadermainwin.h92
-rw-r--r--kmail/kmreadermainwin.rc75
-rw-r--r--kmail/kmreaderwin.cpp2767
-rw-r--r--kmail/kmreaderwin.h546
-rw-r--r--kmail/kmsearchpattern.cpp929
-rw-r--r--kmail/kmsearchpattern.h407
-rw-r--r--kmail/kmsearchpatternedit.cpp483
-rw-r--r--kmail/kmsearchpatternedit.h211
-rw-r--r--kmail/kmsender.cpp1231
-rw-r--r--kmail/kmsender.h174
-rw-r--r--kmail/kmsender_p.h151
-rw-r--r--kmail/kmservertest.cpp189
-rw-r--r--kmail/kmservertest.h88
-rw-r--r--kmail/kmstartup.cpp268
-rw-r--r--kmail/kmstartup.h44
-rw-r--r--kmail/kmsystemtray.cpp585
-rw-r--r--kmail/kmsystemtray.h91
-rw-r--r--kmail/kmtransport.cpp807
-rw-r--r--kmail/kmtransport.h169
-rw-r--r--kmail/kmversion.h8
-rw-r--r--kmail/korghelper.cpp53
-rw-r--r--kmail/korghelper.h32
-rw-r--r--kmail/kwindowpositioner.cpp60
-rw-r--r--kmail/kwindowpositioner.h47
-rw-r--r--kmail/listjob.cpp255
-rw-r--r--kmail/listjob.h146
-rw-r--r--kmail/localsubscriptiondialog.cpp148
-rw-r--r--kmail/localsubscriptiondialog.h67
-rw-r--r--kmail/mailcomposerIface.h53
-rw-r--r--kmail/maildirjob.cpp120
-rw-r--r--kmail/maildirjob.h61
-rw-r--r--kmail/mailinglist-magic.cpp414
-rw-r--r--kmail/mailinglist-magic.h85
-rw-r--r--kmail/mailinglistpropertiesdialog.cpp344
-rw-r--r--kmail/mailinglistpropertiesdialog.h87
-rw-r--r--kmail/mailserviceimpl.cpp135
-rw-r--r--kmail/mailserviceimpl.h74
-rw-r--r--kmail/mailsourceviewer.cpp84
-rw-r--r--kmail/mailsourceviewer.h71
-rw-r--r--kmail/main.cpp116
-rw-r--r--kmail/managesievescriptsdialog.cpp347
-rw-r--r--kmail/managesievescriptsdialog.h55
-rw-r--r--kmail/managesievescriptsdialog_p.h27
-rw-r--r--kmail/mboxjob.cpp124
-rw-r--r--kmail/mboxjob.h61
-rw-r--r--kmail/messageactions.cpp260
-rw-r--r--kmail/messageactions.h106
-rw-r--r--kmail/messagecomposer.cpp2284
-rw-r--r--kmail/messagecomposer.h279
-rw-r--r--kmail/messagecopyhelper.cpp115
-rw-r--r--kmail/messagecopyhelper.h79
-rw-r--r--kmail/messageproperty.cpp173
-rw-r--r--kmail/messageproperty.h112
-rw-r--r--kmail/messagesender.h97
-rwxr-xr-xkmail/mh2kmail27
-rwxr-xr-xkmail/mh2kmailr29
-rw-r--r--kmail/networkaccount.cpp367
-rw-r--r--kmail/networkaccount.h142
-rw-r--r--kmail/newfolderdialog.cpp311
-rw-r--r--kmail/newfolderdialog.h79
-rw-r--r--kmail/objecttreeparser.cpp2872
-rw-r--r--kmail/objecttreeparser.h295
-rw-r--r--kmail/partNode.cpp612
-rw-r--r--kmail/partNode.h259
-rw-r--r--kmail/partmetadata.h64
-rw-r--r--kmail/partnodebodypart.cpp98
-rw-r--r--kmail/partnodebodypart.h74
-rw-r--r--kmail/pics/Makefile.am37
-rw-r--r--kmail/pics/attachmentQuicklistClosed.pngbin0 -> 727 bytes
-rw-r--r--kmail/pics/attachmentQuicklistOpened.pngbin0 -> 719 bytes
-rw-r--r--kmail/pics/enterprise_bottom.pngbin0 -> 182 bytes
-rw-r--r--kmail/pics/enterprise_bottom_left.pngbin0 -> 264 bytes
-rw-r--r--kmail/pics/enterprise_bottom_right.pngbin0 -> 275 bytes
-rw-r--r--kmail/pics/enterprise_icon.pngbin0 -> 10638 bytes
-rw-r--r--kmail/pics/enterprise_left.pngbin0 -> 190 bytes
-rw-r--r--kmail/pics/enterprise_right.pngbin0 -> 184 bytes
-rw-r--r--kmail/pics/enterprise_s_left.pngbin0 -> 359 bytes
-rw-r--r--kmail/pics/enterprise_s_right.pngbin0 -> 362 bytes
-rw-r--r--kmail/pics/enterprise_sbar.pngbin0 -> 218 bytes
-rw-r--r--kmail/pics/enterprise_sp_right.pngbin0 -> 1101 bytes
-rw-r--r--kmail/pics/enterprise_sw.pngbin0 -> 2385 bytes
-rw-r--r--kmail/pics/enterprise_top.pngbin0 -> 187 bytes
-rw-r--r--kmail/pics/enterprise_top_left.pngbin0 -> 263 bytes
-rw-r--r--kmail/pics/enterprise_top_right.pngbin0 -> 266 bytes
-rw-r--r--kmail/pics/enterprise_w.pngbin0 -> 7223 bytes
-rw-r--r--kmail/pics/icons/Makefile.am2
-rw-r--r--kmail/pics/icons/cr128-action-online_status.pngbin0 -> 14284 bytes
-rw-r--r--kmail/pics/icons/cr16-action-kmgroupware_folder_calendar.pngbin0 -> 904 bytes
-rw-r--r--kmail/pics/icons/cr16-action-kmgroupware_folder_contacts.pngbin0 -> 1059 bytes
-rw-r--r--kmail/pics/icons/cr16-action-kmgroupware_folder_journals.pngbin0 -> 963 bytes
-rw-r--r--kmail/pics/icons/cr16-action-kmgroupware_folder_notes.pngbin0 -> 866 bytes
-rw-r--r--kmail/pics/icons/cr16-action-kmgroupware_folder_tasks.pngbin0 -> 1025 bytes
-rw-r--r--kmail/pics/icons/cr16-action-mail_flag.pngbin0 -> 745 bytes
-rw-r--r--kmail/pics/icons/cr16-action-mail_ham.pngbin0 -> 661 bytes
-rw-r--r--kmail/pics/icons/cr16-action-mail_ignore.pngbin0 -> 903 bytes
-rw-r--r--kmail/pics/icons/cr16-action-mail_spam.pngbin0 -> 930 bytes
-rw-r--r--kmail/pics/icons/cr16-action-mail_todo.pngbin0 -> 910 bytes
-rw-r--r--kmail/pics/icons/cr16-action-online_status.pngbin0 -> 894 bytes
-rw-r--r--kmail/pics/icons/cr22-action-kmgroupware_folder_calendar.pngbin0 -> 1215 bytes
-rw-r--r--kmail/pics/icons/cr22-action-kmgroupware_folder_journals.pngbin0 -> 1564 bytes
-rw-r--r--kmail/pics/icons/cr22-action-kmgroupware_folder_tasks.pngbin0 -> 947 bytes
-rw-r--r--kmail/pics/icons/cr22-action-mail_ham.pngbin0 -> 769 bytes
-rw-r--r--kmail/pics/icons/cr22-action-mail_ignore.pngbin0 -> 1364 bytes
-rw-r--r--kmail/pics/icons/cr22-action-mail_spam.pngbin0 -> 1502 bytes
-rw-r--r--kmail/pics/icons/cr22-action-online_status.pngbin0 -> 1396 bytes
-rw-r--r--kmail/pics/icons/cr32-action-kmgroupware_folder_calendar.pngbin0 -> 1155 bytes
-rw-r--r--kmail/pics/icons/cr32-action-kmgroupware_folder_tasks.pngbin0 -> 1358 bytes
-rw-r--r--kmail/pics/icons/cr32-action-mail_ham.pngbin0 -> 1393 bytes
-rw-r--r--kmail/pics/icons/cr32-action-mail_ignore.pngbin0 -> 2202 bytes
-rw-r--r--kmail/pics/icons/cr32-action-mail_spam.pngbin0 -> 2512 bytes
-rw-r--r--kmail/pics/icons/cr32-action-online_status.pngbin0 -> 2350 bytes
-rw-r--r--kmail/pics/icons/cr48-action-online_status.pngbin0 -> 4204 bytes
-rw-r--r--kmail/pics/icons/crsc-action-mail_ignore.svgzbin0 -> 2309 bytes
-rw-r--r--kmail/pics/icons/crsc-action-online_status.svgzbin0 -> 6038 bytes
-rw-r--r--kmail/pics/kmmsgattachment.pngbin0 -> 529 bytes
-rw-r--r--kmail/pics/kmmsgdel.pngbin0 -> 545 bytes
-rw-r--r--kmail/pics/kmmsgencryptionproblematic.pngbin0 -> 442 bytes
-rw-r--r--kmail/pics/kmmsgflag.pngbin0 -> 568 bytes
-rw-r--r--kmail/pics/kmmsgforwarded.pngbin0 -> 277 bytes
-rw-r--r--kmail/pics/kmmsgfullyencrypted.pngbin0 -> 430 bytes
-rw-r--r--kmail/pics/kmmsgfullysigned.pngbin0 -> 456 bytes
-rw-r--r--kmail/pics/kmmsgham.pngbin0 -> 438 bytes
-rw-r--r--kmail/pics/kmmsgignored.pngbin0 -> 589 bytes
-rw-r--r--kmail/pics/kmmsgnew.pngbin0 -> 481 bytes
-rw-r--r--kmail/pics/kmmsgpartiallyencrypted.pngbin0 -> 312 bytes
-rw-r--r--kmail/pics/kmmsgpartiallysigned.pngbin0 -> 515 bytes
-rw-r--r--kmail/pics/kmmsgqueued.pngbin0 -> 282 bytes
-rw-r--r--kmail/pics/kmmsgread.pngbin0 -> 517 bytes
-rw-r--r--kmail/pics/kmmsgread_fwd.pngbin0 -> 432 bytes
-rw-r--r--kmail/pics/kmmsgread_fwd_replied.pngbin0 -> 406 bytes
-rw-r--r--kmail/pics/kmmsgread_replied.pngbin0 -> 418 bytes
-rw-r--r--kmail/pics/kmmsgreplied.pngbin0 -> 291 bytes
-rw-r--r--kmail/pics/kmmsgsent.pngbin0 -> 291 bytes
-rw-r--r--kmail/pics/kmmsgsignatureproblematic.pngbin0 -> 446 bytes
-rw-r--r--kmail/pics/kmmsgspam.pngbin0 -> 660 bytes
-rw-r--r--kmail/pics/kmmsgtodo.pngbin0 -> 910 bytes
-rw-r--r--kmail/pics/kmmsgundefinedencrypted.pngbin0 -> 415 bytes
-rw-r--r--kmail/pics/kmmsgundefinedsigned.pngbin0 -> 430 bytes
-rw-r--r--kmail/pics/kmmsgunseen.pngbin0 -> 396 bytes
-rw-r--r--kmail/pics/kmmsgwatched.pngbin0 -> 616 bytes
-rw-r--r--kmail/pics/kmwizard.pngbin0 -> 24546 bytes
-rw-r--r--kmail/pics/kmwizard.svg1875
-rw-r--r--kmail/pics/pgp-keys.pngbin0 -> 4165 bytes
-rw-r--r--kmail/pics/quotecollapse.pngbin0 -> 1142 bytes
-rw-r--r--kmail/pics/quoteexpand.pngbin0 -> 1149 bytes
-rw-r--r--kmail/popaccount.cpp1086
-rw-r--r--kmail/popaccount.h242
-rw-r--r--kmail/profiles/Makefile.am14
-rw-r--r--kmail/profiles/profile-default-rc.desktop180
-rw-r--r--kmail/profiles/profile-high-contrast-rc.desktop164
-rw-r--r--kmail/profiles/profile-html-rc.desktop109
-rw-r--r--kmail/profiles/profile-purist-rc.desktop129
-rw-r--r--kmail/profiles/profile-secure-rc.desktop136
-rw-r--r--kmail/protocols.h45
-rw-r--r--kmail/quotajobs.cpp147
-rw-r--r--kmail/quotajobs.h194
-rw-r--r--kmail/recipientseditor.cpp998
-rw-r--r--kmail/recipientseditor.h366
-rw-r--r--kmail/recipientseditortest.cpp112
-rw-r--r--kmail/recipientseditortest.h44
-rw-r--r--kmail/recipientspicker.cpp878
-rw-r--r--kmail/recipientspicker.h248
-rw-r--r--kmail/redirectdialog.cpp140
-rw-r--r--kmail/redirectdialog.h92
-rw-r--r--kmail/regexplineedit.cpp136
-rw-r--r--kmail/regexplineedit.h79
-rw-r--r--kmail/renamejob.cpp253
-rw-r--r--kmail/renamejob.h95
-rw-r--r--kmail/replyphrases.kcfg35
-rw-r--r--kmail/replyphrases.kcfgc5
-rw-r--r--kmail/rulewidgethandlermanager.cpp1520
-rw-r--r--kmail/rulewidgethandlermanager.h100
-rw-r--r--kmail/scalix.cpp104
-rw-r--r--kmail/scalix.h83
-rw-r--r--kmail/searchjob.cpp454
-rw-r--r--kmail/searchjob.h136
-rw-r--r--kmail/searchwindow.cpp946
-rw-r--r--kmail/searchwindow.h195
-rw-r--r--kmail/secondarywindow.cpp81
-rw-r--r--kmail/secondarywindow.h63
-rw-r--r--kmail/sieveconfig.cpp170
-rw-r--r--kmail/sieveconfig.h128
-rw-r--r--kmail/sievedebugdialog.cpp410
-rw-r--r--kmail/sievedebugdialog.h94
-rw-r--r--kmail/sievejob.cpp289
-rw-r--r--kmail/sievejob.h129
-rw-r--r--kmail/signatureconfigurator.cpp268
-rw-r--r--kmail/signatureconfigurator.h82
-rw-r--r--kmail/simplestringlisteditor.cpp307
-rw-r--r--kmail/simplestringlisteditor.h106
-rw-r--r--kmail/smimeconfiguration.ui413
-rw-r--r--kmail/snippetconfig.cpp25
-rw-r--r--kmail/snippetconfig.h61
-rw-r--r--kmail/snippetdlg.cpp108
-rw-r--r--kmail/snippetdlg.h42
-rw-r--r--kmail/snippetdlgbase.ui177
-rw-r--r--kmail/snippetitem.cpp154
-rw-r--r--kmail/snippetitem.h85
-rw-r--r--kmail/snippetsettings.cpp53
-rw-r--r--kmail/snippetsettings.h46
-rw-r--r--kmail/snippetsettingsbase.ui184
-rw-r--r--kmail/snippetwidget.cpp957
-rw-r--r--kmail/snippetwidget.h95
-rw-r--r--kmail/spamheaderanalyzer.cpp157
-rw-r--r--kmail/spamheaderanalyzer.h90
-rw-r--r--kmail/stl_util.h47
-rw-r--r--kmail/subscriptiondialog.cpp444
-rw-r--r--kmail/subscriptiondialog.h156
-rw-r--r--kmail/teehtmlwriter.cpp98
-rw-r--r--kmail/teehtmlwriter.h71
-rw-r--r--kmail/templateparser.cpp1093
-rw-r--r--kmail/templateparser.h90
-rw-r--r--kmail/templatesconfiguration.cpp561
-rw-r--r--kmail/templatesconfiguration.h75
-rw-r--r--kmail/templatesconfiguration_base.ui332
-rw-r--r--kmail/templatesconfiguration_kfg.kcfg43
-rw-r--r--kmail/templatesconfiguration_kfg.kcfgc5
-rw-r--r--kmail/templatesinsertcommand.cpp402
-rw-r--r--kmail/templatesinsertcommand.h61
-rw-r--r--kmail/tests/Makefile.am23
-rw-r--r--kmail/tests/messagedicttests.cpp79
-rw-r--r--kmail/tests/messagedicttests.h30
-rw-r--r--kmail/tests/mimelibtests.cpp117
-rw-r--r--kmail/tests/mimelibtests.h44
-rw-r--r--kmail/tests/multipartmixed.mbox10
-rw-r--r--kmail/tests/signedmail.mbox111
-rw-r--r--kmail/tests/storagelayermodule.cpp16
-rw-r--r--kmail/tests/utiltests.cpp207
-rw-r--r--kmail/tests/utiltests.h30
-rw-r--r--kmail/textsource.cpp65
-rw-r--r--kmail/textsource.h46
-rw-r--r--kmail/tips78
-rw-r--r--kmail/transportmanager.cpp68
-rw-r--r--kmail/transportmanager.h42
-rw-r--r--kmail/undostack.cpp157
-rw-r--r--kmail/undostack.h72
-rwxr-xr-xkmail/upgrade-signature.pl63
-rwxr-xr-xkmail/upgrade-transport.pl36
-rw-r--r--kmail/urlhandlermanager.cpp597
-rw-r--r--kmail/urlhandlermanager.h88
-rw-r--r--kmail/util.cpp194
-rw-r--r--kmail/util.h222
-rw-r--r--kmail/vacation.cpp729
-rw-r--r--kmail/vacation.h89
-rw-r--r--kmail/vacationdialog.cpp195
-rw-r--r--kmail/vacationdialog.h82
-rw-r--r--kmail/vcardviewer.cpp96
-rw-r--r--kmail/vcardviewer.h58
-rw-r--r--kmail/warningconfiguration.ui408
-rw-r--r--kmail/xfaceconfigurator.cpp285
-rw-r--r--kmail/xfaceconfigurator.h64
578 files changed, 162849 insertions, 0 deletions
diff --git a/kmail/COMMITPOLICY b/kmail/COMMITPOLICY
new file mode 100644
index 00000000..5ebb56a0
--- /dev/null
+++ b/kmail/COMMITPOLICY
@@ -0,0 +1,13 @@
+KMail policy is decided by the KMail decision making group according
+to the KMail decision making process, as was decided on the kde-core
+development list and is reflected by the state of the KMail about
+box.
+
+The KMail decision making group consists of all KMail core developers,
+including maintainers. The decision making process is as follows:
+
+In the result of a conflict over a commit to the KMail section of KDE
+CVS a resolution to this conflict, that is the decision to keep or
+revert the commit can be decided by a unanimous agreement of the
+maintainers, or failing that a resolution to the conflict will be
+decided by a vote of KMail core developers.
diff --git a/kmail/ChangeLog b/kmail/ChangeLog
new file mode 100644
index 00000000..e9c2eaa1
--- /dev/null
+++ b/kmail/ChangeLog
@@ -0,0 +1,806 @@
+
+NOTE: This file is out of date. For a detailed list of changes
+please visit http://webcvs.kde.org
+
+2000-05-17 George Staikos <staikos@kde.org>
+ * Updated the authors list
+ * Added Stefan's external filter code and modified it somewhat
+ * bugfixes on size parameter again.
+
+2000-05-14 George Staikos <staikos@0wned.org>
+
+ * Forward now forwards ALL headers if ALL headers are set
+
+2000-05-12 George Staikos <staikos@0wned.org>
+
+ * Added an optional column for message size
+ * Created a context menu item for "Save As"
+ * Fixed various typos
+ * Created welcome message on inbox creation
+
+2000-03-25 Sven Radej <radej@kde.org>
+
+ * Removed old signal-driven "IPC" and introduced DCOP interface
+ kmailIface.h gets installed in include directory
+ * new class KMKernel, holds all previously static objects
+ (to access them, instead of "yourObject->something()" use
+ "kmkernel->yourObject()->something()"
+
+2000-02-28 Mario Weilguni <mario@weilguni.net>
+
+ * Corrected wrong shortcut in menu "File/&Filter"
+ * Added mini-icon to several subwindows of kmail
+ * Removed those ugly password dialogs with some
+ more modern and style one.
+
+2000-02-02 George Staikos <staikos@0wned.org> (KMail-1.1.35)
+ Mail Sending
+ * External editor support
+ * Confirm before send
+ * Attach custom mime headers
+
+ POP3
+ * Settings entry for the POP3 timer
+
+ Security
+ * Changed tpmnam to mkstemp
+
+ General
+ * New mail received notification
+ * Sigfile editor
+
+2000-02-02 Jacek Stolarczyk <jacek@mer.chemia.polsl.gliwice.pl>
+ Settings
+ * Ported createPushButton, createLabeledEntry and addLabeledWidget
+ from char* to QString&. It was causing problems for passing
+ already internationalized strings. In cPB i18n() was unnecessarily
+ called for the second time.
+
+1999-12-15 Don Sanders <sanders@kde.org> (KMail-1.1.32)
+
+ General
+ * Cache number of unread messages
+ * Added auto synchronization logic for correcting count of unread
+ messages.
+ * Added support for customizing colors in all three panes. (Currently
+ have to restart kmail for this to take effect due to HTML widget
+ renovations).
+ * Added support for customizing fonts and font sizes in all three
+ panes. (Currently have to restart kmail for this to take effect due
+ to HTML widget renovations). Fixed width fonts starting working too.
+ * Ported all the changes made to KMail 1.0.x.
+ * Ported KMail to QT 2.1 and KDE 2 kdelibs (that is it runs and works
+ now rather than just compiling)
+
+ Privacy
+ * Committed patch by "J. Nick Koston" <bdraco@darkorb.net> to add
+ support for GNU Privacy Guard.
+
+ Filter Dialog
+ * Various buttons are enabled/disabled depending on whether they can
+ be used.
+ * Filter title is updated as the user enters filter details
+ * Fix a bug where changes could be lost when changing priority of
+ new filter.
+ * List of folders supports nested folders by indentation.
+
+ Folder Tree Window
+ * Nested folder support.
+ * Improved DnD support (hover opening, auto scrolling, highlight
+ destination folder while dragging).
+ * Show count of unread messages in different color after the folder
+ name.
+
+ Headers Window
+ * Ported kmheaders to QListView.
+ * Sorting is now done by QListView, this means the index file on
+ doesn't have to be updated, all sorting is done in main memory
+ (much faster). This also seems to have eliminated the lingering
+ problem of missorted mail.
+ * Implemented support for Shift and Ctrl selection and DnD.
+ * Show DnD cursor while dragging even in headers window.
+ * Eliminated flicker when changing folder.
+ * Speed up folder changing by reusing QListViewItems.
+ * When sorting always use the date as the second priority sorting key
+ * Added indicator in header for current sort column and direction.
+ * Eliminated needless gui updating when changing status, copying or
+ moving messages. This speeds up these operations a lot.
+ * Fixed problem with different date format being shown for current
+ message.
+
+ Reader Window
+ * Committed patched by Daniel Naber <dnaber@mini.gt.owl.de> that
+ fixes problem with messges with attachments and no text part.
+ * Lars Knoll ported the Reader Window to the new html widget. This
+ widget is still under construction (somethings haven't been
+ reimplemented yet)
+ * Show messages of type text/html as html (For Wired news etc).
+ * Added slight delay to updating reader window and so that holding
+ down the next/prev message key wouldn't cause the header window to
+ become out of sync with the reader window.
+
+ Folder Settings Dialog
+ * Simplified by removing account related stuff.
+ * Added support for reparenting via combobox.
+
+ Pixmaps
+ * Converted the pixmaps to png (expect for kdelogo which wasn't
+ looking right).
+ * New folder pixmaps contributed by
+ Greg Newton <gregnewton@netscape.net>
+
+ Composer Window
+ * Added undo/redo menu items. (Sent patch to support undo/redo in
+ QMultiLineEdit to Trolls)
+ * Updated KMail to use the new improved word wrapping in QMultiLineEdit
+ (no more signature munching).
+ * Set date of sent messages to current sent time rather than creation
+ time.
+
+ Message class
+ * Worked with Jacek Stolarczyk <jacek@mer.chemia.polsl.gliwice.pl> to
+ fix bug that was preventing KMail from working on Alpha Architecture.
+
+ Folder class
+ * Added extra protection so mail won't be lost if the disk was full.
+ * Fixed problem with unfiltered mail being lost with the help of
+ Bob Bernstein <ruptured-duck@home.com> and dep <dep@snet.net>
+
+1999-12-04 Stefan Taferner <taferner@kde.org> (KMail-1.1.31)
+
+ * Implemented bouncing of mails. Hopefully this will help
+ to fool spammers ;-)
+
+1999-10-10 Stefan Taferner <taferner@kde.org> (KMail-1.1.25)
+
+ * Switched folder-tree widget to QListView. Currently
+ drag&drop of messages is therefore broken.
+ * Added support for subdirectories in ~/Mail -> hierarchical
+ folders!
+ * Changed ancient folder edit/create dialog to something
+ more useful.
+
+1999-02-21 Stefan Taferner <taferner@kde.org>
+
+ * Added extra ungrabbing of pointer and keyboard to avoid
+ locking problems when many message windows pop up.
+
+1999-02-10 Stefan Taferner <taferner@kde.org> (KMail-1.1.1)
+
+ * Bugfix: new/unread messages that are displayed upon selecting
+ of a folder are now properly displayed as read.
+
+ * Bugfix: filter-dialog: up/down moving (esp. of last entry)
+ now works properly
+
+1999-02-06 Stefan Taferner <taferner@kde.org> (KMail-1.1.0)
+
+ * Added missing parts of documentation for proper install.
+
+1999-02-06 Sven Radej <radej@kde.org> (KMail-1.0.17)
+
+ * Server-client method - no more locking problems, lost instead
+ of sent mail, ghost messages...
+ Do the right thing when sending to "me@there (John Doe)"
+ Waldo's folderless-acount-segv-fix
+ More against destroyed last char in message
+ Better long/normal folder-list geometry bugfix
+ Don't quit while sending, and show a label while you send.
+
+1999-02-03 Sven Radej <radej@kde.org> (KMail-1.0.16)
+
+ * Bugfix: possible segv-on-create-folder. Reciever is properly
+ shown (index design & version updated) in sent&queued mail.
+ Fix agains overwriting last char in last message when appending
+ new one to folder.
+
+1999-01-30 Stefan Taferner <taferner@kde.org> (KMail-1.0.16)
+
+ * Removed obsolete / commented-out code.
+
+ * Bugfix: KMail now properly handles the 'filename' attribute
+ of message parts in the reader (Bug #445).
+
+1999-01-29 Stefan Taferner <taferner@kde.org> (KMail-1.0.15)
+
+ * Bugfix: disabled deleting of system folders.
+
+ * Removed save button in composer which is still not
+ implemented ;->
+
+ * Bugfix: disabled renaming of system folders (inbox, outbox,
+ sent-mails, trash).
+
+ * Fix: improved performance when displaying messages (Bug #148).
+
+ * Bugfix: fixed crash when dropping message on directory
+ entry in folder list.
+
+ * Improved: email completion of composer (Ctrl-t) now
+ searches for appearance of given characters in addressbook's
+ list. Up to now only used beginning of string.
+
+ * Added missing i18n() around "Spellcheck complete" in
+ composer.
+
+ * Bugfix: Added %_ in composer settings, e.g. for indentation
+ template, to add a space at the end. Added %f which expands
+ to the two first characters of the name in the email address.
+
+ * Bugfix: Indentation template (see composer settings) now
+ supports the same wildcards as the other fields, e.g. "%f>%_"
+
+1999-01-28 Stefan Taferner <taferner@kde.org>
+
+ * Bugfix: kmail hangs when sending large messages via
+ SMTP. Actually was a performance issue with QRegExp.
+
+ * Bugfix: main window was hidden upon press of Ok button
+ in settings dialog.
+
+1999-01-25 Stefan Taferner <taferner@kde.org>
+
+ * Bugfix: 'From' column did not update new text at
+ first.
+
+1999-01-23 Stefan Taferner <taferner@kde.org> (KMail-1.0.14)
+
+ * New feature: layout can now be switched between
+ "long folder list" and "short folder list". Option
+ setable in settings->appearance.
+
+ * New feature: the "From" column now contains the
+ receiver for the folders outbox and sent-mail. Column
+ "Sender" automatically switches it's title to "Receiver"
+ for these folders.
+
+ * Incorporated new documentation.
+
+1999-01-21 Stefan Taferner <taferner@kde.org> (KMail-1.0.13)
+
+ * Fixed broken placement of contents in settings dialog.
+
+ * Filter Dialog: changed combo box style to new style.
+ Now it is possible to have more folders than the screen
+ is high and still select them in the filter dialog.
+ * Filter Dialog: changed folder combo box to (semi) auto
+ resize. Changed layout of dialog to better display all
+ elements. Also enabled vertical resizing of dialog.
+
+1999-01-17 Stefan Taferner <taferner@kde.org> (KMail-1.0.12)
+
+ Patches from Michael Teske <mteske@c-s-k.de>:
+ * Fixed broken retrieve-all for pop accounts.
+ * Fixed broken marking of new mails as New.
+
+1999-01-01 Stefan Taferner <taferner@kde.org> (KMail-1.0.11)
+
+ * Hopefully pgp zombies are fixed now.
+ * Applied patch for fixing problems with some inline
+ encoding switchings.
+
+1998-12-21 Stefan Taferner <taferner@kde.org>
+
+ Applied several patches from Lars Heete <hel@admin.de>:
+ * missing deletion of drop zone in composer destructor
+ * handling of NULL status field in message base
+ * reading process status of finished pgp process to avoid
+ zombies ;-)
+ * workaround for "Could not load..." warnings, that should
+ rather be debug messages, in message handler
+
+1998-12-20 Stefan Taferner <taferner@kde.org> (KMail-1.0.10)
+
+ * Fixed possible crash when subject is empty.
+
+1998-12-17 Juraj Bednar <bednar@isternet.sk>
+
+ * Added the capatability to insert arbitary public keys from public
+ keyring. (PGP)
+
+1998-12-16 Stefan Taferner <taferner@kde.org> (KMail-1.0.9)
+
+ * Switched busy pointer (if not animated) and hand cursor
+ to new KCursor class.
+
+ * Headers: status of message is now set to read also for
+ messages that are displayed when the folder is opened.
+
+1998-12-07 Stefan Taferner <taferner@kde.org>
+
+ * Updated documentation
+
+1998-12-06 Stefan Taferner <taferner@kde.org>
+
+ * Added i18n() around label in folder list.
+
+1998-12-03 Stefan Taferner <taferner@kde.org> (KMail-1.0.8)
+
+ * New messages: added organization to message header
+ if given.
+
+ * Headers: position of top message in folder list is
+ stored and reused upon next opening. Exception: if there
+ is a new or unread message in the folder, then the
+ first new/unread message is shown.
+
+ * Composer: fixed missing last character in replies.
+
+ * Composer: attachments are now included in forwards.
+
+1998-11-24 Stefan Taferner <taferner@kde.org>
+
+ * Pop: does not stop pop retrieval now when pop server does
+ not understand LAST command.
+
+1998-11-15 Stefan Taferner <taferner@kde.org> (KMail-1.0.7)
+
+ * Headers: now current message is not reset when reading mails
+ and checking for new messages meanwhile.
+
+ * Pop: added configuration option for leave-mail-on-server.
+
+ * Pop: Fixed problems in pop authentication code.
+
+ * Pop: Enabled POP3 LAST command which was committed to
+ kdesupport some time ago.
+
+1998-11-15 Alex Zepeda <garbanzo@hooked.net>
+
+ * kfontutils.cpp (kfontToStr): Cast two const char *'s to char *'s as
+ egcs seems to barf without the casts.
+
+1998-11-10 Harri Porten <porten@kde.org>
+
+ * Removed hardcoded localkdedir()
+
+ * Let KApplication() do the job of creating ~/.kde/share/config
+
+1998-10-31 Stefan Taferner <taferner@kde.org> (KMail-1.0.6)
+
+ * Fixed: crash when fetching new mail and inbox folder
+ is not accessible.
+
+1998-10-21 Lars Knoll <knoll@mpi-hd.mpg.de>
+ * fixed a bug in the support for pgp-2.6
+
+1998-10-08 Stefan Taferner <taferner@kde.org> (KMail-1.0.5)
+
+ * Sorting messages: replaced sorting algorithm, which caused
+ random hangs, with stock qsort -- hopefully working now ;-)
+
+ * Fixed: folder list went out of scope (current item pointing to
+ nowhere) when folder was deleted.
+
+ * Composer: fixed broken confirm-close dialog.
+
+ * Increased version to better match upcoming Kde-1.1 release.
+
+ * Added call to kapp->quit() when last window is closed.
+
+1998-10-05 Lars Knoll <knoll@mpi-hd.mpg.de>
+ * Added new pgp classes. They should fix a lot of problems
+ with the current support of pgp5.0 and pgp2.6, and fix all
+ security problems with the old versions of kpgp, since all
+ comunication with pgp (including the passphrase) is done via
+ pipes.
+
+1998-09-26 Stefan Taferner <taferner@kde.org> (KMail-0.8.1)
+
+ * Fixed crash upon close of a main- or composer window.
+ Bug seems to be introduced by changed behaviour of KTMainWindow.
+ Still KMail crashes when you click on any message afterwards.
+
+ * Addressbook: finally fixed bug in not reading last line.
+ Thanks to all who reported!
+
+ * Replaced occurrences of KTopLevelWidget with KTMainWindow.
+
+1998-09-21 Markus Wuebben <markus@office.DInet.de>
+
+ * added a short cut for mail checking
+
+1998-09-12 Markus Wuebben <markus@kde.org>
+
+ * some nice little fixes
+
+1998-09-11 Juraj Bednar <bednar@isternet.sk>
+
+ * finally wrote PGP replying and forwarding decryption
+ * PGP 5.0i should work now with no problems (should ;-)
+
+Sun Sep 6 19:20:34 1998 Markus Wuebben <mason@HoneyBunny.uni-dortmund.de>
+
+ * kmacctpop.cpp (setPasswd): Fixed password problem.
+
+Sun Sep 6 18:28:45 1998 Markus Wuebben <markus@kde.org>
+
+ * kmreaderwin.cpp : Finally fixed attachment problem
+
+1998-07-31 Markus Wuebben <markus@kde.org>
+
+ * kmsettings.cpp / kmmainwin.cpp Implemented send mail on check.
+ * kmacctlocal.cpp (processNewMail): Added message box
+ warning if mail folder was not found.
+
+ * kmmainwin.cpp Added editing of message in outbox folder.
+ * kmfolderdlg.cpp Removed out of index warning
+
+
+1998-07-23 Stefan Taferner <taferner@kde.org>
+
+ * Added message status "Read". This status is set to
+ messages which are loaded with check-mail that have
+ status set to "R".
+
+ These messages appear whith blue text, but without
+ the green ball to the left, in the message list.
+
+1998-07-22 Markus Wuebben <markus@kde.org>
+
+ * main.cpp Applied session management patch.
+ * kmfolder.cpp Applied fseek patch for solaris
+
+1998-07-03 Stefan Taferner <taferner@kde.org>
+
+ * PGP: fixed crash when no ~/.pgp/pubring.pgp is installed
+ and signed message is selected.
+
+1998-06-30 Stefan Taferner <taferner@kde.org> (KMail-0.7.9)
+
+ * PGP: removed dialog asking for pass phrase when only
+ signed message was given, added missing asking for pass
+ phrase when encrypted/signed message is sent.
+
+ * Composer: fixed bug that showed busy pointer all the
+ time with auto-append-signature set and no signature file
+ given.
+
+ * Composer: removed mSendImmediate which seems unused
+ in the composer nowadays. Simplified code of slotSend,
+ slotSendNow, and slotSendLater (to be easier consistent).
+
+1998-06-29 Stefan Taferner <taferner@kde.org> (KMail-0.7.8)
+
+ * Config: writeConfig() was not called when windows
+ got closed. Now it is.
+
+1998-06-27 Markus Wuebben <markus@kde.org>
+
+ * kmcomposewin.cpp (applyChanges): add false to applyChanges to
+ avoid segfault on ALPHAs.
+
+1998-06-24 Stefan Taferner <taferner@kde.org>
+
+ * Pgp detection simplified and bugfixed.
+
+ * Folder status messages for index creation and
+ compacting folder reduced from every 100th to every 10th.
+
+1998-06-23 Markus Wuebben <markus@kde.org> (KMail-0.7.7)
+
+ * removed various unnecessary assert()s. and replaced them
+ with if()s. Especially in functions that return void this
+ is very helpfull and makes kmail more stable.
+
+ * Checked return values with if()s for some functions to
+ make sure that we run into to trouble with those problems.
+
+1998-06-23 Stefan Taferner <taferner@kde.org> (KMail-0.7.7)
+
+ * Removed lots of old debug messages.
+
+ * Composer: answering the confirmation is no longer
+ ignored.
+
+ * Finetuning: added missing pixmaps to makefile and
+ repainted pixmap for queued and sent messages.
+
+ * Composer: changed behaviour of email completion a bit.
+ Now it is possible to add multiple recipients with comma
+ separated and complete also those after the first one.
+ Drawback: email addresses with comma in them are not
+ handled properly currently.
+
+ * Pop leave-on-server: due to the fact that we need another
+ field in the pop settings dialog "download-all-msgs"
+ the leave-on-server checkbox currently also toggles
+ the download-all-msgs feature.
+ So: download-all-msgs = !leave-on-server
+
+ * Folders are now marked red after download if they
+ contain new or unread messages. As a feature, folders
+ that receive old messages are not marked.
+
+ * Fixed problems in pop code downloading old messages
+ also. The "download" dialog is a bit misleading because
+ it should say now "checking message:" instead of
+ "downloading message:" because old messages are counted
+ here also.
+
+1998-06-22 Markus Wuebben <markus@kde.org> (KMail-0.7.6)
+
+ * fixed a whole bunch of stuff that made kmail segfault.
+
+1998-06-21 Mario Weilguni <mweilguni@kde.org>
+
+ * small fix for quicker response in kmnewiostatus.cpp
+
+ * "Delete folder" dialog now defaults to "No" (compliant to
+ KDE standards)
+
+1998-06-20 Markus Wuebben <markus@kde.org>
+
+ * kmsender.cpp (cleanup): Fixed the sendQueued problem.
+ If only one message from the outbox couldnt get sent all
+ following messages got deleted from the outbox. This is fixed now.
+
+
+1998-06-19 Stefan Taferner <taferner@kde.org> (KMail-0.7.6)
+
+ * Folder: fixed broken locking on systems without
+ flock(). Thanks to Werner Ertle <wer@christl.hl.siemens.de>
+ who sent me the patch.
+
+1998-06-18 Stefan Taferner <taferner@kde.org> (KMail-0.7.5)
+
+ * Deleting folders crashed kmail. Fixed.
+
+ * Folder-compacting: added busy pointer and progress
+ output in the status bar (idea from Mario).
+
+ * Reader: removed ':' from the characters that mark
+ quoted text to catch smileys at the beginning of the
+ line ;-)
+
+ * Main window configuration (geometry, etc.) is now
+ stored again.
+
+ * Composer: changed completion key from Ctrl-. to Ctrl-T
+ as kfile has.
+
+1998-06-18 Mario Weilguni <mweilguni@kde.org>
+
+ * Dialog for folder selection: Escape now closes dialog,
+ remembers last folder, has a default pushbutton
+
+1998-06-17 Stefan Taferner <taferner@kde.org> (KMail-0.7.4)
+
+ * Message-list: now the first unread/new message is
+ displayed when opening a folder.
+
+ * Message-status: now messages change status from
+ "new" to "unread" when the user changes folder (and
+ not when the folder is closed somewhere within KMail).
+
+ * Reader: worked around problem of current HTML widget
+ with long lines (without '\n')
+
+1998-06-16 Stefan Taferner <taferner@kde.org> (KMail-0.7.3)
+
+ * Headers: Improved switching between folders to do
+ less paints to avoid flickering where possible.
+
+ * Warnings: changed warning messages of QPixmap and
+ QPainter to debug messages to avoid lots of message
+ boxes from broken KToolbar code when changing color
+ scheme.
+
+ * Composer (email-address-completion)
+ Changed email-address completion to be case insensitive.
+ I think this is more useful in the general case.
+
+ * Composer: fixed broken Tab handling. Replaced
+ Tab-completion in the email-address header lines
+ (To, From, Cc, etc.) with Ctrl-. completion.
+
+ * Filters: removed some debug statements that slowed
+ down filtering a lot.
+
+ * kmmsgbase.cpp: added isUnread() method.
+
+ * Message-list: improved next/prev_unread_message methods.
+ Improved code that ensures that current item is visible
+ and added it to several places in the headers code.
+
+1998-06-15 Stefan Taferner <taferner@kde.org>
+
+ * kmfilteraction.cpp (process): Removed patch for kmfilter
+ action "Move" of 1998-06-14.
+ Fixed bug in kmfilteraction "Move" action.
+
+ * Fonts: reader- and composer-window now change
+ their font when the settings are changed.
+
+ * Shutdown: improved handling of window-close and
+ KMail shutdown- and crash-handling.
+
+
+1998-06-14 Markus Wuebben <markus@kde.org>
+
+ * kmfilteraction.cpp (process): Applied patch for kmfilter
+ actionmove.
+
+1998-06-13 Mario Weilguni <mweilguni@kde.org> (KMail-0.7.2)
+
+ * key for next_unread_message and prev_unread_message added
+
+1998-06-12 Stefan Taferner <taferner@kde.org>
+
+ * Folder loading: moved status message in index
+ creation to a more suitable place. Should be lots
+ faster now.
+
+ * Composer: Now path of last filedialog for attachments
+ is stored.
+
+ * Fonts: improved font settings. The HTML widget
+ unfortunately only honors the font family. Added new
+ functions (kfontutils.h) for easy font to/from string
+ conversion.
+
+1998-06-12 Mario Weilguni <mweilguni@kde.org> (KMail-0.7.1)
+ * new sort algorithm - quicksort instead of bubble-sort
+
+1998-06-11 Stefan Taferner <taferner@kde.org> (KMail-0.7.0)
+
+ * Initial start now opens the settings dialog. Don't
+ be alerted, this will happen once for everybody now ;-)
+
+ * Fonts: implemented font setting for HTML widget,
+ list of messages, and composer.
+
+ * Drag&Drop: implemented drag&drop of messages to
+ folders. Dropping into HTML widget crashes KMail.
+ Could be a bug of the HTML widget, however.
+
+ * Move-message: improved folder selection dialog.
+
+ * Message-list: now cleared properly when the current
+ folder is deleted.
+
+1998-06-11 Markus Wuebben <markus@kde.org> (KMail-0.6.9)
+
+ * KMail now uses KFileDialog only!
+
+1998-06-11 Mario Weilguni <mweilguni@kde.org> (KMail-0.6.9)
+
+ * "P" and "N" (next and previous mail) will cause the header
+ list to be scrolled if the new item is not visible
+
+ * fixed some code to prevent compiler warning
+
+ * panner position is now (again) restored
+
+1998-06-07 Stefan Taferner <taferner@kde.org> (KMail-0.6.8)
+
+ * Folders: changed message about index-recreation
+ to debug from warning.
+
+ * Message/Headers: Email addresses like <joe@home.org>
+ (with the <> around the address) no longer lead to
+ an empty field in the message list.
+
+ * Headers: Removed extra space in header line(s).
+
+ * Headers: Empty Subject moved From and Date one column
+ left. Fixed (hopefully).
+
+ * Composer: Send again did not decode quoted-printable
+ sent messages. Fixed.
+
+ * PGP: KMail did not ask for mantra upon first reading of
+ an encrypted message. Applied patch, from Michael Vogel
+ <icarus@hades.pop-celle.de>, which hopefully works :-)
+
+1998-05-13 Stefan Taferner <taferner@kde.org> (KMail-0.6.7)
+
+ * Filters: Bugfix: when deleting a folder that was the target
+ of a filter the next get-mails crashed.
+
+ * Filter Dialog: Deleting filter rules did not work. Fixed.
+
+1998-05-09 Markus Wuebben <markus@kde.org>
+
+ * kmsettings.cpp (KMAccountSettings):
+ Fixed "Delete mail from server". The row was too low.
+ * kmmainwin.cpp
+ Added a single account mail check option.
+
+1998-04-29 Markus Wuebben <markus@kde.org>
+
+ * Reader: Fixed the url parsing which made kmail
+ loop.
+
+1998-04-28 Stefan Taferner <taferner@kde.org> (KMail-0.6.6)
+
+ * Folders: Emptying of the trash folder resulted in an infinite
+ loop. Fixed now.
+
+1998-04-04 Stefan Taferner <taferner@kde.org> (Kde Beta-4)
+
+ * Filters: Removed warning dialog. Filters are working ok for
+ me for several weeks now.
+
+ * Folders: After I finally also deleted lots of important messages
+ by mistake I now changed the behaviour of Folder->Empty to
+ move the messages into trash instead of deleting them ;-)
+ This made the "Are you sure" dialog now obsolete, IMO.
+
+1998-03-31 Stefan Taferner <taferner@kde.org> (KMail-0.6.5)
+
+ * Folders: fixed bug introduced on 1998-03-26: open failed on
+ folders where lock() returned an error.
+
+1998-03-28 Stefan Taferner <taferner@kde.org>
+
+ * Headers: when opening a folder the contents was not automatically
+ sorted, now is.
+
+ * Pop: new messages retrieved from pop accounts were not
+ marked new. Now fixed.
+
+1998-03-26 Stefan Taferner <taferner@kde.org>
+
+ * Folders: when opening and locking a folder there were
+ cases (in fact most of the time) when the folder seemed
+ to be not locked but was. Now this is handled better.
+
+1998-03-24 Stefan Taferner <taferner@kde.org> (KMail-0.6.4)
+
+ * Message: decoding of quoted-printable RFC1522 strings
+ was broken for strings that started with a decoded character.
+
+1998-03-18 Stefan Taferner <taferner@kde.org>
+
+ * Reader: improved detection of urls and email addresses
+ to ignore special characters at the end, e.g. "." or ")".
+
+ * Messagelist: finally fixed sorting of messages. Also
+ implemented ascending/descending/none sorting (use multiple
+ clicks on the column headers to switch). Sorting order "none"
+ is what was IMO missing for the trash folder :-)
+
+1998-03-17 Stefan Taferner <taferner@kde.org> (KMail-0.6.3)
+
+ * Composer: in menu view, when 'all headers' view is
+ activated, then the individual header line menu entries are
+ disabled now.
+
+ * Folders: changed creation of folders to -rw-------
+ instead of the default -rw-r--r--. Same for the initial
+ creation of ~/Mail.
+
+ * Attachments: temporary files (when viewing attachments)
+ are now also created with permissions -rw-------.
+
+1998-03-15 Stefan Taferner <taferner@kde.org> (KMail-0.6.2)
+
+ * Startup: added option -check which does mail checking
+ upon startup. Also options that start with a '-' but which
+ are unknown are now skipped.
+
+1998-03-09 Stefan Taferner <taferner@kde.org> (KMail-0.6.1)
+
+ * Reader: '_' was not considered part of a smart-detected email
+ address (auto detection of @).
+
+ * Reader: attachments of type message/rfc822 are now shown
+ in an external reader window if open or view from the attachment
+ popup menu is chosen.
+
+ * Composer: finally got insertion of tabs into message
+ working.
+
+(many changes are missing here, sorry)
+
+1998-02-14 Stefan Taferner <taferner@kde.org>
+
+ * Startup: when recovering dead letters the auto signature was
+ appended twice. Fixed now.
+
+ * Composer: fixed broken inserting of files.
+
+ * kFileToString(): fixed handling of files with zero length.
+
+Initial version: 0.5.7
diff --git a/kmail/DESIGN b/kmail/DESIGN
new file mode 100644
index 00000000..0d2c93c4
--- /dev/null
+++ b/kmail/DESIGN
@@ -0,0 +1 @@
+The contents of this file are now to be found and added to in Mainpage.dox.
diff --git a/kmail/KMail.desktop b/kmail/KMail.desktop
new file mode 100644
index 00000000..52e31f0e
--- /dev/null
+++ b/kmail/KMail.desktop
@@ -0,0 +1,93 @@
+[Desktop Entry]
+Name=KMail
+Name[eo]=Retpoŝto
+Name[hi]=के-मेल
+Name[lv]=KPasts
+Name[mk]=КПошта
+Name[ne]=केडीई मेल
+Name[pa]=ਕੇ-ਪੱਤਰ
+Name[sv]=Kmail
+Name[ta]=Kஅஞ்சல்
+Name[th]=จัดการจดหมาย - K
+Name[zh_TW]=KMail 郵件軟體
+Type=Application
+Exec=kmail -caption "%c" %i %m
+Icon=kmail
+DocPath=kmail/index.html
+GenericName=Mail Client
+GenericName[af]=E-pos kliënt
+GenericName[ar]=زبون البريد
+GenericName[az]=Poçt Alıcısı
+GenericName[be]=Паштовы кліент
+GenericName[bg]=Пощенски клиент
+GenericName[br]=Kliant postel
+GenericName[bs]=Program za čitanje elektronske pošte
+GenericName[ca]=Client de correu
+GenericName[cs]=Klient pro čtení elektronické pošty
+GenericName[cy]=Dibynnydd Ebost
+GenericName[da]=E-mail-klient
+GenericName[de]=Mail-Programm
+GenericName[el]=Πελάτης mail
+GenericName[eo]=Legi kaj sendi retpoŝton
+GenericName[es]=Cliente de correo
+GenericName[et]=E-posti klient
+GenericName[eu]=Posta bezeroa
+GenericName[fa]=کارخواه‌نامه
+GenericName[fi]=Sähköpostiohjelma
+GenericName[fr]=Logiciel de messagerie électronique
+GenericName[fy]=E-portclient
+GenericName[ga]=Cliant Ríomhphoist
+GenericName[gl]=Cliente de correo
+GenericName[he]=לקוח דוא"ל
+GenericName[hi]=डाकिया
+GenericName[hr]=Program za čitanje elektronske pošte
+GenericName[hu]=Levelezőprogram
+GenericName[id]=Klien Mail
+GenericName[is]=Póstforrit
+GenericName[it]=Programma di posta elettronica
+GenericName[ja]=メールクライアント
+GenericName[ka]=ფოსტის კლიენტი
+GenericName[kk]=Эл.пошта клиент бағдарламасы
+GenericName[km]=កម្មវិធី​អ៊ីមែល
+GenericName[lt]=Pašto klientas
+GenericName[lv]=Pasta Klients
+GenericName[mk]=Клиент за електронска пошта
+GenericName[ms]=Pelanggan Mel
+GenericName[mt]=Klijent tal-imejl
+GenericName[nb]=E-postklient
+GenericName[nds]=Nettpostprogramm
+GenericName[ne]=मेल क्लाइन्ट
+GenericName[nl]=E-mailclient
+GenericName[nn]=E-postklient
+GenericName[pa]=ਪੱਤਰ ਕਲਾਂਇਟ
+GenericName[pl]=Program pocztowy
+GenericName[pt]=Cliente de E-mail
+GenericName[pt_BR]=Cliente de E-mail
+GenericName[ro]=Program de poştă electronică
+GenericName[ru]=Почтовый клиент
+GenericName[rw]=Umukiriya w'Ubutumwa
+GenericName[se]=E-boastaprográmma
+GenericName[sk]=Poštový klient
+GenericName[sl]=Poštni odjemalec
+GenericName[sr]=Поштански клијент
+GenericName[sr@Latn]=Poštanski klijent
+GenericName[sv]=E-postklient
+GenericName[ta]=அஞ்சல் பயனர்
+GenericName[tg]=Клиенти почтавӣ
+GenericName[th]=ไคลเอนต์จดหมายอิเล็กทรอนิกส์
+GenericName[tr]=E-posta İstemcisi
+GenericName[uk]=Поштовий клієнт
+GenericName[uz]=Xat-xabar klienti
+GenericName[uz@cyrillic]=Хат-хабар клиенти
+GenericName[ven]=Mushumisani na poso
+GenericName[xh]=Umxhasi Weposi
+GenericName[zh_CN]=邮件客户程序
+GenericName[zh_TW]=收發信軟體
+GenericName[zu]=Imeyili Yomthengi
+Terminal=false
+
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+X-DCOP-ServiceName=kmail
+ServiceTypes=DCOP/ResourceBackend/IMAP,DCOP/Mailer
+Categories=Qt;KDE;Network;Office;Email;
diff --git a/kmail/Mainpage.dox b/kmail/Mainpage.dox
new file mode 100644
index 00000000..0b15ebfb
--- /dev/null
+++ b/kmail/Mainpage.dox
@@ -0,0 +1,871 @@
+/** \mainpage KMail architectural overview
+
+\section KMail design principles
+
+This file is intended to guide the reader's way through the KMail
+codebase. It should esp. be handy for people not hacking full-time on
+KMail as well as people that want to trace bugs in parts of KMail
+which they don't know well.
+
+Contents:
+- Kernel
+- Identity
+- Filters
+- ConfigureDialog
+- MDNs
+- Folders
+- Index
+- Headers
+- Display
+
+TODO: reader, composer, messages, accounts, ...
+
+\section kernel KERNEL
+
+Files: kmkernel.h, kmkernel.cpp
+
+Contact Zack Rusin <zack@kde.org> with questions...
+
+The first thing you'll notice about KMail is the extensive use of
+kmkernel->xxx() constructs. The "kmkernel" is a define in kmkernel.h
+declared as :
+#define kmkernel KMKernel::self()
+KMKernel is the central object in KMail. It's always created before
+any other class, therefore you are _guaranteed_ that KMKernel::self()
+(and therefore "kmkernel" construct) won't return 0 (null).
+
+KMKernel implements the KMailIface (our DCOP interface) and gives
+access to all the core KMail functionality.
+
+
+\section identity IDENTITY
+
+FIXME this has moved to libkpimidentities, right?
+
+Files: identity*, kmidentity.{h,cpp}, configuredialog.cpp,
+ signatureconfigurator.{h,cpp}
+
+Contact Marc Mutz <mutz@kde.org> on questions...
+
+Identities consists of various fields represented by
+QStrings. Currently, those fields are hardcoded, but feel free to
+implement KPIM::Identity as a map from strings to QVariants or somesuch.
+
+One part of identities are signatures. They can represent four modes
+(Signature::Type) of operation (disabled, text from file or command
+and inline text), which correspond to the combo box in the
+identitydialog.
+
+Identities are designed to be used through the KPIM::IdentityManager:
+const KPIM::Identity & ident =
+ kmkernel->identityManager()->identityForUoidOrDefault(...)
+Make sure you assign to a _const_ reference, since the identityForFoo
+methods are overloaded with non-const methods that access a different
+list of identities in the manager that is used while configuring. That
+is known source of errors when you use identityForFoo() as a parameter
+to a method taking const KPIM::Identity &.
+
+WARNING: Don't hold the reference longer than the current functions
+scope or next return to the event loop. That's b/c the config dialog
+is not modal and the user may hit apply/ok anytime between calls to
+function that want to use the identity reference. Store the UOID
+instead if you need to keep track of the identity. You may also want
+to connect to one of the KPIM::IdentityManager::changed() or ::deleted()
+signals, if you want to do special processing in case the identity
+changes.
+
+Thus, in the ConfigureDialog, you will see non-const KPIM::Identity
+references being used, while everywhere else (KMMessage,
+IdentityCombo) const references are used.
+
+The KPIM::IdentityCombo is what you see in the composer. It's a
+self-updating combo box of KPIM::Identity's. Use this if you want the user
+to choose an identity, e.g. in the folder dialog.
+
+Ihe IdentityListView is what you see in the config dialog's identity
+management page. It's not meant to be used elsewhere, but is DnD
+enabled (well, at the time of this writing, only drag-enabled). This
+is going to be used to dnd identities around between KNode and KMail,
+e.g.
+
+The SignatureConfigurator is the third tab in the identity
+dialog. It's separate since it is used by the identity manager to
+request a new file/command if the current value somehow fails.
+
+
+
+\section filter FILTER
+
+Contact Marc Mutz <mutz@kde.org> on questions...
+
+Filters consist of a search pattern and a list of actions plus a few
+flags to indicate when they are to be applied (kmfilter.h).
+ They are managed in a QPtrList<KMFilter>, called KMFilterMgr. This
+filter magnager is responsible for loading and storing filters
+(read/writeConfig) and for executing them (process). The unique
+instance of the filter manager is held by the kernel
+(KMKernel::filterMgr()).
+
+The search pattern is a QPtrList of search rules (kmsearchpattern.h) and a
+boolean operator that defines their relation (and/or).
+
+A search rule consists of a field-QString, a "function"-enum and a
+"contents" or "value" QString. The first gives the header (or
+pseudoheader) to match against, the second says how to match (equals,
+consists, is less than,...) and the third holds the pattern to match
+against.
+ Currently, there are two types of search rules, which are mixed
+together into a single class: String-valued and int-valued. The latter
+is a hack to enable \verbatim<size>\endverbatim and
+\verbatim<age in days>\endverbatim pseudo-header matching.
+ KMSearchRules should better be organized like KMFilterActions are.
+
+A filter action (kmfilteraction.h) inherits from KMFilterAction or one
+of it's convenience sub-classes. They have three sub-interfaces: (1)
+argument handling, (2) processing and (3) parameter widget handling.
+ Interface (1) consists of args{From,As}String(), name() and
+isEmpty() and is used to read and write the arguments (if any) from/to
+the config.
+ Interface (2) is used by the filter manager to execute the action
+(process() / ReturnCode).
+ Interface (3) is used by the filter dialog to allow editing of
+actions and consists of name(), label() and the
+*ParamWidget*(). Complex parameter widgets are collected in
+kmfawidget.{h,cpp}.
+
+A typical call for applying filters is
+
+KMKernel::filterMgr()
+foreach message {
+ KMFilterMgr::process():
+}
+
+
+\section configuration CONFIGURE DIALOG
+
+Files: configuredialog*.{h,cpp} ( identitylistview.{h,cpp} )
+
+Contact Marc Mutz <mutz@kde.org> on questions...
+
+The configuredialog is made up of pages that in turn may consist of a
+number of tabs. The genral rule of thumb is that each page and tab is
+responsible for reading and writing the config options presented on
+it, although in the future, that may be reduced to interacting with
+the corresponding config manager instead. But that won't change the
+basic principle.
+
+Thus, there is an abstract base class ConfigurePage (defined in
+configuredialog_p.h), which derives from QWidget. It has four methods
+of which you have to reimplement at least the first two:
+
+- void setup()
+ Re-read the config (from the config file or the manager) and update
+ the widgets correspondingly. That is, you should only create the
+ widgets in the ctor, not set the options yet. The reason for that is
+ that the config dialog, once created, is simply hidden and shown
+ subsequently, so we need a reset-like method anyway.
+
+- void apply()
+ Read the config from the widgets and write it into the config file
+ or the corresponding config manager.
+
+- void installProfile()
+ This is called when the user selected a profile and hit apply. A
+ profile is just another KConfig object. Therefore, this method
+ should be the same as setup(), except that you should only alter
+ widgets for configs that really exist in the profile.
+
+For tabbed config pages, there exists a convenience class called
+TabbedConfigurationPage, which (as of this writing only offers the
+addTab() convenience method. It is planned to also provide
+reimplementations of setup, dismiss, apply and installProfile that just
+call the same functions for each tab.
+
+\section mdn MDNs
+
+Files: libkdenetwork/kmime_mdn.{h,cpp} and kmmessage.{h,cpp}, mostly
+
+Contact Marc Mutz <mutz@kde.org> on questions...
+
+MDNs (Message Disposition Notifications; RFC 2298) are a way to send
+back information regarding received messages back to their
+sender. Examples include "message read/deleted/forwarded/processed".
+
+The code in kmime_mdn.{h,cpp} is responsible for creating the
+message/disposition-notification body part (2nd child of
+multipart/report that makes the MDN) and for providing the template
+for human-readable text that goes into the text/plain part (1st child
+of the multipart/report).
+
+The code in KMMessage::createMDN() actually constructs a message
+containing a MDN for this message, using the kmime_mdn helper
+functions. It starts by checking the index for an already sent MDN,
+since the RFC demands that MDNs be sent only once for every
+message. If that test succeeds, it goes on to check various other
+constraints as per RFC and if all goes well the message containing the
+multipart/report is created.
+
+If you need to use this functionality, see KMReaderWin::touchMsg() and
+KMFilterAction::sendMDN() for examples. The touchMsg() code is invoked
+on display of a message and sends a "displayed" MDN back (if so
+configured), whereas the KMFilterAction method is a convenience helper
+for the various filter actions that can provoke a MDN (move to trash,
+redirect, forward, ...).
+
+
+\section folders Folders
+
+Files: kmfolder*.{h,cpp}, folderstorage.{h,cpp} and *job.{h,cpp}
+
+Contact Zack Rusin <zack@kde.org> with questions...
+
+The collaboration among KMail folder classes looks
+as follows :
+
+ KMFolderNode
+ / \
+ / \
+ KMFolderDir \
+ KMFolder
+ .
+ .
+ v
+ FolderStorage
+ |
+ |
+ KMFolderIndex
+ |
+ |
+ ---< actual folder types: KMFolderImap, KMFolderMbox... >--
+
+At the base KMail's folder design starts with KMFolderNode which
+inherits QObject. KMFolderNode is the base class encapsulating
+common folder properties such as the name and a boolean signifying whether
+the folder is a folder holding mail directly or a KMFolderDir.
+KMFolderNode's often do not have an on-disk representation, they are
+entities existing only within KMail's design.
+
+KMFolder acts as the runtime representation of a folder with the physical
+storage part being represented by a member of type FolderStorage.
+KMFolder and FolderStorage have many functions with the same names and
+signatures, but there is no inheritance.
+KMFolderIndex contains some common indexing functionality for physical folders.
+Subclasses of KMFolderIndex finally interact directly with physical storage
+or with storage providers over the network.
+
+KMFolderDir is a directory abstraction which holds KMFolderNode's.
+It inherits KMFolderNode and KMFolderNodeList which is a QPtrList<KMFolderNode>.
+A special case of a KMFolderDir is KMFolderRootDir; it represents
+the toplevel KMFolderDir in KMail's folder hierarchy.
+
+KMFolderDir's contents are managed by KMFolderMgr's.
+KMail contains three main KMFolderMgr's. They can be
+accessed via KMKernel ( the "kmkernel" construct ). Those methods are :
+1) KMFolderMgr *folderMgr() - which returns the folder manager for
+ the folders stored locally.
+2) KMFolderMgr *imapFolderMgr() - which returns the folder manager
+ for all imap folders. They're handled a little differently because
+ for all imap messages only headers are cached locally while the
+ main contents of all messages is kept on the server.
+3) KMFolderMgr *dimapFolderMgr() - which returns disconnected IMAP (dimap)
+ folder manager. In dimap, both the headers and a copy of the full message
+ are cached locally.
+4) KMFolderMgr *searchFolderMgr() - which returns the folder manager
+ for search folders (folders created by using the "find
+ messages" tool). Other email clients call this type of folder
+ "virtual folders".
+
+FolderJob classes - These classes allow asynchronous operations on
+KMFolder's. You create a Job on the heap, connect to one of its
+signals and wait for the job to finish. Folders serve as FolderJob
+factories. For example, to retrieve the full message from a folder
+you do :
+
+FolderJob *job = folderParent->createJob( aMsg, tGetMessage );
+connect( job, SIGNAL(messageRetrieved(KMMessage*)),
+ SLOT(msgWasRetrieved(KMMessage*)) );
+job->start();
+
+
+\section index Index (old)
+
+Files: kmfolderindex.{h,cpp} and kmmsg{base,info}.{h,cpp}
+
+Contact Marc Mutz <mutz@kde.org> or
+ Till Adam <adam@kde.org> or
+ Don Sanders <sanders@kde.org>
+with questions...
+
+ index := header *entry
+
+
+ header := magic LF NUL header-length byte-order-marker sizeof-long
+
+ magic := "# KMail-Index V" 1*DIGITS
+
+ header-length := Q_UINT32
+
+ byte-order-marker := Q_UINT32( 0x12345678 )
+
+ sizeof-long := Q_UINT32( 4 / 8 )
+
+
+ entry := tag length value
+
+ tag := Q_UINT32 ; little endian (native?)
+
+ length := Q_UINT16 ; little endian (native?)
+
+ value := unicode-string-value / ulong-value
+
+ unicode-string-value := 0*256QChar ; network-byte-order
+
+ ulong-value := unsigned_long ; little endian
+
+Currently defined tag values are:
+
+ Msg*Part num. val type obtained by:
+
+ No 0 u -
+ From 1 u fromStrip().stripWhitespace()
+ Subject 2 u subject().stripWhitespace()
+ To 3 u toStrip().stripWhiteSpace()
+ ReplyToIdMD5 4 u replyToIdMD5().stripWhiteSpace()
+ IdMD5 5 u msgIdMD5().stripWhiteSpace()
+ XMark 6 u xmark().stripWhiteSpace()
+ Offset 7 l folderOffset() (not only mbox!)
+ LegacyStatus 8 l mLegacyStatus
+ Size 9 l msgSize()
+ Date 10 l date()
+ File 11 u fileName() (not only maildir!)
+ CryptoState 12 l (signatureState() << 16) | encryptionState())
+ MDNSent 13 l mdnSentState()
+ ReplyToAuxIdMD5 14 u replyToAuxIdMD5()
+ StrippedSubject 15 u strippedSubjectMD5().stripWhiteSpace()
+ Status 16 l status()
+
+ u: unicode-string-value; l: ulong-value
+
+Proposed new (KDE 3.2 / KMail 1.6) entry format:
+
+ index := header *entry
+
+ entry := sync 1*( tag type content ) crc-tag crc-value
+
+ sync := Q_UINT16 (32?) ; resync mark, some magic bit pattern
+ ; (together with preceding crc-tag provides
+ ; 24(40)bits to resync on in case of index
+ ; corruption)
+
+ tag := Q_UINT8
+
+ type := Q_UINT8
+
+ content := variable-length-content / fixed-length-content
+
+ crc-tag := tag type ; tag=CRC16, type=CRC16
+
+ crc-value := Q_UINT16 ; the CRC16 sum is calculated over all of
+ ; 1*( tag type content )
+
+ variable-length-content := length *512byte padding
+
+ padding := *3NUL ; make the string a multiple of 4 octets in length
+
+ fixed-length-content := 1*byte
+
+ length := Q_UINT16 (Q_UINT8?)
+
+ byte := Q_UINT8
+
+The type field is pseudo-structured:
+
+bit: 7 6 5 4 3 2 1 0
+ +-----+-----+-----+-----+-----+-----+-----+-----+
+ | uniq | chunk | len |
+ +-----+-----+-----+-----+-----+-----+-----+-----+
+
+uniq: 3 bits = max. 8 different types with same chunk size:
+
+ for chunk = (0)00 (LSB(base)=0: octets):
+ 00(0) Utf8String
+ 01(0) BitField
+ 10(0) reserved
+ 11(0) Extend
+
+ for chunk = (1)00 (LSB(base)=1: 16-octet blocks):
+ 00(1) MD5(Hash/List)
+ 01(1) reserved
+ 10(1) reserved
+ 11(1) Extend
+
+ for chunk = 01 (shorts):
+ 000 Utf16String
+ 001-110 reserved
+ 111 Extend
+
+ for chunk = 10 (int32):
+ 000 Utf32String (4; not to be used yet)
+ 001 Size32
+ 010 Offset32
+ 011 SerNum/UOID
+ 100 DateTime
+ 101 Color (QRgb: (a,r,g,b))
+ 110 reserved
+ 111 Extend
+
+ for chunk = 11 (int64):
+ 000 reserved
+ 001 Size64
+ 010 Offset64
+ 011-110 reserved
+ 111 Extend
+
+len: length in chunks
+ 000 (variable width -> Q_UINT16 with the real width follows)
+ 001..111: fixed-width data of length 2^len (2^1=2..2^6=128)
+
+You find all defined values for the type field in indexentrybase.cpp
+
+Currently defined tags are:
+
+ tag type content
+
+ DateSent DateTime Date:
+ DateReceived DateTime last Received:'s date-time
+ FromDisplayName String decoded display-name of first From: addr
+ ToDisplayName String dto. for To:
+ CcDisplayName String dto. for Cc:
+ FromAddrSpecs String possibly IMAA-encoded, comma-separated addr-spec's of From:
+ ToAddrSpecs String dto. for To:
+ CcAddrSpecs String dto. for Cc:
+ Subject String decoded Subject:
+ BaseSubjectMD5 String md5(utf8(stripOffPrefixes(subject())))
+ BodyPeek String body preview
+ MaildirFile String Filename of maildir file for this messagea
+ MBoxOffset Offset(64) Offset in mbox file (pointing to From_)
+ MBoxLength Size(64) Length of message in mbox file (incl. From_)
+ Size Size(64) rfc2822-size of message (in mbox: excl. From_)
+ Status BitField (see below)
+ MessageIdMD5 MD5Hash MD5Hash of _normalized_ Message-Id:
+ MDNLink SerialNumber SerNum of MDN received for this message
+ DNSLink SerialNumber SerNUm of DSN received for this message
+ ThreadHeads SerialNumberList MD5Hash's of all (so far discovered)
+ _top-level thread parents_
+ ThreadParents SerialNumberList MD5Hash's of all (so far discovered)
+ thread parents
+
+
+ "String" is either Utf8String or (Utf16String or Latin1String),
+ depending on content
+
+Currently allocated bits for the Status BitField are:
+
+ Bit Value: on(/off) (\\imapflag)
+
+ # "std stati":
+ 0 New (\\Recent)
+ 1 Read (\\Seen)
+ 2 Answered (\\Answered)
+ 3 Deleted (\\Deleted)
+ 4 Flagged (\\Flagged)
+ 5 Draft (\\Draft)
+ 6 Forwarded
+ 7 reserved
+
+ # message properties:
+ 8 HasAttachments
+ 9 MDNSent ($MDNSent)
+ 10..11 00: unspecified, 01: Low, 10: Normal, 11: High Priority
+ 12..15 0001: Queued, 0010: Sent, 0011: DeliveryDelayed,
+ 0100: Delivered, 0101: DeliveryFailed,
+ 0110: DisplayedToReceiver, 0111: DeletedByReceiver,
+ 1001: ProcessedByReceiver, 1010: ForwardedByReceiver,
+ 1011-1110: reserved
+ 1111: AnswerReceived
+
+ # signature / encryption state:
+ 16..19 0001: FullyEncrypted, 0010: PartiallyEncrypted, 1xxx: Problem
+ 20..23 0001: FullySigned, 0010: PartiallySigned, 1xxx: Problem
+
+ # "workflow stati":
+ 24..25 01: Important, 10: ToDo, 11: Later (from Moz/Evo)
+ 26..27 01: Work, 10: Personal, 11: reserved (dto.)
+ 28..29 01: ThreadWatched, 10: ThreadIgnored, 11: reserved
+ 30..31 reserved
+
+All bits and combinations marked as reserved MUST NOT be altered if
+set and MUST be set to zero (0) when creating the bitfield.
+
+
+\section headers Headers (Threading and Sorting)
+
+Contact Till Adam <adam@kde.org> or
+ Don Sanders <sanders@kde.org>
+with questions...
+
+Threading and sorting is implemented in kmheaders.[cpp|h] and headeritem.[cpp|h]
+and involves a handfull of players, namely:
+
+class KMHeaders:
+ this is the listview that contains the subject, date etc of each mail.
+ It's a singleton, which means there is only one, per mainwidget headers
+ list. It is actually a member of KMMainwidget and accessible there.
+
+class HeaderItem:
+ these are the [Q|K]ListViewItem descendend items the KMHeaders listview
+ consists of. There's one for each message.
+
+class SortCacheItem:
+ these are what the threading and sorting as well as the caching of those
+ operate on. Each is paired with a HeaderItem, such that each holds a
+ pointer to one, and vice versa, each header item holds a pointer to it's
+ associated sort cache item.
+
+.sorted file:
+ The order of the sorted and threaded (if threading is turned on for this
+ folder) messages is cached on disk in a file named .$FOLDER.index.sorted
+ so if, for example the name of a folder is foo, the associated sorting
+ cache file would be called ".foo.index.sorted".
+ For each message, its serial number, that of its parent, the length of its
+ sorting key, and the key itself are written to this file. At the start of
+ the file several per folder counts and flags are cached additionally,
+ immediately after a short file headers. The entries from the start of the
+ file are:
+ - "## KMail Sort V%04d\n\t" (magic header and version string)
+ - byteOrder flag containing 0x12345678 for byte order testing
+ - column, the sort column used for the folder
+ - ascending, the sort direction
+ - threaded, is the view threaded or is it not?
+ - appended, have there been items appended to the file (obsolete?)
+ - discovered_count, number of new mail discovered since the last sort file
+ generation
+ - sorted_count, number of sorted messages in the header list
+
+What is used for figuring out threading?
+ - messages can have an In-Reply-To header that contains the message id of
+ another message. This is called a perfect parent.
+ - additionally there is the References header which, if present, holds a
+ list of message ids that the current message is a follow up to. We
+ currently use the second to last entry in that list only. See further
+ down for the reasoning behind that.
+ - If the above two fail and the message is prefixed (Re: foo, Fwd: foo etc.)
+ an attempt is made to find a parent by looking for messages with the same
+ subject. How that is done is explained below as well.
+
+ For all these comparisons of header contents, the md5 hashes of the headers
+ are used for speed reasons. They are stored in the index entry for each
+ message. All data structures described below use md5 hash strings unless
+ stated otherwise.
+
+Strategy:
+ When a folder is opened, updateMessageList is called, which in turn calls
+ readSortOrder where all the fun happens. If there is a .sorted file at the
+ expected location, it is openend and parsed. The header flags are read in
+ order to figure out the state in which this .sorted file was written. This
+ means the sort direction, whether the folder is threaded or not etc.
+ FIXME: is there currently sanity checking going on?
+ Now the file is parsed and for each message in the file a SortCacheItem is
+ created, which holds the offset in the .sorted file for this message as well
+ as it's sort key as read from the file. That sort cache item is entered into
+ the global mSortCache structure (member of the KMHeaders instance), which is
+ a QMemArray<SortCacheItem *> of the size mFolder->count(). Note that this
+ is the size reported by the folder, not as read from the .sorted file. The
+ mSortCache (along with some other structures) is updated when messages are
+ added or removed. More on that further down.
+ As soon as the serial number is read from the file, that number is looked up
+ in the message dict, to ensure it is still in the current folder. If not, it
+ has been moved away in the meantime (possibly by outside forces such as
+ other clients) and a deleted counter is incremented and all further
+ processing stopped for this message.
+ The messages parent serial number, as read from the sorted file is then
+ used to look up the parent and reset it to -1 should it not be in the
+ current folder anymore. -1 and -2 are special values that can show up
+ as parent serial numbers and are used to encode the following:
+ -1 means this message has no perfect parent, a parent for it needs to
+ be found from among the other messages, if there is a suitable one
+ -2 means this message is top level and will forever stay so, no need
+ to even try to find a parent. This is also used for the non-threaded
+ case. These are messages that have neither an In-Reply-To header nor
+ a References header and have a subject that is not prefixed.
+ In case there is a perfect parent, the current sort cache item is
+ appended to the parents list of unsorted children, or to that of
+ root, if there is not. A sort cache item is created in the mSortCache
+ for the parent, if it is not already there. Messages with a parent of
+ -1 are appended to the "unparented" list, which is later traversed and
+ its elements threaded. Messages with -2 as the parent are children of
+ root as well, as noted above, and will remain so.
+
+ Once the end of the file is reached, we should have a nicely filled
+ mSortCache, containing a sort cache item for each message that was in the
+ sorted file. Messages with perfect parents know about them, top level
+ messages know about that as well, all others are on a list and will be
+ threaded later.
+
+ Now, what happens when messages have been added to the store since the last
+ update of the .sorted file? Right, they don't have a sort cache item yet,
+ and would be overlooked. Consequently all message ids in the folder from 0
+ to mFolder->count() are looked at and a SortCacheItem is created for the
+ ones that do not have one yet. This is where all sort cache items are created
+ if there was no sorted file. The items created here are by definition un-
+ sorted as well as unparented. On creation their sort key is figured out as
+ well.
+
+ The next step is finding parents for those messages that are either new, or
+ had a parent of -1 in the .sorted file. To that end, a dict of all sort
+ cache items indexed by the md5 hash of their messsage id headers is created,
+ that will be used for looking up sort cache items by message id. The list of
+ yet unparented messages is then traversed and findParent() called for each
+ element wihch checks In-Reply-To and References headers and looks up the
+ sort cache item of those parents in the above mentioned dict. Should none be
+ found, the item is added to a second list the items of which will be subject
+ threaded.
+
+ How does findParent() work, well, it tries to find the message pointed to by
+ the In-Reply-To header and if that fails looks for the one pointed to by the
+ second to last entry of the References header list. Why the second to last?
+ Imagine the following situation in Bob's kmail:
+ - Bob get's mail from Alice
+ - Bob replies to Alice's mail, but his mail is stored in the Outbox, not the
+ Inbox.
+ - Alice replies again, so Bob now has two mails from Alice which are part of
+ the same thread. The mail in the middle is somewhere else. We want that to
+ thread as follows:
+ Bob <- In-Reply-To: Alice1
+ ============
+ Alice1
+ |_Alice <- In-Reply-To: Bob (not here), References: Alice, Bob
+
+ - since the above is a common special case, it is worth trying. I think. ;)
+
+ If the parent found is perfect (In-Reply-To), the sort cache items is marked
+ as such. mIsImperfectlyThreaded is used for that purposer, we will soon see
+ why that flag is needed.
+
+ On this first pass, no subject threading is attempted yet. Once it is done,
+ the messages that are now top-level, the current thread heads, so to speak,
+ are collected into a second dict ( QDict< QPtrList< SortCacheItem > > )
+ that contains for each different subject an entry holding a list of (so far
+ top level) messages with that subject, that are potential parents for
+ threading by subjects. These lists are sorted by date, so the parent closest
+ by date can be chosen. Sorting of these lists happens via insertion sort
+ while they are built because not only are they expected to be short (apart
+ from hard corner cases such as cvs commit lists, for which subject threading
+ makes little sense anyhow and where it should be turned off), but also since
+ the messages should be roughly pre sorted by date in the store already.
+ Some cursory benchmarking supports that assumption.
+ If now a parent is needed for a message with a certain subject, the list of
+ top level messages with that subject is traversed and the first one that is
+ older than our message is chosen as it's parent. Parents more than six weeks
+ older than the message are not accepted. The reasoning being that if a new
+ message with the same subject turns up after such a long time, the chances
+ that it is still part of the same thread are slim. The value of six weeks
+ is chosen as a result of a poll conducted on #kde-devel, so it's probably
+ bogus. :) All of this happens in the aptly named: findParentBySubject().
+
+ Everthing that still has no parent after this ends up at toplevel, no further
+ attemp is made at finding one. If you are reading this because you want to
+ implement threading by body search or somesuch, please go away, I don't like
+ you. :)
+
+ Ok, so far we have only operated on sort cache items, nothing ui wise has
+ happened yet. Now that we have established the parent/child relations of all
+ messages, it's time to create HeaderItems for them for use in the header
+ list. But wait, you say, what about sorting? Wouldn't it make sense to do
+ that first? Exactly, you're a clever bugger, ey? Here, have a cookie. ;)
+ Both creation of header items and sorting of the as of yet unsorted sort
+ cache items happen at the same time.
+
+ As previously mentioned (or not) each sort cache item holds a list of its
+ sorted and one of its unsorted children. Starting with the root node the
+ unsorted list is first qsorted, and then merged with the list of already
+ sorted children. To achieve that, the heads of both lists are compared and
+ the one with the "better" key is added to the list view next by creating a
+ KMHeaderListItem for it. That header item receives both its sort key as well
+ as its id from the sort cache item. Should the current sort cache item have
+ children, it is added to the end of a queue of nodes to repeat these steps
+ on after the current level is sorted. This way, a breadth first merge sort
+ is performed on the sort cache items and header items are created at each
+ node.
+
+ What follows is another iteration over all message ids in the folder, to
+ make sure that there are HeaderItems for each now. Should that not be the
+ case, top level emergency items are created. This loop is also used to add
+ all header items that are imperfectly threaded to a list so they can be
+ reevalutated when a new message arrives. Here the reverse mapping from
+ header items to sort cache items are made as well. Those are also necessary
+ so the sort cache item based data structures can be updated when a message
+ is removed.
+
+ The rest of readSortOrder should make sense on itself, I guess, if not, drop
+ me an email.
+
+What happens when a message arrives in the folder?
+ Among other things, the msgAdded slot is called, which creates the necessary
+ sort cache item and header item for the new message and makes sure the data
+ structures described above are updated accordingly. If threading is enabled,
+ the new message is threaded using the same findParent and findParentBySubject
+ methods used on folder open. If the message ends up in a watched or ignored
+ thread, those status bits are inherited from the parent. The message is also
+ added to the dict of header items, the index of messages by message id and,
+ if applicable and if the message is threaded at top level, to the list of
+ potential parents for subject threading.
+
+ After those house keeping tasks are performed, the list of as of yet imper-
+ fectly threaded messages is traversed and our newly arrived message is
+ considered as a new parent for each item on it. This is especially important
+ to ensure that parents arriving out of order after their children still end
+ up as parents. If necessary, the entries in the .sorted file of rethreaded
+ messages are updated. An entry for the new message itself is appended to the
+ .sorted file as well.
+
+ Note that as an optimization newly arriving mail as part of a mailcheck in
+ an imap folder is not added via msgAdded, but rather via complete reload of
+ the folder via readSortOrder(). That's because only the headers are gotten
+ for each mail on imap and that is so fast, that adding them individually to
+ the list view is very slow by comparison. Thus we need to make sure that
+ writeSortOrder() is called whenever something related to sorting changes,
+ otherwise we read stale info from the .sorted file. The reload is triggered
+ by the folderComplete() signal of imap folders.
+
+What happens when a message is removed from the folder?
+ In this case the msgRemoved slot kicks in and updates the headers list. First
+ the sort cache item and header item representing our message are removed from
+ the data structures and the ids of all items after it in the store decre-
+ mented. Then a list of children of the message is assembled containing those
+ children that have to be reparented now that our message has gone away. If
+ one of those children has been marked as toBeDeleted, it is simply added to
+ root at top level, because there is no need to find a parent for it if it is
+ to go away as well. This is an optimization to avoid rethreading all
+ messages in a thread when deleting several messages in a thread, or even the
+ whole thread. The KMMoveCommand marks all messages that will be moved out of
+ the folder as such so that can be detected here and the useless reparenting
+ can be avoided. Note that that does not work when moving messages via filter
+ action.
+
+ That list of children is then traversed and a new parent found for each one
+ using, again, findParent and findParentBySubject. When a message becomes
+ imperfectly threaded in the process, it is added to the corresponding list.
+
+ The message itself is removed from the list of imperfectly threaded messages
+ and its header item is finally deleted. The HeaderItem destructor destroys
+ the SortCacheItem as well, which is hopefully no longer referenced anywhere
+ at this point.
+
+
+
+\section display DISPLAY (reader window - new)
+
+ Contact Marc Mutz <mutz@kde.org> with questions...
+
+What happens when a message is to displayed in the reader window?
+ First, since KMMessagePart and KMMessage don't work with nested body
+ parts, a hierarchical tree of MIME body parts is constructed with
+ partNode's (being wrappers around KMMessagePart and
+ DwBodyPart). This is done in KMReaderWin::parseMsg(KMMessage*).
+ After some legacy handling, an ObjectTreeParser is instantiated and
+ it's parseObjectTree() method called on the root
+ partNode. ObjectTreeParser is the result of an ongoing refactoring
+ to enhance the design of the message display code. It's an
+ implementation of the Method Object pattern, used to break down a
+ huuuge method into many smaller ones without the need to pass around
+ a whole lot of paramters (those are made members
+ instead). parseObjectTree() recurses into the partNode tree and
+ generates an HTML representation of each node in the tree (although
+ some can be hidden by setting them to processed beforehand or - the
+ new way - by using AttachmentStrategy::Hidden). The HTML generation
+ is delegated to BodyPartFormatters, while the HTML is written to
+ HTMLWriters, which abstract away HTML sinks. One of those is
+ KHTMLPartHTMLWriter, which writes to the KHTMLPart in the
+ readerwindow. This is the current state of the code. The goal of the
+ ongoing refactoring is to make the HTML generation blissfully
+ ignorant of the readerwindow and to allow display plugins that can
+ operate against stable interfaces even though the internal KMail
+ classes change dramatically.
+
+ To this end, we designed a new set of interfaces that allows plugins
+ to be written that need or want to asynchronously update their HTML
+ representation. This set of interfaces consists of the following:
+
+ - @em BodyPartFormatterPlugin
+ the plugin base class. Allows the BodyPartFormatterFactory to
+ query it for an arbitray number of BodyPartFormatters and
+ their associated metadata and url handlers.
+
+ - @em BodyPartFormatter
+ the formatter interface. Contains a single method format()
+ that takes a BodyPart to process and an HTMLWriter to write the
+ generated HTML to and returns a result code with which it can
+ request more information or delegate the formatting back to
+ some default processor. BodyPartFormatters are meant to be
+ Flyweights, implying that the format() method is not allowed
+ to maintain state between calls, but see Mememto below.
+
+ - @em BodyPart
+ body part interface. Contains methods to retrieve the content
+ of a message part and some of the more interesting header
+ information. This interface decouples the bodypart formatters
+ from the implementation used in KMail (or KNode, for that
+ matter). Also contains methods to set and retrieve a Memento,
+ which is used by BodyPartFormatters to maintain state between
+ calls of format().
+
+ - @em BodyPartMemento
+ interface for opaque state storage and event handling.
+ Contains only a virtual destructor to enable the backend
+ processing code to destroy the object without the help of the
+ bodypart formatter.
+
+
+During the design phase we identified a need for BodyPartFormatters to
+request their being called on some form of events, e.g. a dcop
+signal. Thus, the Memento interface also includes the IObserver and
+ISubject interfaces. If a BodyPartFormatter needs to react to a signal
+(Qt or DCOP), it implements the Memento interface using a QObject,
+connects the signal to a slot on the Memento and (as an ISubject)
+notifies it's IObservers when the slot is called. If a Memento is
+created, the reader window registers itself as an observer of the
+Memento and will magically invoke the corresponding BodyPartFormatter,
+passing along the Memento to be retrieved from the BodyPart interface.
+
+An example should make this clearer. Suppose, we want to update our
+display after 10 seconds. Initially, we just write out an icon, and
+after 10 seconds, we want to replace the icon by a "Hello world!"
+line. The following code does exactly this:
+
+@code
+class DelayedHelloWorldBodyPartFormatter
+ : public KMail::BodyPartFormatter {
+public:
+ Result format( KMail::BodyPart * bodyPart,
+ KMail::HTMLWriter * htmlWriter ) {
+ if ( !bodyPart->memento() ) {
+ bodyPart->registerMemento( new DelayedHelloWorldBodyPartMemento() );
+ return AsIcon;
+ } else {
+ htmlWriter->write( "Hello, world!" );
+ return Ok;
+ }
+ }
+};
+
+class DelayedHelloWorldBodyPartMemento
+ : public QObject, public KMail::BodyPartMemento {
+public:
+ DelayedHelloWorldBodyPartMemento()
+ : QObject( 0, "DelayedHelloWorldBodyPartMemento" ),
+ KMail::BodyPartMemento()
+ {
+ QTimer::singleShot( 10*1000, this, SLOT(slotTimeout()) );
+ }
+
+private slots:
+ void slotTimeout() { notify(): }
+
+private:
+ // need to reimplement this abstract method...
+ bool update() { return true; }
+};
+@endcode
+
+*/
diff --git a/kmail/Makefile.am b/kmail/Makefile.am
new file mode 100644
index 00000000..ea566c45
--- /dev/null
+++ b/kmail/Makefile.am
@@ -0,0 +1,237 @@
+#KDE_OPTIONS = nofinal
+KDE_CXXFLAGS = $(USE_RTTI)
+
+SUBDIRS = interfaces . about pics profiles avscripts tests
+
+INCLUDES = -I$(top_srcdir)/libkmime \
+ -I$(top_srcdir)/libkpgp \
+ -I$(top_srcdir)/libkdenetwork \
+ -I$(top_srcdir)/libkdepim \
+ -I$(top_srcdir)/libkpimidentities \
+ -I$(top_srcdir)/libemailfunctions \
+ -I$(top_srcdir)/libksieve \
+ -I$(top_srcdir)/mimelib \
+ -I$(top_srcdir)/certmanager/lib \
+ -I$(top_srcdir)/certmanager/lib/ui \
+ -I$(top_srcdir)/indexlib \
+ -I$(top_srcdir)/ktnef \
+ -I$(top_srcdir)/korganizer \
+ -I$(top_srcdir) \
+ $(GPGME_CFLAGS) \
+ $(all_includes)
+
+if add_indexlib
+INDEXLIB=../indexlib/libindex.la
+endif
+
+lib_LTLIBRARIES = libkmailprivate.la
+libkmailprivate_la_LDFLAGS = $(all_libraries) -avoid-version -no-undefined
+libkmailprivate_la_LIBADD = \
+ ../libkmime/libkmime.la ../libkpgp/libkpgp.la ../libkdepim/libkdepim.la \
+ ../libkpimidentities/libkpimidentities.la ../mimelib/libmimelib.la \
+ ../libksieve/libksieve.la ../libemailfunctions/libemailfunctions.la \
+ ../certmanager/lib/libkleopatra.la $(INDEXLIB) \
+ ../libkcal/libkcal.la \
+ $(LIB_KHTML) $(LIB_KSPELL) $(LIB_KABC)
+
+kde_module_LTLIBRARIES = kcm_kmail.la libkmailpart.la libkmail_bodypartformatter_application_octetstream.la
+libkmailpart_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module -avoid-version -no-undefined
+libkmailpart_la_LIBADD = libkmailprivate.la
+
+kcm_kmail_la_SOURCES = kcm_kmail.cpp
+kcm_kmail_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+kcm_kmail_la_LIBADD = libkmailprivate.la $(LIB_KDECORE)
+
+libkmail_bodypartformatter_application_octetstream_la_SOURCES = app_octetstream.cpp
+libkmail_bodypartformatter_application_octetstream_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+linkdir = $(kde_datadir)/kmail/plugins/bodypartformatter
+link_DATA = application_octetstream.desktop
+
+bin_PROGRAMS = kmail
+kmail_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kmail_LDADD = libkmailprivate.la
+
+libkmailprivate_la_SOURCES = kmmessage.cpp kmmainwin.cpp configuredialog.cpp \
+ configuredialog_p.cpp klistviewindexedsearchline.cpp \
+ simplestringlisteditor.cpp index.cpp \
+ identitydrag.cpp identitylistview.cpp identitydialog.cpp \
+ kmfolderdia.cpp kmfoldertree.cpp kmtransport.cpp \
+ kmfoldercombobox.cpp kmaccount.cpp kmheaders.cpp \
+ headeritem.cpp listjob.cpp \
+ kmcomposewin.cpp kmfolder.cpp kmmsgpartdlg.cpp \
+ kmreaderwin.cpp htmlstatusbar.cpp kmmsgdict.cpp \
+ kmgroupware.cpp folderstorage.cpp \
+ csshelper.cpp klistboxdialog.cpp \
+ actionscheduler.cpp messageproperty.cpp \
+ kmmsgpart.cpp kmmsginfo.cpp \
+ accountmanager.cpp kmacctfolder.cpp kmdict.cpp \
+ kmsystemtray.cpp kmacctlocal.cpp kmfolderdir.cpp \
+ kmfoldermgr.cpp kmfoldernode.cpp kmsender.cpp \
+ kmacctseldlg.cpp kmfiltermgr.cpp kmsearchpatternedit.cpp \
+ filterimporterexporter.cpp \
+ encodingdetector.cpp encodingdetector_ja.cpp \
+ kmfilteraction.cpp kmsearchpattern.cpp \
+ kmfolderseldlg.cpp kmfilter.cpp kmfilterdlg.cpp \
+ kmmsgbase.cpp kmmsglist.cpp kmaddrbook.cpp \
+ signatureconfigurator.cpp xfaceconfigurator.cpp \
+ networkaccount.cpp imapaccountbase.cpp \
+ kmservertest.cpp kmacctimap.cpp kmacctcachedimap.cpp \
+ kmfawidgets.cpp kmfoldermbox.cpp kmfolderimap.cpp \
+ undostack.cpp kmfoldercachedimap.cpp \
+ kmfoldermaildir.cpp popaccount.cpp colorlistbox.cpp \
+ kmkernel.cpp kmailIface.skel kmailicalIface.skel \
+ accountdialog.cpp searchwindow.cpp vcardviewer.cpp \
+ vacationdialog.cpp vacation.cpp sievedebugdialog.cpp \
+ sieveconfig.cpp sievejob.cpp \
+ kmpopheaders.cpp kmpopfiltercnfrmdlg.cpp \
+ kmmimeparttree.cpp \
+ mailinglist-magic.cpp kmacctmaildir.cpp \
+ attachmentstrategy.cpp \
+ headerstrategy.cpp headerstyle.cpp khtmlparthtmlwriter.cpp \
+ filehtmlwriter.cpp teehtmlwriter.cpp \
+ mailcomposerIface.skel objecttreeparser.cpp \
+ attachmentcollector.cpp \
+ bodypartformatter.cpp bodypartformatterfactory.cpp \
+ partNode.cpp \
+ mailsourceviewer.cpp \
+ kmcommands.cpp kmreadermainwin.cpp \
+ kmstartup.cpp kmmainwidget.cpp \
+ folderpropertiesdialog.ui kmfolderindex.cpp \
+ kmfoldersearch.cpp transportmanager.cpp \
+ folderjob.cpp cachedimapjob.cpp \
+ maildirjob.cpp mboxjob.cpp imapjob.cpp \
+ subscriptiondialog.cpp kmailicalifaceimpl.cpp aboutdata.cpp \
+ folderIface.cpp folderIface.skel mailserviceimpl.cpp \
+ attachmentlistview.cpp kmedit.cpp kmlineeditspell.cpp \
+ kmatmlistview.cpp composer.cpp \
+ isubject.cpp bodyvisitor.cpp antispamwizard.cpp \
+ urlhandlermanager.cpp dictionarycombobox.cpp \
+ secondarywindow.cpp filterlog.cpp filterlogdlg.cpp \
+ korganizeriface.stub messagecomposer.cpp \
+ keyresolver.cpp globalsettings.cpp globalsettings_base.kcfgc \
+ regexplineedit.cpp rulewidgethandlermanager.cpp \
+ headerlistquicksearch.cpp acljobs.cpp folderdiaacltab.cpp \
+ quotajobs.cpp folderdiaquotatab.cpp folderdiaquotatab_p.cpp \
+ partnodebodypart.cpp \
+ expirejob.cpp compactionjob.cpp jobscheduler.cpp callback.cpp \
+ searchjob.cpp renamejob.cpp \
+ composercryptoconfiguration.ui \
+ warningconfiguration.ui smimeconfiguration.ui annotationjobs.cpp \
+ accountcombobox.cpp redirectdialog.cpp foldershortcutdialog.cpp \
+ folderrequester.cpp \
+ spamheaderanalyzer.cpp antispamconfig.cpp \
+ replyphrases.kcfgc custommimeheader.kcfgc \
+ recipientseditor.cpp \
+ recipientspicker.cpp kwindowpositioner.cpp \
+ distributionlistdialog.cpp expirypropertiesdialog.cpp \
+ mailinglistpropertiesdialog.cpp newfolderdialog.cpp \
+ accountwizard.cpp textsource.cpp \
+ managesievescriptsdialog.cpp chiasmuskeyselector.cpp \
+ util.cpp templatesinsertcommand.cpp \
+ customtemplates_base.ui customtemplates.cpp \
+ customtemplates_kfg.kcfgc \
+ templatesconfiguration_base.ui templatesconfiguration.cpp \
+ templatesconfiguration_kfg.kcfgc \
+ templateparser.cpp \
+ copyfolderjob.cpp \
+ messagecopyhelper.cpp \
+ localsubscriptiondialog.cpp \
+ editorwatcher.cpp \
+ kcalendariface.stub \
+ favoritefolderview.cpp \
+ foldertreebase.cpp \
+ snippetdlgbase.ui \
+ snippetwidget.cpp \
+ snippetconfig.cpp \
+ snippetdlg.cpp \
+ snippetitem.cpp \
+ snippetsettings.cpp \
+ snippetsettingsbase.ui \
+ scalix.cpp \
+ messageactions.cpp \
+ korghelper.cpp
+
+libkmailprivate_la_COMPILE_FIRST = globalsettings_base.h customtemplates_base.h templatesconfiguration_base.h
+
+kmail_SOURCES = main.cpp
+
+kmail_COMPILE_FIRST = globalsettings_base.h customtemplates_base.h templatesconfiguration_base.h
+
+libkmailpart_la_SOURCES = kmailpartIface.skel kmail_part.cpp
+
+libkmailpart_la_COMPILE_FIRST = globalsettings_base.h customtemplates_base.h templatesconfiguration_base.h
+
+check_PROGRAMS = dcoptest recipienteditortest
+
+METASOURCES = AUTO
+
+dcoptest_SOURCES = dcoptest.cpp kmailIface.skel kmailIface.stub mailcomposerIface.skel mailcomposerIface.stub
+dcoptest_LDADD = $(LIB_KIO)
+dcoptest_LDFLAGS = $(all_libraries)
+
+recipienteditortest_SOURCES = recipientseditortest.cpp
+recipienteditortest_LDADD = libkmailprivate.la ../libkdepim/libkdepim.la $(LIB_KIO) $(LIB_KABC)
+recipienteditortest_LDFLAGS = $(all_libraries)
+
+kmailIface_DCOPIDLNG = true
+kmailicalIface_DCOPIDLNG = true
+
+korganizeriface_DIR = $(top_srcdir)/korganizer
+kcalendariface_DIR = $(top_srcdir)/korganizer
+
+include_HEADERS = kmailIface.h kmailpartIface.h kmailicalIface.h
+
+xdg_apps_DATA = KMail.desktop kmail_view.desktop
+
+# why?
+EXTRA_DIST = KMail.desktop $(link_DATA)
+
+KDE_ICON = AUTO
+
+rcdir = $(kde_datadir)/kmail
+rc_DATA = kmcomposerui.rc kmmainwin.rc kmreadermainwin.rc eventsrc kmail_part.rc
+
+updatedir = $(kde_datadir)/kconf_update
+update_DATA = kmail.upd
+update_SCRIPTS = upgrade-transport.pl kmail-pgpidentity.pl \
+ upgrade-signature.pl kmail-upd-identities.pl \
+ kmail-3.1-use-UOID-for-identities.pl \
+ kmail-3.1-update-new-mail-notification-settings.pl \
+ kmail-3.1.4-dont-use-UOID-0-for-any-identity.pl \
+ kmail-3.2-update-loop-on-goto-unread-settings.sh \
+ kmail-3.2-misc.sh \
+ kmail-3.3-use-ID-for-accounts.pl \
+ kmail-3.3-move-identities.pl \
+ kmail-3.3-aegypten.pl \
+ kmail-3.3-split-sign-encr-keys.sh \
+ kmail-3.3-misc.pl \
+ kmail-3.3b1-misc.pl \
+ kmail-3.4-misc.pl \
+ kmail-3.4.1-update-status-filters.pl \
+ kmail-3.5-trigger-flag-migration.pl
+
+confdir = $(kde_confdir)
+conf_DATA = kmail.antispamrc kmail.antivirusrc
+
+tipdir = $(kde_datadir)/kmail
+tip_DATA = tips
+
+servicetypedir = $(kde_servicetypesdir)
+servicetype_DATA = dcopmail.desktop dcopimap.desktop
+
+kde_services_DATA = kmail_config_misc.desktop kmail_config_appearance.desktop \
+ kmail_config_identity.desktop kmail_config_accounts.desktop kmail_config_composer.desktop \
+ kmail_config_security.desktop
+
+messages: rc.cpp
+ rm -f tips.cpp
+ $(PREPARETIPS) > tips.cpp
+ $(XGETTEXT) -ktranslate *.cpp *.h -o $(podir)/kmail.pot
+ rm -f tips.cpp
+
+kde_kcfg_DATA = kmail.kcfg replyphrases.kcfg custommimeheader.kcfg \
+ templatesconfiguration_kfg.kcfg customtemplates_kfg.kcfg
+
+DOXYGEN_REFERENCES = kdeui
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/kmail/TODO b/kmail/TODO
new file mode 100644
index 00000000..cf5792a1
--- /dev/null
+++ b/kmail/TODO
@@ -0,0 +1,36 @@
+Around the 3.4 release
+TA: remove the disabled expiry tab code from kmfolderdia.cpp once it is clear
+ that it won't be used anymore
+
+Before the first 3.2 Beta
+MM: Write config upgrade script for
+ - AttachmentStyle -> AttachmentStrategy change
+ - HeaderStyle -> { HeaderStyle, HeaderStrategy } split
+DS: Full Text Indexing
+DS: Client side imap filtering
+DS: Support for multipart/related mails
+DS: Support for html composing
+DS: Better for replying to html mail
+??: Disconnected IMAP
+
+Needs more planning:
+DS: BBDB like functionality
+DS: Fuller DCOP interface (requires hidden dcop interfaces thanks Alex!)
+DS: Console (plain text) client using dcop interface
+DS: XFace with support for Allison reconstruction.
+DS: writeindex incrementally update for deleted items.
+DS: (improve status showing, for concurrent account checking)
+DS: Use takeitem to hide read messages, with special behavior
+ in threaded mode
+DS: Propoganda: Analysis Articles, head-to-head comparisons
+DS: Single message class
+DS: Zero-copy display of message 15465
+DS: Zero-copy downloading from pop server
+DS: Set color action
+DS: XML GUI context menus to support KMail plugins
+DS: IMAP body searching
+??: Dock Windows
+
+Groupware:
+KHZ: Make groupware use a real vCal parser
+MM: Implement generic viewer plugin
diff --git a/kmail/about/Makefile.am b/kmail/about/Makefile.am
new file mode 100644
index 00000000..4ac57fc2
--- /dev/null
+++ b/kmail/about/Makefile.am
@@ -0,0 +1,6 @@
+about_DATA = \
+ top-right-kmail.png \
+ main.html \
+ kmail.css
+
+aboutdir = $(kde_datadir)/kmail/about
diff --git a/kmail/about/kmail.css b/kmail/about/kmail.css
new file mode 100644
index 00000000..3fb2ce90
--- /dev/null
+++ b/kmail/about/kmail.css
@@ -0,0 +1,26 @@
+
+#headerR {
+ position: absolute;
+ right: 0px;
+ width: 430px;
+ height: 131px;
+ background-image: url(top-right-kmail.png);
+}
+
+#title {
+ right: 125px;
+}
+
+#tagline {
+ right: 125px;
+}
+
+#boxCenter {
+ background-image: url(box-center-kmail.png);
+ background-repeat: no-repeat;
+ background-color: #dfe7f3;
+ background-position: bottom right;
+}
+
+/* vim:set sw=2 et nocindent smartindent: */
+
diff --git a/kmail/about/main.html b/kmail/about/main.html
new file mode 100644
index 00000000..bc367933
--- /dev/null
+++ b/kmail/about/main.html
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta name="generator" content=
+ "HTML Tidy for Linux/x86 (vers 1st August 2004), see www.w3.org" />
+
+ <style type="text/css">
+ /*<![CDATA[*/
+ @import "%1"; /* kde_infopage.css */
+ %1 /* maybe @import "kde_infopage_rtl.css"; */
+ @import "kmail.css";
+ body {font-size: %1px;}
+ /*]]>*/
+ </style>
+
+ <title>KMail</title>
+</head>
+
+<body>
+ <div id="header">
+ <div id="headerL"/>
+ <div id="headerR"/>
+
+ <div id="title">
+ %2 <!-- KMail -->
+ </div>
+
+ <div id="tagline">
+ %3 <!-- Catchphrase -->
+ </div>
+ </div>
+
+ <!-- the bar -->
+ <div id="bar">
+ <div id="barT"><div id="barTL"/><div id="barTR"/><div id="barTC"/></div>
+ <div id="barL">
+ <div id="barR">
+ <div id="barCenter" class="bar_text">
+ %4<!-- KMail is ... -->
+ </div>
+ </div>
+ </div>
+ <div id="barB"><div id="barBL"/><div id="barBR"/><div id="barBC"/></div>
+ </div>
+
+ <!-- the main text box -->
+ <div id="box">
+ <div id="boxT"><div id="boxTL"/><div id="boxTR"/><div id="boxTC"/></div>
+ <div id="boxL">
+ <div id="boxR">
+ <div id="boxCenter">
+ <!--Welcome to KMail-->
+ %5
+ </div>
+ </div>
+ </div>
+ <div id="boxB"><div id="boxBL"/><div id="boxBR"/><div id="boxBC"/></div>
+ </div>
+
+ <div id="footer"><div id="footerL"/><div id="footerR"/></div>
+</body>
+</html>
+<!-- vim:set sw=2 et nocindent smartindent: -->
diff --git a/kmail/about/top-right-kmail.png b/kmail/about/top-right-kmail.png
new file mode 100644
index 00000000..bf15f38b
--- /dev/null
+++ b/kmail/about/top-right-kmail.png
Binary files differ
diff --git a/kmail/aboutdata.cpp b/kmail/aboutdata.cpp
new file mode 100644
index 00000000..e525fae4
--- /dev/null
+++ b/kmail/aboutdata.cpp
@@ -0,0 +1,229 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ aboutdata.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2003 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "aboutdata.h"
+
+#include "kmversion.h"
+
+namespace KMail {
+
+ struct about_data {
+ const char * name;
+ const char * desc;
+ const char * email;
+ const char * web;
+ };
+
+ // This file should not be changed by anybody other than the maintainer
+ // or the co-maintainer.
+
+ static const about_data authors[] = {
+ { "Ingo Kl\303\266cker", I18N_NOOP("Maintainer"),
+ "kloecker@kde.org", 0 },
+ { "Don Sanders", I18N_NOOP("Adopter and co-maintainer"),
+ "sanders@kde.org", 0 },
+ { "Stefan Taferner", I18N_NOOP("Original author"),
+ "taferner@kde.org", 0 },
+ { "Michael H\303\244ckel", I18N_NOOP("Former maintainer"),
+ "haeckel@kde.org", 0 },
+
+ { "Till Adam", I18N_NOOP("Core developer"),
+ "adam@kde.org", 0 },
+ { "Carsten Burghardt", I18N_NOOP("Core developer"),
+ "burghardt@kde.org", 0 },
+ { "Marc Mutz", I18N_NOOP("Core developer"),
+ "mutz@kde.org", 0 },
+ { "Daniel Naber", I18N_NOOP("Documentation"),
+ "daniel.naber@t-online.de", 0 },
+ { "Zack Rusin", I18N_NOOP("Core developer"),
+ "zack@kde.org", 0 },
+
+ { "Toyohiro Asukai", 0,
+ "toyohiro@ksmplus.com", 0 },
+ { "Waldo Bastian", 0,
+ "bastian@kde.org", 0 },
+ { "Ryan Breen", I18N_NOOP("system tray notification"),
+ "ryan@ryanbreen.com", 0 },
+ { "Steven Brown", 0,
+ "swbrown@ucsd.edu", 0 },
+ { "Matthias Kalle Dalheimer", 0,
+ "kalle@kde.org", 0 },
+ { "Matt Douhan", 0,
+ "matt@fruitsalad.org", 0 },
+ { "Cristi Dumitrescu", 0,
+ "cristid@chip.ro", 0 },
+ { "David Faure", 0,
+ "faure@kde.org", 0 },
+ { "Philippe Fremy", 0,
+ "pfremy@chez.com", 0 },
+ { "Kurt Granroth", 0,
+ "granroth@kde.org", 0 },
+ { "Andreas Gungl", I18N_NOOP("PGP 6 support and further enhancements of the encryption support"),
+ "a.gungl@gmx.de", 0 },
+ { "Steffen Hansen", 0,
+ "hansen@kde.org", 0 },
+ { "Igor Janssen", 0,
+ "rm@linux.ru.net", 0 },
+ { "Matt Johnston", 0,
+ "matt@caifex.org", 0 },
+ { "Christer Kaivo-oja", 0,
+ "whizkid@telia.com", 0 },
+ { "Lars Knoll", I18N_NOOP("Original encryption support\n"
+ "PGP 2 and PGP 5 support"),
+ "knoll@kde.org", 0 },
+ { "J. Nick Koston", I18N_NOOP("GnuPG support"),
+ "bdraco@darkorb.net", 0 },
+ { "Stephan Kulow", 0,
+ "coolo@kde.org", 0 },
+ { "Guillaume Laurent", 0,
+ "glaurent@telegraph-road.org", 0 },
+ { "Sam Magnuson", 0,
+ "sam@trolltech.com", 0 },
+ { "Laurent Montel", 0,
+ "lmontel@mandrakesoft.com", 0 },
+ { "Matt Newell", 0,
+ "newellm@proaxis.com", 0 },
+ { "Denis Perchine", 0,
+ "dyp@perchine.com", 0 },
+ { "Samuel Penn", 0,
+ "sam@bifrost.demon.co.uk", 0 },
+ { "Carsten Pfeiffer", 0,
+ "pfeiffer@kde.org", 0 },
+ { "Sven Radej", 0,
+ "radej@kde.org", 0 },
+ { "Mark Roberts", 0,
+ "mark@taurine.demon.co.uk", 0 },
+ { "Wolfgang Rohdewald", 0,
+ "wrohdewald@dplanet.ch", 0 },
+ { "Espen Sand", 0,
+ "espen@kde.org", 0 },
+ { "Aaron J. Seigo", 0,
+ "aseigo@olympusproject.org", 0 },
+ { "George Staikos", 0,
+ "staikos@kde.org", 0 },
+ { "Jason Stephenson", 0,
+ "panda@mis.net", 0 },
+ { "Jacek Stolarczyk", 0,
+ "jacek@mer.chemia.polsl.gliwice.pl", 0 },
+ { "Roberto S. Teixeira", 0,
+ "maragato@kde.org", 0 },
+ { "Bo Thorsen", 0,
+ "bo@sonofthor.dk", 0 },
+ { "Ronen Tzur", 0,
+ "rtzur@shani.net", 0 },
+ { "Mario Weilguni", 0,
+ "mweilguni@sime.com", 0 },
+ { "Wynn Wilkes", 0,
+ "wynnw@calderasystems.com", 0 },
+ { "Robert D. Williams", 0,
+ "rwilliams@kde.org", 0 },
+ { "Markus W\303\274bben", 0,
+ "markus.wuebben@kde.org", 0 },
+ { "Karl-Heinz Zimmer", 0,
+ "khz@kde.org", 0 }
+ };
+
+ static const about_data credits[] = {
+ { "Sam Abed", 0, 0, 0 }, // KConfigXT porting, smileys->emoticons replacement
+ { "Joern Ahrens", 0, 0, 0 }, // implement wish 77182 (Add some separators to "Mark Message as" popup menu)
+ { "Tom Albers", 0, 0, 0 }, // small fixes, bugzilla maintenance
+ { "Albert Cervera Areny", 0, 0, 0 }, // implemented wish 88309 (optional compression of attachments)
+ { "Patrick Audley", 0, 0, 0 }, // add optional graphical spam status to fancy headers
+ { "Benjamin Azan", 0, 0, 0 }, // implemented todo status handling
+ { "Albert Astals Cid", 0, 0, 0 }, // fix for bug:95441 (folder tree context menu doesn't show shortcuts assigned to the actions)
+ { "Cornelius Schumacher", 0, "schumacher@kde.org", 0 }, // implemented the new recipients editor and picker
+ { "Frederick Emmott", I18N_NOOP("Anti-virus support"),
+ "fred87@users.sf.net", 0 },
+ { "Sandro Giessl", 0, 0, 0 }, // frame width fixes for widget styles
+ { "Severin Greimel", 0, 0, 0 }, // several patches
+ { "Shaheed Haque", 0, 0, 0 }, // fix for bug:69744 (Resource folders: "Journals" should be "Journal")
+ { "Ingo Heeskens", 0, 0, 0 }, // implemented wish 34857 (per folder option for loading external references)
+ { "Kurt Hindenburg", 0, 0, 0 }, // implemented wish 89003 (delete whole thread)
+ { "Heiko Hund", I18N_NOOP("POP filters"),
+ "heiko@ist.eigentlich.net", 0 },
+ { "Torsten Kasch", 0, 0, 0 }, // crash fix for Solaris (cf. bug:68801)
+ { "Jason 'vanRijn' Kasper", 0, 0, 0 }, // implemented wish 79938 (configurable font for new/unread/important messages)
+ { "Martijn Klingens", 0, 0, 0 }, // fix keyboard navigation in the Status combo of the quick search
+ { "Christoph Kl\303\274nter", 0, 0, 0 }, // fix for bug:88216 (drag&drop from KAddressBook to the To: field)
+ { "Martin Koller", 0, 0, 0 }, // optional columns in the message list
+ { "Tobias K\303\266nig", 0, 0, 0 }, // edit recent addresses, store email<->OpenPGP key association in address book
+ { "Volker Krause", 0, 0, 0 }, // implemented KWallet support, fixed multiple bugs
+ { "Francois Kritzinger", 0, 0, 0 }, // fix bug in configuration dialog
+ { "Danny Kukawka", 0, 0, 0 }, // DCOP enhancements for better message importing
+ { "Roger Larsson", 0, 0, 0 }, // add name of checked account to status bar message
+ { "Jeffrey McGee", 0, 0, 0 }, // fix for bug:64251
+ { "Dirk M\303\274ller", 0, 0, 0 }, // KURL() fixes and qt_cast optimizations
+ { "OpenUsability", I18N_NOOP("Usability tests and improvements"), 0, "http://www.openusability.org" },
+ { "Mario Teijeiro Otero", 0, 0, 0 }, // various vendor annotations fixes
+ { "Simon Perreault", 0, 0, 0 }, // make the composer remember its "Use Fixed Font" setting (bug 49481)
+ { "Bernhard Reiter", I18N_NOOP("\xC3\x84gypten and Kroupware project management"),
+ "bernhard@intevation.de", 0 },
+ { "Edwin Schepers", 0, "yez@home.nl", 0 }, // composition of HTML messages
+ { "Jakob Schr\303\266ter", 0, 0, 0 }, // implemented wish 28319 (X-Face support)
+ { "Jan Simonson", I18N_NOOP("beta testing of PGP 6 support"),
+ "jan@simonson.pp.se", 0 },
+ { "Paul Sprakes", 0, 0, 0 }, // fix for bug:63619 (filter button in toolbar doesn't work), context menu clean up
+ { "Will Stephenson", 0, 0, 0 }, // added IM status indicator
+ { "Hasso Tepper", 0, 0, 0 }, // improve layout of recipients editor
+ { "Patrick S. Vogt", I18N_NOOP("timestamp for 'Transmission completed' status messages"),
+ "patrick.vogt@unibas.ch", 0 },
+ { "Jan-Oliver Wagner", I18N_NOOP("\xC3\x84gypten and Kroupware project management"),
+ "jan@intevation.de", 0 },
+ { "Wolfgang Westphal", I18N_NOOP("multiple encryption keys per address"),
+ "wolfgang.westphal@gmx.de", 0 },
+ { "Thorsten Zachmann", I18N_NOOP("POP filters"),
+ "t.zachmann@zagge.de", 0 },
+ { "Thomas Zander", 0, 0, 0 }
+ };
+
+ AboutData::AboutData()
+ : KAboutData( "kmail", I18N_NOOP("KMail"),KMAIL_VERSION,
+ I18N_NOOP("KDE Email Client"), License_GPL,
+ I18N_NOOP("(c) 1997-2008, The KMail developers"), 0,
+ "http://kontact.kde.org/kmail/" )
+ {
+ using KMail::authors;
+ using KMail::credits;
+ for ( unsigned int i = 0 ; i < sizeof authors / sizeof *authors ; ++i )
+ addAuthor( authors[i].name, authors[i].desc, authors[i].email, authors[i].web );
+ for ( unsigned int i = 0 ; i < sizeof credits / sizeof *credits ; ++i )
+ addCredit( credits[i].name, credits[i].desc, credits[i].email, credits[i].web );
+ }
+
+ AboutData::~AboutData() {
+
+ }
+
+} // namespace KMail
diff --git a/kmail/aboutdata.h b/kmail/aboutdata.h
new file mode 100644
index 00000000..b7c82f11
--- /dev/null
+++ b/kmail/aboutdata.h
@@ -0,0 +1,49 @@
+/* -*- c++ -*-
+ aboutdata.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2003 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KMAIL_ABOUTDATA_H__
+#define __KMAIL_ABOUTDATA_H__
+
+#include <kaboutdata.h>
+#include <kdepimmacros.h>
+
+namespace KMail {
+
+ class KDE_EXPORT AboutData : public KAboutData {
+ public:
+ AboutData();
+ ~AboutData();
+ };
+
+} // namespace KMail
+
+#endif // __KMAIL_ABOUTDATA_H__
+
diff --git a/kmail/accountcombobox.cpp b/kmail/accountcombobox.cpp
new file mode 100644
index 00000000..afa8398e
--- /dev/null
+++ b/kmail/accountcombobox.cpp
@@ -0,0 +1,106 @@
+/** -*- mode: C++ -*-
+ * Copyright (c) 2004 David Faure <faure@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+
+#include "accountcombobox.h"
+#include "kmfolder.h"
+#include "kmfolderdir.h"
+#include "accountmanager.h"
+#include <kdebug.h>
+
+using namespace KMail;
+
+AccountComboBox::AccountComboBox( QWidget* parent, const char* name )
+ : QComboBox( parent, name )
+{
+ connect( kmkernel->acctMgr(), SIGNAL( accountAdded( KMAccount* ) ),
+ this, SLOT( slotRefreshAccounts() ) );
+ connect( kmkernel->acctMgr(), SIGNAL( accountRemoved( KMAccount* ) ),
+ this, SLOT( slotRefreshAccounts() ) );
+ slotRefreshAccounts();
+}
+
+void AccountComboBox::slotRefreshAccounts()
+{
+ KMAccount* curr = currentAccount();
+ clear();
+ // Note that this won't take into account newly-created-in-configuredialog accounts
+ // until clicking OK or Apply. This would make this class much more complex
+ // (this would have to be different depending on whether this combo is in the
+ // configuration dialog or not...)
+ QStringList accountNames;
+ QValueList<KMAccount *> lst = applicableAccounts();
+ QValueList<KMAccount *>::ConstIterator it = lst.begin();
+ for ( ; it != lst.end() ; ++it )
+ accountNames.append( (*it)->name() );
+ kdDebug() << k_funcinfo << accountNames << endl;
+ insertStringList( accountNames );
+ if ( curr )
+ setCurrentAccount( curr );
+}
+
+
+void AccountComboBox::setCurrentAccount( KMAccount* account )
+{
+ int i = 0;
+ QValueList<KMAccount *> lst = applicableAccounts();
+ QValueList<KMAccount *>::ConstIterator it = lst.begin();
+ for ( ; it != lst.end() ; ++it, ++i ) {
+ if ( (*it) == account ) {
+ setCurrentItem( i );
+ return;
+ }
+ }
+}
+
+KMAccount* AccountComboBox::currentAccount() const
+{
+ int i = 0;
+ QValueList<KMAccount *> lst = applicableAccounts();
+ QValueList<KMAccount *>::ConstIterator it = lst.begin();
+ while ( it != lst.end() && i < currentItem() ) {
+ ++it;
+ ++i;
+ }
+ if ( it != lst.end() )
+ return *it;
+ return 0;
+}
+
+QValueList<KMAccount *> KMail::AccountComboBox::applicableAccounts() const
+{
+ QValueList<KMAccount *> lst;
+ for( KMAccount *a = kmkernel->acctMgr()->first(); a;
+ a = kmkernel->acctMgr()->next() ) {
+ if ( a && a->type() == "cachedimap" ) { //// ## proko2 hack. Need a list of allowed account types as ctor param
+ lst.append( a );
+ }
+ }
+ return lst;
+}
+
+#include "accountcombobox.moc"
diff --git a/kmail/accountcombobox.h b/kmail/accountcombobox.h
new file mode 100644
index 00000000..5c8d1bbd
--- /dev/null
+++ b/kmail/accountcombobox.h
@@ -0,0 +1,61 @@
+/* -*- mode: C++ -*-
+ * Copyright (c) 2004 David Faure <faure@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+#ifndef KMAIL_ACCOUNTCOMBOBOX_H
+#define KMAIL_ACCOUNTCOMBOBOX_H
+
+#include <qcombobox.h>
+
+class KMAccount;
+
+namespace KMail {
+
+/**
+ * A readonly combobox showing the accounts, to select one.
+ * WARNING: this widget is hardcoded to only display disconnected imap
+ * accounts, in this branch.
+ */
+class AccountComboBox : public QComboBox
+{
+ Q_OBJECT
+
+public:
+ AccountComboBox( QWidget* parent, const char* name = 0 );
+
+ void setCurrentAccount( KMAccount* account );
+ KMAccount* currentAccount() const;
+
+private slots:
+ void slotRefreshAccounts();
+private:
+ QValueList<KMAccount *> applicableAccounts() const;
+};
+
+
+} // namespace
+
+#endif
diff --git a/kmail/accountdialog.cpp b/kmail/accountdialog.cpp
new file mode 100644
index 00000000..b517925a
--- /dev/null
+++ b/kmail/accountdialog.cpp
@@ -0,0 +1,2352 @@
+/*
+ * kmail: KDE mail client
+ * This file: Copyright (C) 2000 Espen Sand, espen@kde.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#include <config.h>
+
+#include "accountdialog.h"
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qtabwidget.h>
+#include <qradiobutton.h>
+#include <qvalidator.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qwhatsthis.h>
+#include <qhbox.h>
+#include <qcombobox.h>
+#include <qheader.h>
+#include <qtoolbutton.h>
+#include <qgrid.h>
+
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kseparator.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kprotocolinfo.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "sieveconfig.h"
+#include "kmacctmaildir.h"
+#include "kmacctlocal.h"
+#include "accountmanager.h"
+#include "popaccount.h"
+#include "kmacctimap.h"
+#include "kmacctcachedimap.h"
+#include "kmfoldermgr.h"
+#include "kmservertest.h"
+#include "protocols.h"
+#include "folderrequester.h"
+#include "kmmainwidget.h"
+#include "kmfolder.h"
+#include <libkpimidentities/identitymanager.h>
+#include <libkpimidentities/identitycombo.h>
+#include <libkpimidentities/identity.h>
+#include "globalsettings.h"
+
+#include <cassert>
+#include <stdlib.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h> /* defines _PATH_MAILDIR */
+#endif
+
+#ifndef _PATH_MAILDIR
+#define _PATH_MAILDIR "/var/spool/mail"
+#endif
+
+namespace KMail {
+
+class ProcmailRCParser
+{
+public:
+ ProcmailRCParser(QString fileName = QString::null);
+ ~ProcmailRCParser();
+
+ QStringList getLockFilesList() const { return mLockFiles; }
+ QStringList getSpoolFilesList() const { return mSpoolFiles; }
+
+protected:
+ void processGlobalLock(const QString&);
+ void processLocalLock(const QString&);
+ void processVariableSetting(const QString&, int);
+ QString expandVars(const QString&);
+
+ QFile mProcmailrc;
+ QTextStream *mStream;
+ QStringList mLockFiles;
+ QStringList mSpoolFiles;
+ QAsciiDict<QString> mVars;
+};
+
+ProcmailRCParser::ProcmailRCParser(QString fname)
+ : mProcmailrc(fname),
+ mStream(new QTextStream(&mProcmailrc))
+{
+ mVars.setAutoDelete(true);
+
+ // predefined
+ mVars.insert( "HOME", new QString( QDir::homeDirPath() ) );
+
+ if( !fname || fname.isEmpty() ) {
+ fname = QDir::homeDirPath() + "/.procmailrc";
+ mProcmailrc.setName(fname);
+ }
+
+ QRegExp lockFileGlobal("^LOCKFILE=", true);
+ QRegExp lockFileLocal("^:0", true);
+
+ if( mProcmailrc.open(IO_ReadOnly) ) {
+
+ QString s;
+
+ while( !mStream->eof() ) {
+
+ s = mStream->readLine().stripWhiteSpace();
+
+ if( s[0] == '#' ) continue; // skip comments
+
+ int commentPos = -1;
+
+ if( (commentPos = s.find('#')) > -1 ) {
+ // get rid of trailing comment
+ s.truncate(commentPos);
+ s = s.stripWhiteSpace();
+ }
+
+ if( lockFileGlobal.search(s) != -1 ) {
+ processGlobalLock(s);
+ } else if( lockFileLocal.search(s) != -1 ) {
+ processLocalLock(s);
+ } else if( int i = s.find('=') ) {
+ processVariableSetting(s,i);
+ }
+ }
+
+ }
+ QString default_Location = getenv("MAIL");
+
+ if (default_Location.isNull()) {
+ default_Location = _PATH_MAILDIR;
+ default_Location += '/';
+ default_Location += getenv("USER");
+ }
+ if ( !mSpoolFiles.contains(default_Location) )
+ mSpoolFiles << default_Location;
+
+ default_Location = default_Location + ".lock";
+ if ( !mLockFiles.contains(default_Location) )
+ mLockFiles << default_Location;
+}
+
+ProcmailRCParser::~ProcmailRCParser()
+{
+ delete mStream;
+}
+
+void
+ProcmailRCParser::processGlobalLock(const QString &s)
+{
+ QString val = expandVars(s.mid(s.find('=') + 1).stripWhiteSpace());
+ if ( !mLockFiles.contains(val) )
+ mLockFiles << val;
+}
+
+void
+ProcmailRCParser::processLocalLock(const QString &s)
+{
+ QString val;
+ int colonPos = s.findRev(':');
+
+ if (colonPos > 0) { // we don't care about the leading one
+ val = s.mid(colonPos + 1).stripWhiteSpace();
+
+ if ( val.length() ) {
+ // user specified a lockfile, so process it
+ //
+ val = expandVars(val);
+ if( val[0] != '/' && mVars.find("MAILDIR") )
+ val.insert(0, *(mVars["MAILDIR"]) + '/');
+ } // else we'll deduce the lockfile name one we
+ // get the spoolfile name
+ }
+
+ // parse until we find the spoolfile
+ QString line, prevLine;
+ do {
+ prevLine = line;
+ line = mStream->readLine().stripWhiteSpace();
+ } while ( !mStream->eof() && (line[0] == '*' ||
+ prevLine[prevLine.length() - 1] == '\\' ));
+
+ if( line[0] != '!' && line[0] != '|' && line[0] != '{' ) {
+ // this is a filename, expand it
+ //
+ line = line.stripWhiteSpace();
+ line = expandVars(line);
+
+ // prepend default MAILDIR if needed
+ if( line[0] != '/' && mVars.find("MAILDIR") )
+ line.insert(0, *(mVars["MAILDIR"]) + '/');
+
+ // now we have the spoolfile name
+ if ( !mSpoolFiles.contains(line) )
+ mSpoolFiles << line;
+
+ if( colonPos > 0 && (!val || val.isEmpty()) ) {
+ // there is a local lockfile, but the user didn't
+ // specify the name so compute it from the spoolfile's name
+ val = line;
+
+ // append lock extension
+ if( mVars.find("LOCKEXT") )
+ val += *(mVars["LOCKEXT"]);
+ else
+ val += ".lock";
+ }
+
+ if ( !val.isNull() && !mLockFiles.contains(val) ) {
+ mLockFiles << val;
+ }
+ }
+
+}
+
+void
+ProcmailRCParser::processVariableSetting(const QString &s, int eqPos)
+{
+ if( eqPos == -1) return;
+
+ QString varName = s.left(eqPos),
+ varValue = expandVars(s.mid(eqPos + 1).stripWhiteSpace());
+
+ mVars.insert(varName.latin1(), new QString(varValue));
+}
+
+QString
+ProcmailRCParser::expandVars(const QString &s)
+{
+ if( s.isEmpty()) return s;
+
+ QString expS = s;
+
+ QAsciiDictIterator<QString> it( mVars ); // iterator for dict
+
+ while ( it.current() ) {
+ expS.replace(QString::fromLatin1("$") + it.currentKey(), *it.current());
+ ++it;
+ }
+
+ return expS;
+}
+
+
+
+AccountDialog::AccountDialog( const QString & caption, KMAccount *account,
+ QWidget *parent, const char *name, bool modal )
+ : KDialogBase( parent, name, modal, caption, Ok|Cancel|Help, Ok, true ),
+ mAccount( account ),
+ mServerTest( 0 ),
+ mCurCapa( AllCapa ),
+ mCapaNormal( AllCapa ),
+ mCapaSSL( AllCapa ),
+ mCapaTLS( AllCapa ),
+ mSieveConfigEditor( 0 )
+{
+ mValidator = new QRegExpValidator( QRegExp( "[A-Za-z0-9-_:.]*" ), 0 );
+ setHelp("receiving-mail");
+
+ QString accountType = mAccount->type();
+
+ if( accountType == "local" )
+ {
+ makeLocalAccountPage();
+ }
+ else if( accountType == "maildir" )
+ {
+ makeMaildirAccountPage();
+ }
+ else if( accountType == "pop" )
+ {
+ makePopAccountPage();
+ }
+ else if( accountType == "imap" )
+ {
+ makeImapAccountPage();
+ }
+ else if( accountType == "cachedimap" )
+ {
+ makeImapAccountPage(true);
+ }
+ else
+ {
+ QString msg = i18n( "Account type is not supported." );
+ KMessageBox::information( topLevelWidget(),msg,i18n("Configure Account") );
+ return;
+ }
+
+ setupSettings();
+}
+
+AccountDialog::~AccountDialog()
+{
+ delete mValidator;
+ mValidator = 0;
+ delete mServerTest;
+ mServerTest = 0;
+}
+
+void AccountDialog::makeLocalAccountPage()
+{
+ ProcmailRCParser procmailrcParser;
+ QFrame *page = makeMainWidget();
+ QGridLayout *topLayout = new QGridLayout( page, 12, 3, 0, spacingHint() );
+ topLayout->addColSpacing( 1, fontMetrics().maxWidth()*15 );
+ topLayout->setRowStretch( 11, 10 );
+ topLayout->setColStretch( 1, 10 );
+
+ mLocal.titleLabel = new QLabel( i18n("Account Type: Local Account"), page );
+ topLayout->addMultiCellWidget( mLocal.titleLabel, 0, 0, 0, 2 );
+ QFont titleFont( mLocal.titleLabel->font() );
+ titleFont.setBold( true );
+ mLocal.titleLabel->setFont( titleFont );
+ KSeparator *hline = new KSeparator( KSeparator::HLine, page);
+ topLayout->addMultiCellWidget( hline, 1, 1, 0, 2 );
+
+ QLabel *label = new QLabel( i18n("Account &name:"), page );
+ topLayout->addWidget( label, 2, 0 );
+ mLocal.nameEdit = new KLineEdit( page );
+ label->setBuddy( mLocal.nameEdit );
+ topLayout->addWidget( mLocal.nameEdit, 2, 1 );
+
+ label = new QLabel( i18n("File &location:"), page );
+ topLayout->addWidget( label, 3, 0 );
+ mLocal.locationEdit = new QComboBox( true, page );
+ label->setBuddy( mLocal.locationEdit );
+ topLayout->addWidget( mLocal.locationEdit, 3, 1 );
+ mLocal.locationEdit->insertStringList(procmailrcParser.getSpoolFilesList());
+
+ QPushButton *choose = new QPushButton( i18n("Choo&se..."), page );
+ choose->setAutoDefault( false );
+ connect( choose, SIGNAL(clicked()), this, SLOT(slotLocationChooser()) );
+ topLayout->addWidget( choose, 3, 2 );
+
+ QButtonGroup *group = new QButtonGroup(i18n("Locking Method"), page );
+ group->setColumnLayout(0, Qt::Horizontal);
+ group->layout()->setSpacing( 0 );
+ group->layout()->setMargin( 0 );
+ QGridLayout *groupLayout = new QGridLayout( group->layout() );
+ groupLayout->setAlignment( Qt::AlignTop );
+ groupLayout->setSpacing( 6 );
+ groupLayout->setMargin( 11 );
+
+ mLocal.lockProcmail = new QRadioButton( i18n("Procmail loc&kfile:"), group);
+ groupLayout->addWidget(mLocal.lockProcmail, 0, 0);
+
+ mLocal.procmailLockFileName = new QComboBox( true, group );
+ groupLayout->addWidget(mLocal.procmailLockFileName, 0, 1);
+ mLocal.procmailLockFileName->insertStringList(procmailrcParser.getLockFilesList());
+ mLocal.procmailLockFileName->setEnabled(false);
+
+ QObject::connect(mLocal.lockProcmail, SIGNAL(toggled(bool)),
+ mLocal.procmailLockFileName, SLOT(setEnabled(bool)));
+
+ mLocal.lockMutt = new QRadioButton(
+ i18n("&Mutt dotlock"), group);
+ groupLayout->addWidget(mLocal.lockMutt, 1, 0);
+
+ mLocal.lockMuttPriv = new QRadioButton(
+ i18n("M&utt dotlock privileged"), group);
+ groupLayout->addWidget(mLocal.lockMuttPriv, 2, 0);
+
+ mLocal.lockFcntl = new QRadioButton(
+ i18n("&FCNTL"), group);
+ groupLayout->addWidget(mLocal.lockFcntl, 3, 0);
+
+ mLocal.lockNone = new QRadioButton(
+ i18n("Non&e (use with care)"), group);
+ groupLayout->addWidget(mLocal.lockNone, 4, 0);
+
+ topLayout->addMultiCellWidget( group, 4, 4, 0, 2 );
+
+#if 0
+ QHBox* resourceHB = new QHBox( page );
+ resourceHB->setSpacing( 11 );
+ mLocal.resourceCheck =
+ new QCheckBox( i18n( "Account for semiautomatic resource handling" ), resourceHB );
+ mLocal.resourceClearButton =
+ new QPushButton( i18n( "Clear" ), resourceHB );
+ QWhatsThis::add( mLocal.resourceClearButton,
+ i18n( "Delete all allocations for the resource represented by this account." ) );
+ mLocal.resourceClearButton->setEnabled( false );
+ connect( mLocal.resourceCheck, SIGNAL( toggled(bool) ),
+ mLocal.resourceClearButton, SLOT( setEnabled(bool) ) );
+ connect( mLocal.resourceClearButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearResourceAllocations() ) );
+ mLocal.resourceClearPastButton =
+ new QPushButton( i18n( "Clear Past" ), resourceHB );
+ mLocal.resourceClearPastButton->setEnabled( false );
+ connect( mLocal.resourceCheck, SIGNAL( toggled(bool) ),
+ mLocal.resourceClearPastButton, SLOT( setEnabled(bool) ) );
+ QWhatsThis::add( mLocal.resourceClearPastButton,
+ i18n( "Delete all outdated allocations for the resource represented by this account." ) );
+ connect( mLocal.resourceClearPastButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearPastResourceAllocations() ) );
+ topLayout->addMultiCellWidget( resourceHB, 5, 5, 0, 2 );
+#endif
+
+ mLocal.includeInCheck =
+ new QCheckBox( i18n("Include in m&anual mail check"),
+ page );
+ topLayout->addMultiCellWidget( mLocal.includeInCheck, 5, 5, 0, 2 );
+
+ mLocal.intervalCheck =
+ new QCheckBox( i18n("Enable &interval mail checking"), page );
+ topLayout->addMultiCellWidget( mLocal.intervalCheck, 6, 6, 0, 2 );
+ connect( mLocal.intervalCheck, SIGNAL(toggled(bool)),
+ this, SLOT(slotEnableLocalInterval(bool)) );
+ mLocal.intervalLabel = new QLabel( i18n("Check inter&val:"), page );
+ topLayout->addWidget( mLocal.intervalLabel, 7, 0 );
+ mLocal.intervalSpin = new KIntNumInput( page );
+ mLocal.intervalLabel->setBuddy( mLocal.intervalSpin );
+ mLocal.intervalSpin->setRange( GlobalSettings::self()->minimumCheckInterval(), 10000, 1, false );
+ mLocal.intervalSpin->setSuffix( i18n(" min") );
+ mLocal.intervalSpin->setValue( defaultmailcheckintervalmin );
+ topLayout->addWidget( mLocal.intervalSpin, 7, 1 );
+
+ label = new QLabel( i18n("&Destination folder:"), page );
+ topLayout->addWidget( label, 8, 0 );
+ mLocal.folderCombo = new QComboBox( false, page );
+ label->setBuddy( mLocal.folderCombo );
+ topLayout->addWidget( mLocal.folderCombo, 8, 1 );
+
+ label = new QLabel( i18n("&Pre-command:"), page );
+ topLayout->addWidget( label, 9, 0 );
+ mLocal.precommand = new KLineEdit( page );
+ label->setBuddy( mLocal.precommand );
+ topLayout->addWidget( mLocal.precommand, 9, 1 );
+
+ mLocal.identityLabel = new QLabel( i18n("Identity:"), page );
+ topLayout->addWidget( mLocal.identityLabel, 10, 0 );
+ mLocal.identityCombo = new KPIM::IdentityCombo(kmkernel->identityManager(), page );
+ mLocal.identityLabel->setBuddy( mLocal.identityCombo );
+ topLayout->addWidget( mLocal.identityCombo, 10, 1 );
+
+ connect(kapp,SIGNAL(kdisplayFontChanged()),SLOT(slotFontChanged()));
+}
+
+void AccountDialog::makeMaildirAccountPage()
+{
+ ProcmailRCParser procmailrcParser;
+
+ QFrame *page = makeMainWidget();
+ QGridLayout *topLayout = new QGridLayout( page, 11, 3, 0, spacingHint() );
+ topLayout->addColSpacing( 1, fontMetrics().maxWidth()*15 );
+ topLayout->setRowStretch( 11, 10 );
+ topLayout->setColStretch( 1, 10 );
+
+ mMaildir.titleLabel = new QLabel( i18n("Account Type: Maildir Account"), page );
+ topLayout->addMultiCellWidget( mMaildir.titleLabel, 0, 0, 0, 2 );
+ QFont titleFont( mMaildir.titleLabel->font() );
+ titleFont.setBold( true );
+ mMaildir.titleLabel->setFont( titleFont );
+ QFrame *hline = new QFrame( page );
+ hline->setFrameStyle( QFrame::Sunken | QFrame::HLine );
+ topLayout->addMultiCellWidget( hline, 1, 1, 0, 2 );
+
+ mMaildir.nameEdit = new KLineEdit( page );
+ topLayout->addWidget( mMaildir.nameEdit, 2, 1 );
+ QLabel *label = new QLabel( mMaildir.nameEdit, i18n("Account &name:"), page );
+ topLayout->addWidget( label, 2, 0 );
+
+ mMaildir.locationEdit = new QComboBox( true, page );
+ topLayout->addWidget( mMaildir.locationEdit, 3, 1 );
+ mMaildir.locationEdit->insertStringList(procmailrcParser.getSpoolFilesList());
+ label = new QLabel( mMaildir.locationEdit, i18n("Folder &location:"), page );
+ topLayout->addWidget( label, 3, 0 );
+
+ QPushButton *choose = new QPushButton( i18n("Choo&se..."), page );
+ choose->setAutoDefault( false );
+ connect( choose, SIGNAL(clicked()), this, SLOT(slotMaildirChooser()) );
+ topLayout->addWidget( choose, 3, 2 );
+
+#if 0
+ QHBox* resourceHB = new QHBox( page );
+ resourceHB->setSpacing( 11 );
+ mMaildir.resourceCheck =
+ new QCheckBox( i18n( "Account for semiautomatic resource handling" ), resourceHB );
+ mMaildir.resourceClearButton =
+ new QPushButton( i18n( "Clear" ), resourceHB );
+ mMaildir.resourceClearButton->setEnabled( false );
+ connect( mMaildir.resourceCheck, SIGNAL( toggled(bool) ),
+ mMaildir.resourceClearButton, SLOT( setEnabled(bool) ) );
+ QWhatsThis::add( mMaildir.resourceClearButton,
+ i18n( "Delete all allocations for the resource represented by this account." ) );
+ connect( mMaildir.resourceClearButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearResourceAllocations() ) );
+ mMaildir.resourceClearPastButton =
+ new QPushButton( i18n( "Clear Past" ), resourceHB );
+ mMaildir.resourceClearPastButton->setEnabled( false );
+ connect( mMaildir.resourceCheck, SIGNAL( toggled(bool) ),
+ mMaildir.resourceClearPastButton, SLOT( setEnabled(bool) ) );
+ QWhatsThis::add( mMaildir.resourceClearPastButton,
+ i18n( "Delete all outdated allocations for the resource represented by this account." ) );
+ connect( mMaildir.resourceClearPastButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearPastResourceAllocations() ) );
+ topLayout->addMultiCellWidget( resourceHB, 4, 4, 0, 2 );
+#endif
+
+ mMaildir.includeInCheck =
+ new QCheckBox( i18n("Include in &manual mail check"), page );
+ topLayout->addMultiCellWidget( mMaildir.includeInCheck, 4, 4, 0, 2 );
+
+ mMaildir.intervalCheck =
+ new QCheckBox( i18n("Enable &interval mail checking"), page );
+ topLayout->addMultiCellWidget( mMaildir.intervalCheck, 5, 5, 0, 2 );
+ connect( mMaildir.intervalCheck, SIGNAL(toggled(bool)),
+ this, SLOT(slotEnableMaildirInterval(bool)) );
+ mMaildir.intervalLabel = new QLabel( i18n("Check inter&val:"), page );
+ topLayout->addWidget( mMaildir.intervalLabel, 6, 0 );
+ mMaildir.intervalSpin = new KIntNumInput( page );
+ mMaildir.intervalSpin->setRange( GlobalSettings::self()->minimumCheckInterval(), 10000, 1, false );
+ mMaildir.intervalSpin->setSuffix( i18n(" min") );
+ mMaildir.intervalSpin->setValue( defaultmailcheckintervalmin );
+ mMaildir.intervalLabel->setBuddy( mMaildir.intervalSpin );
+ topLayout->addWidget( mMaildir.intervalSpin, 6, 1 );
+
+ mMaildir.folderCombo = new QComboBox( false, page );
+ topLayout->addWidget( mMaildir.folderCombo, 7, 1 );
+ label = new QLabel( mMaildir.folderCombo,
+ i18n("&Destination folder:"), page );
+ topLayout->addWidget( label, 7, 0 );
+
+ mMaildir.precommand = new KLineEdit( page );
+ topLayout->addWidget( mMaildir.precommand, 8, 1 );
+ label = new QLabel( mMaildir.precommand, i18n("&Pre-command:"), page );
+ topLayout->addWidget( label, 8, 0 );
+
+
+ mMaildir.identityLabel = new QLabel( i18n("Identity:"), page );
+ topLayout->addWidget( mMaildir.identityLabel, 9, 0 );
+ mMaildir.identityCombo = new KPIM::IdentityCombo(kmkernel->identityManager(), page );
+ mMaildir.identityLabel->setBuddy( mMaildir.identityCombo );
+ topLayout->addWidget( mMaildir.identityCombo, 9, 1 );
+
+ connect(kapp,SIGNAL(kdisplayFontChanged()),SLOT(slotFontChanged()));
+}
+
+
+void AccountDialog::makePopAccountPage()
+{
+ QFrame *page = makeMainWidget();
+ QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+ mPop.titleLabel = new QLabel( page );
+ mPop.titleLabel->setText( i18n("Account Type: POP Account") );
+ QFont titleFont( mPop.titleLabel->font() );
+ titleFont.setBold( true );
+ mPop.titleLabel->setFont( titleFont );
+ topLayout->addWidget( mPop.titleLabel );
+ KSeparator *hline = new KSeparator( KSeparator::HLine, page);
+ topLayout->addWidget( hline );
+
+ QTabWidget *tabWidget = new QTabWidget(page);
+ topLayout->addWidget( tabWidget );
+
+ QWidget *page1 = new QWidget( tabWidget );
+ tabWidget->addTab( page1, i18n("&General") );
+
+ QGridLayout *grid = new QGridLayout( page1, 16, 2, marginHint(), spacingHint() );
+ grid->addColSpacing( 1, fontMetrics().maxWidth()*15 );
+ grid->setRowStretch( 15, 10 );
+ grid->setColStretch( 1, 10 );
+
+ QLabel *label = new QLabel( i18n("Account &name:"), page1 );
+ grid->addWidget( label, 0, 0 );
+ mPop.nameEdit = new KLineEdit( page1 );
+ label->setBuddy( mPop.nameEdit );
+ grid->addWidget( mPop.nameEdit, 0, 1 );
+
+ label = new QLabel( i18n("&Login:"), page1 );
+ QWhatsThis::add( label, i18n("Your Internet Service Provider gave you a <em>user name</em> which is used to authenticate you with their servers. It usually is the first part of your email address (the part before <em>@</em>).") );
+ grid->addWidget( label, 1, 0 );
+ mPop.loginEdit = new KLineEdit( page1 );
+ label->setBuddy( mPop.loginEdit );
+ grid->addWidget( mPop.loginEdit, 1, 1 );
+
+ label = new QLabel( i18n("P&assword:"), page1 );
+ grid->addWidget( label, 2, 0 );
+ mPop.passwordEdit = new KLineEdit( page1 );
+ mPop.passwordEdit->setEchoMode( QLineEdit::Password );
+ label->setBuddy( mPop.passwordEdit );
+ grid->addWidget( mPop.passwordEdit, 2, 1 );
+
+ label = new QLabel( i18n("Ho&st:"), page1 );
+ grid->addWidget( label, 3, 0 );
+ mPop.hostEdit = new KLineEdit( page1 );
+ // only letters, digits, '-', '.', ':' (IPv6) and '_' (for Windows
+ // compatibility) are allowed
+ mPop.hostEdit->setValidator(mValidator);
+ label->setBuddy( mPop.hostEdit );
+ grid->addWidget( mPop.hostEdit, 3, 1 );
+
+ label = new QLabel( i18n("&Port:"), page1 );
+ grid->addWidget( label, 4, 0 );
+ mPop.portEdit = new KLineEdit( page1 );
+ mPop.portEdit->setValidator( new QIntValidator(this) );
+ label->setBuddy( mPop.portEdit );
+ grid->addWidget( mPop.portEdit, 4, 1 );
+
+ mPop.storePasswordCheck =
+ new QCheckBox( i18n("Sto&re POP password"), page1 );
+ QWhatsThis::add( mPop.storePasswordCheck,
+ i18n("Check this option to have KMail store "
+ "the password.\nIf KWallet is available "
+ "the password will be stored there which is considered "
+ "safe.\nHowever, if KWallet is not available, "
+ "the password will be stored in KMail's configuration "
+ "file. The password is stored in an "
+ "obfuscated format, but should not be "
+ "considered secure from decryption efforts "
+ "if access to the configuration file is obtained.") );
+ grid->addMultiCellWidget( mPop.storePasswordCheck, 5, 5, 0, 1 );
+
+ mPop.leaveOnServerCheck =
+ new QCheckBox( i18n("Lea&ve fetched messages on the server"), page1 );
+ connect( mPop.leaveOnServerCheck, SIGNAL( clicked() ),
+ this, SLOT( slotLeaveOnServerClicked() ) );
+ grid->addMultiCellWidget( mPop.leaveOnServerCheck, 6, 6, 0, 1 );
+ QHBox *afterDaysBox = new QHBox( page1 );
+ afterDaysBox->setSpacing( KDialog::spacingHint() );
+ mPop.leaveOnServerDaysCheck =
+ new QCheckBox( i18n("Leave messages on the server for"), afterDaysBox );
+ connect( mPop.leaveOnServerDaysCheck, SIGNAL( toggled(bool) ),
+ this, SLOT( slotEnableLeaveOnServerDays(bool)) );
+ mPop.leaveOnServerDaysSpin = new KIntNumInput( afterDaysBox );
+ mPop.leaveOnServerDaysSpin->setRange( 1, 365, 1, false );
+ connect( mPop.leaveOnServerDaysSpin, SIGNAL(valueChanged(int)),
+ SLOT(slotLeaveOnServerDaysChanged(int)));
+ mPop.leaveOnServerDaysSpin->setValue( 1 );
+ afterDaysBox->setStretchFactor( mPop.leaveOnServerDaysSpin, 1 );
+ grid->addMultiCellWidget( afterDaysBox, 7, 7, 0, 1 );
+ QHBox *leaveOnServerCountBox = new QHBox( page1 );
+ leaveOnServerCountBox->setSpacing( KDialog::spacingHint() );
+ mPop.leaveOnServerCountCheck =
+ new QCheckBox( i18n("Keep only the last"), leaveOnServerCountBox );
+ connect( mPop.leaveOnServerCountCheck, SIGNAL( toggled(bool) ),
+ this, SLOT( slotEnableLeaveOnServerCount(bool)) );
+ mPop.leaveOnServerCountSpin = new KIntNumInput( leaveOnServerCountBox );
+ mPop.leaveOnServerCountSpin->setRange( 1, 999999, 1, false );
+ connect( mPop.leaveOnServerCountSpin, SIGNAL(valueChanged(int)),
+ SLOT(slotLeaveOnServerCountChanged(int)));
+ mPop.leaveOnServerCountSpin->setValue( 100 );
+ grid->addMultiCellWidget( leaveOnServerCountBox, 8, 8, 0, 1 );
+ QHBox *leaveOnServerSizeBox = new QHBox( page1 );
+ leaveOnServerSizeBox->setSpacing( KDialog::spacingHint() );
+ mPop.leaveOnServerSizeCheck =
+ new QCheckBox( i18n("Keep only the last"), leaveOnServerSizeBox );
+ connect( mPop.leaveOnServerSizeCheck, SIGNAL( toggled(bool) ),
+ this, SLOT( slotEnableLeaveOnServerSize(bool)) );
+ mPop.leaveOnServerSizeSpin = new KIntNumInput( leaveOnServerSizeBox );
+ mPop.leaveOnServerSizeSpin->setRange( 1, 999999, 1, false );
+ mPop.leaveOnServerSizeSpin->setSuffix( i18n(" MB") );
+ mPop.leaveOnServerSizeSpin->setValue( 10 );
+ grid->addMultiCellWidget( leaveOnServerSizeBox, 9, 9, 0, 1 );
+#if 0
+ QHBox *resourceHB = new QHBox( page1 );
+ resourceHB->setSpacing( 11 );
+ mPop.resourceCheck =
+ new QCheckBox( i18n( "Account for semiautomatic resource handling" ), resourceHB );
+ mPop.resourceClearButton =
+ new QPushButton( i18n( "Clear" ), resourceHB );
+ mPop.resourceClearButton->setEnabled( false );
+ connect( mPop.resourceCheck, SIGNAL( toggled(bool) ),
+ mPop.resourceClearButton, SLOT( setEnabled(bool) ) );
+ QWhatsThis::add( mPop.resourceClearButton,
+ i18n( "Delete all allocations for the resource represented by this account." ) );
+ connect( mPop.resourceClearButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearResourceAllocations() ) );
+ mPop.resourceClearPastButton =
+ new QPushButton( i18n( "Clear Past" ), resourceHB );
+ mPop.resourceClearPastButton->setEnabled( false );
+ connect( mPop.resourceCheck, SIGNAL( toggled(bool) ),
+ mPop.resourceClearPastButton, SLOT( setEnabled(bool) ) );
+ QWhatsThis::add( mPop.resourceClearPastButton,
+ i18n( "Delete all outdated allocations for the resource represented by this account." ) );
+ connect( mPop.resourceClearPastButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearPastResourceAllocations() ) );
+ grid->addMultiCellWidget( resourceHB, 10, 10, 0, 2 );
+#endif
+
+ mPop.includeInCheck =
+ new QCheckBox( i18n("Include in man&ual mail check"), page1 );
+ grid->addMultiCellWidget( mPop.includeInCheck, 10, 10, 0, 1 );
+
+ QHBox * hbox = new QHBox( page1 );
+ hbox->setSpacing( KDialog::spacingHint() );
+ mPop.filterOnServerCheck =
+ new QCheckBox( i18n("&Filter messages if they are greater than"), hbox );
+ mPop.filterOnServerSizeSpin = new KIntNumInput ( hbox );
+ mPop.filterOnServerSizeSpin->setEnabled( false );
+ hbox->setStretchFactor( mPop.filterOnServerSizeSpin, 1 );
+ mPop.filterOnServerSizeSpin->setRange( 1, 10000000, 100, false );
+ connect(mPop.filterOnServerSizeSpin, SIGNAL(valueChanged(int)),
+ SLOT(slotFilterOnServerSizeChanged(int)));
+ mPop.filterOnServerSizeSpin->setValue( 50000 );
+ grid->addMultiCellWidget( hbox, 11, 11, 0, 1 );
+ connect( mPop.filterOnServerCheck, SIGNAL(toggled(bool)),
+ mPop.filterOnServerSizeSpin, SLOT(setEnabled(bool)) );
+ connect( mPop.filterOnServerCheck, SIGNAL( clicked() ),
+ this, SLOT( slotFilterOnServerClicked() ) );
+ QString msg = i18n("If you select this option, POP Filters will be used to "
+ "decide what to do with messages. You can then select "
+ "to download, delete or keep them on the server." );
+ QWhatsThis::add( mPop.filterOnServerCheck, msg );
+ QWhatsThis::add( mPop.filterOnServerSizeSpin, msg );
+
+ mPop.intervalCheck =
+ new QCheckBox( i18n("Enable &interval mail checking"), page1 );
+ grid->addMultiCellWidget( mPop.intervalCheck, 12, 12, 0, 1 );
+ connect( mPop.intervalCheck, SIGNAL(toggled(bool)),
+ this, SLOT(slotEnablePopInterval(bool)) );
+ mPop.intervalLabel = new QLabel( i18n("Chec&k interval:"), page1 );
+ grid->addWidget( mPop.intervalLabel, 13, 0 );
+ mPop.intervalSpin = new KIntNumInput( page1 );
+ mPop.intervalSpin->setRange( GlobalSettings::self()->minimumCheckInterval(), 10000, 1, false );
+ mPop.intervalSpin->setSuffix( i18n(" min") );
+ mPop.intervalSpin->setValue( defaultmailcheckintervalmin );
+ mPop.intervalLabel->setBuddy( mPop.intervalSpin );
+ grid->addWidget( mPop.intervalSpin, 13, 1 );
+
+ label = new QLabel( i18n("Des&tination folder:"), page1 );
+ grid->addWidget( label, 14, 0 );
+ mPop.folderCombo = new QComboBox( false, page1 );
+ label->setBuddy( mPop.folderCombo );
+ grid->addWidget( mPop.folderCombo, 14, 1 );
+
+ label = new QLabel( i18n("Pre-com&mand:"), page1 );
+ grid->addWidget( label, 15, 0 );
+ mPop.precommand = new KLineEdit( page1 );
+ label->setBuddy(mPop.precommand);
+ grid->addWidget( mPop.precommand, 15, 1 );
+
+ mPop.identityLabel = new QLabel( i18n("Identity:"), page1 );
+ grid->addWidget( mPop.identityLabel, 16, 0 );
+ mPop.identityCombo = new KPIM::IdentityCombo(kmkernel->identityManager(), page1 );
+ mPop.identityLabel->setBuddy( mPop.identityCombo );
+ grid->addWidget( mPop.identityCombo, 16, 1 );
+
+ QWidget *page2 = new QWidget( tabWidget );
+ tabWidget->addTab( page2, i18n("&Extras") );
+ QVBoxLayout *vlay = new QVBoxLayout( page2, marginHint(), spacingHint() );
+
+ vlay->addSpacing( KDialog::spacingHint() );
+
+ QHBoxLayout *buttonLay = new QHBoxLayout( vlay );
+ mPop.checkCapabilities =
+ new QPushButton( i18n("Check &What the Server Supports"), page2 );
+ connect(mPop.checkCapabilities, SIGNAL(clicked()),
+ SLOT(slotCheckPopCapabilities()));
+ buttonLay->addStretch();
+ buttonLay->addWidget( mPop.checkCapabilities );
+ buttonLay->addStretch();
+
+ vlay->addSpacing( KDialog::spacingHint() );
+
+ mPop.encryptionGroup = new QButtonGroup( 1, Qt::Horizontal,
+ i18n("Encryption"), page2 );
+ mPop.encryptionNone =
+ new QRadioButton( i18n("&None"), mPop.encryptionGroup );
+ mPop.encryptionSSL =
+ new QRadioButton( i18n("Use &SSL for secure mail download"),
+ mPop.encryptionGroup );
+ mPop.encryptionTLS =
+ new QRadioButton( i18n("Use &TLS for secure mail download"),
+ mPop.encryptionGroup );
+ connect(mPop.encryptionGroup, SIGNAL(clicked(int)),
+ SLOT(slotPopEncryptionChanged(int)));
+ vlay->addWidget( mPop.encryptionGroup );
+
+ mPop.authGroup = new QButtonGroup( 1, Qt::Horizontal,
+ i18n("Authentication Method"), page2 );
+ mPop.authUser = new QRadioButton( i18n("Clear te&xt") , mPop.authGroup,
+ "auth clear text" );
+ mPop.authLogin = new QRadioButton( i18n("Please translate this "
+ "authentication method only if you have a good reason", "&LOGIN"),
+ mPop.authGroup, "auth login" );
+ mPop.authPlain = new QRadioButton( i18n("Please translate this "
+ "authentication method only if you have a good reason", "&PLAIN"),
+ mPop.authGroup, "auth plain" );
+ mPop.authCRAM_MD5 = new QRadioButton( i18n("CRAM-MD&5"), mPop.authGroup, "auth cram-md5" );
+ mPop.authDigestMd5 = new QRadioButton( i18n("&DIGEST-MD5"), mPop.authGroup, "auth digest-md5" );
+ mPop.authNTLM = new QRadioButton( i18n("&NTLM"), mPop.authGroup, "auth ntlm" );
+ mPop.authGSSAPI = new QRadioButton( i18n("&GSSAPI"), mPop.authGroup, "auth gssapi" );
+ if ( KProtocolInfo::capabilities("pop3").contains("SASL") == 0 )
+ {
+ mPop.authNTLM->hide();
+ mPop.authGSSAPI->hide();
+ }
+ mPop.authAPOP = new QRadioButton( i18n("&APOP"), mPop.authGroup, "auth apop" );
+
+ vlay->addWidget( mPop.authGroup );
+
+ mPop.usePipeliningCheck =
+ new QCheckBox( i18n("&Use pipelining for faster mail download"), page2 );
+ connect(mPop.usePipeliningCheck, SIGNAL(clicked()),
+ SLOT(slotPipeliningClicked()));
+ vlay->addWidget( mPop.usePipeliningCheck );
+
+ vlay->addStretch();
+
+ connect(kapp,SIGNAL(kdisplayFontChanged()),SLOT(slotFontChanged()));
+}
+
+
+void AccountDialog::makeImapAccountPage( bool connected )
+{
+ QFrame *page = makeMainWidget();
+ QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+ mImap.titleLabel = new QLabel( page );
+ if( connected )
+ mImap.titleLabel->setText( i18n("Account Type: Disconnected IMAP Account") );
+ else
+ mImap.titleLabel->setText( i18n("Account Type: IMAP Account") );
+ QFont titleFont( mImap.titleLabel->font() );
+ titleFont.setBold( true );
+ mImap.titleLabel->setFont( titleFont );
+ topLayout->addWidget( mImap.titleLabel );
+ KSeparator *hline = new KSeparator( KSeparator::HLine, page);
+ topLayout->addWidget( hline );
+
+ QTabWidget *tabWidget = new QTabWidget(page);
+ topLayout->addWidget( tabWidget );
+
+ QWidget *page1 = new QWidget( tabWidget );
+ tabWidget->addTab( page1, i18n("&General") );
+
+ int row = -1;
+ QGridLayout *grid = new QGridLayout( page1, 16, 2, marginHint(), spacingHint() );
+ grid->addColSpacing( 1, fontMetrics().maxWidth()*16 );
+
+ ++row;
+ QLabel *label = new QLabel( i18n("Account &name:"), page1 );
+ grid->addWidget( label, row, 0 );
+ mImap.nameEdit = new KLineEdit( page1 );
+ label->setBuddy( mImap.nameEdit );
+ grid->addWidget( mImap.nameEdit, row, 1 );
+
+ ++row;
+ label = new QLabel( i18n("&Login:"), page1 );
+ QWhatsThis::add( label, i18n("Your Internet Service Provider gave you a <em>user name</em> which is used to authenticate you with their servers. It usually is the first part of your email address (the part before <em>@</em>).") );
+ grid->addWidget( label, row, 0 );
+ mImap.loginEdit = new KLineEdit( page1 );
+ label->setBuddy( mImap.loginEdit );
+ grid->addWidget( mImap.loginEdit, row, 1 );
+
+ ++row;
+ label = new QLabel( i18n("P&assword:"), page1 );
+ grid->addWidget( label, row, 0 );
+ mImap.passwordEdit = new KLineEdit( page1 );
+ mImap.passwordEdit->setEchoMode( QLineEdit::Password );
+ label->setBuddy( mImap.passwordEdit );
+ grid->addWidget( mImap.passwordEdit, row, 1 );
+
+ ++row;
+ label = new QLabel( i18n("Ho&st:"), page1 );
+ grid->addWidget( label, row, 0 );
+ mImap.hostEdit = new KLineEdit( page1 );
+ // only letters, digits, '-', '.', ':' (IPv6) and '_' (for Windows
+ // compatibility) are allowed
+ mImap.hostEdit->setValidator(mValidator);
+ label->setBuddy( mImap.hostEdit );
+ grid->addWidget( mImap.hostEdit, row, 1 );
+
+ ++row;
+ label = new QLabel( i18n("&Port:"), page1 );
+ grid->addWidget( label, row, 0 );
+ mImap.portEdit = new KLineEdit( page1 );
+ mImap.portEdit->setValidator( new QIntValidator(this) );
+ label->setBuddy( mImap.portEdit );
+ grid->addWidget( mImap.portEdit, row, 1 );
+
+ // namespace list
+ ++row;
+ QHBox* box = new QHBox( page1 );
+ label = new QLabel( i18n("Namespaces:"), box );
+ QWhatsThis::add( label, i18n( "Here you see the different namespaces that your IMAP server supports."
+ "Each namespace represents a prefix that separates groups of folders."
+ "Namespaces allow KMail for example to display your personal folders and shared folders in one account." ) );
+ // button to reload
+ QToolButton* button = new QToolButton( box );
+ button->setAutoRaise(true);
+ button->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ button->setFixedSize( 22, 22 );
+ button->setIconSet(
+ KGlobal::iconLoader()->loadIconSet( "reload", KIcon::Small, 0 ) );
+ connect( button, SIGNAL(clicked()), this, SLOT(slotReloadNamespaces()) );
+ QWhatsThis::add( button,
+ i18n("Reload the namespaces from the server. This overwrites any changes.") );
+ grid->addWidget( box, row, 0 );
+
+ // grid with label, namespace list and edit button
+ QGrid* listbox = new QGrid( 3, page1 );
+ label = new QLabel( i18n("Personal"), listbox );
+ QWhatsThis::add( label, i18n( "Personal namespaces include your personal folders." ) );
+ mImap.personalNS = new KLineEdit( listbox );
+ mImap.personalNS->setReadOnly( true );
+ mImap.editPNS = new QToolButton( listbox );
+ mImap.editPNS->setIconSet(
+ KGlobal::iconLoader()->loadIconSet( "edit", KIcon::Small, 0 ) );
+ mImap.editPNS->setAutoRaise( true );
+ mImap.editPNS->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ mImap.editPNS->setFixedSize( 22, 22 );
+ connect( mImap.editPNS, SIGNAL(clicked()), this, SLOT(slotEditPersonalNamespace()) );
+
+ label = new QLabel( i18n("Other Users"), listbox );
+ QWhatsThis::add( label, i18n( "These namespaces include the folders of other users." ) );
+ mImap.otherUsersNS = new KLineEdit( listbox );
+ mImap.otherUsersNS->setReadOnly( true );
+ mImap.editONS = new QToolButton( listbox );
+ mImap.editONS->setIconSet(
+ KGlobal::iconLoader()->loadIconSet( "edit", KIcon::Small, 0 ) );
+ mImap.editONS->setAutoRaise( true );
+ mImap.editONS->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ mImap.editONS->setFixedSize( 22, 22 );
+ connect( mImap.editONS, SIGNAL(clicked()), this, SLOT(slotEditOtherUsersNamespace()) );
+
+ label = new QLabel( i18n("Shared"), listbox );
+ QWhatsThis::add( label, i18n( "These namespaces include the shared folders." ) );
+ mImap.sharedNS = new KLineEdit( listbox );
+ mImap.sharedNS->setReadOnly( true );
+ mImap.editSNS = new QToolButton( listbox );
+ mImap.editSNS->setIconSet(
+ KGlobal::iconLoader()->loadIconSet( "edit", KIcon::Small, 0 ) );
+ mImap.editSNS->setAutoRaise( true );
+ mImap.editSNS->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ mImap.editSNS->setFixedSize( 22, 22 );
+ connect( mImap.editSNS, SIGNAL(clicked()), this, SLOT(slotEditSharedNamespace()) );
+
+ label->setBuddy( listbox );
+ grid->addWidget( listbox, row, 1 );
+
+ ++row;
+ mImap.storePasswordCheck =
+ new QCheckBox( i18n("Sto&re IMAP password"), page1 );
+ QWhatsThis::add( mImap.storePasswordCheck,
+ i18n("Check this option to have KMail store "
+ "the password.\nIf KWallet is available "
+ "the password will be stored there which is considered "
+ "safe.\nHowever, if KWallet is not available, "
+ "the password will be stored in KMail's configuration "
+ "file. The password is stored in an "
+ "obfuscated format, but should not be "
+ "considered secure from decryption efforts "
+ "if access to the configuration file is obtained.") );
+ grid->addMultiCellWidget( mImap.storePasswordCheck, row, row, 0, 1 );
+
+ if( !connected ) {
+ ++row;
+ mImap.autoExpungeCheck =
+ new QCheckBox( i18n("Automaticall&y compact folders (expunges deleted messages)"), page1);
+ grid->addMultiCellWidget( mImap.autoExpungeCheck, row, row, 0, 1 );
+ }
+
+ ++row;
+ mImap.hiddenFoldersCheck = new QCheckBox( i18n("Sho&w hidden folders"), page1);
+ grid->addMultiCellWidget( mImap.hiddenFoldersCheck, row, row, 0, 1 );
+
+
+ ++row;
+ mImap.subscribedFoldersCheck = new QCheckBox(
+ i18n("Show only s&ubscribed folders"), page1);
+ grid->addMultiCellWidget( mImap.subscribedFoldersCheck, row, row, 0, 1 );
+
+ ++row;
+ mImap.locallySubscribedFoldersCheck = new QCheckBox(
+ i18n("Show only &locally subscribed folders"), page1);
+ grid->addMultiCellWidget( mImap.locallySubscribedFoldersCheck, row, row, 0, 1 );
+
+ if ( !connected ) {
+ // not implemented for disconnected yet
+ ++row;
+ mImap.loadOnDemandCheck = new QCheckBox(
+ i18n("Load attach&ments on demand"), page1);
+ QWhatsThis::add( mImap.loadOnDemandCheck,
+ i18n("Activate this to load attachments not automatically when you select the email but only when you click on the attachment. This way also big emails are shown instantly.") );
+ grid->addMultiCellWidget( mImap.loadOnDemandCheck, row, row, 0, 1 );
+ }
+
+ if ( !connected ) {
+ // not implemented for disconnected yet
+ ++row;
+ mImap.listOnlyOpenCheck = new QCheckBox(
+ i18n("List only open folders"), page1);
+ QWhatsThis::add( mImap.listOnlyOpenCheck,
+ i18n("Only folders that are open (expanded) in the folder tree are checked for subfolders. Use this if there are many folders on the server.") );
+ grid->addMultiCellWidget( mImap.listOnlyOpenCheck, row, row, 0, 1 );
+ }
+
+#if 0
+ ++row;
+ QHBox* resourceHB = new QHBox( page1 );
+ resourceHB->setSpacing( 11 );
+ mImap.resourceCheck =
+ new QCheckBox( i18n( "Account for semiautomatic resource handling" ), resourceHB );
+ mImap.resourceClearButton =
+ new QPushButton( i18n( "Clear" ), resourceHB );
+ mImap.resourceClearButton->setEnabled( false );
+ connect( mImap.resourceCheck, SIGNAL( toggled(bool) ),
+ mImap.resourceClearButton, SLOT( setEnabled(bool) ) );
+ QWhatsThis::add( mImap.resourceClearButton,
+ i18n( "Delete all allocations for the resource represented by this account." ) );
+ connect( mImap.resourceClearButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearResourceAllocations() ) );
+ mImap.resourceClearPastButton =
+ new QPushButton( i18n( "Clear Past" ), resourceHB );
+ mImap.resourceClearPastButton->setEnabled( false );
+ connect( mImap.resourceCheck, SIGNAL( toggled(bool) ),
+ mImap.resourceClearPastButton, SLOT( setEnabled(bool) ) );
+ QWhatsThis::add( mImap.resourceClearPastButton,
+ i18n( "Delete all outdated allocations for the resource represented by this account." ) );
+ connect( mImap.resourceClearPastButton, SIGNAL( clicked() ),
+ this, SLOT( slotClearPastResourceAllocations() ) );
+ grid->addMultiCellWidget( resourceHB, row, row, 0, 2 );
+#endif
+
+ ++row;
+ mImap.includeInCheck =
+ new QCheckBox( i18n("Include in manual mail chec&k"), page1 );
+ grid->addMultiCellWidget( mImap.includeInCheck, row, row, 0, 1 );
+
+ ++row;
+ mImap.intervalCheck =
+ new QCheckBox( i18n("Enable &interval mail checking"), page1 );
+ grid->addMultiCellWidget( mImap.intervalCheck, row, row, 0, 2 );
+ connect( mImap.intervalCheck, SIGNAL(toggled(bool)),
+ this, SLOT(slotEnableImapInterval(bool)) );
+ ++row;
+ mImap.intervalLabel = new QLabel( i18n("Check inter&val:"), page1 );
+ grid->addWidget( mImap.intervalLabel, row, 0 );
+ mImap.intervalSpin = new KIntNumInput( page1 );
+ mImap.intervalSpin->setRange( GlobalSettings::minimumCheckInterval(), 60, 1, false );
+ mImap.intervalSpin->setValue( defaultmailcheckintervalmin );
+ mImap.intervalSpin->setSuffix( i18n( " min" ) );
+ mImap.intervalLabel->setBuddy( mImap.intervalSpin );
+ grid->addWidget( mImap.intervalSpin, row, 1 );
+
+ ++row;
+ label = new QLabel( i18n("&Trash folder:"), page1 );
+ grid->addWidget( label, row, 0 );
+ mImap.trashCombo = new FolderRequester( page1,
+ kmkernel->getKMMainWidget()->folderTree() );
+ mImap.trashCombo->setShowOutbox( false );
+ label->setBuddy( mImap.trashCombo );
+ grid->addWidget( mImap.trashCombo, row, 1 );
+
+ ++row;
+ mImap.identityLabel = new QLabel( i18n("Identity:"), page1 );
+ grid->addWidget( mImap.identityLabel, row, 0 );
+ mImap.identityCombo = new KPIM::IdentityCombo(kmkernel->identityManager(), page1 );
+ mImap.identityLabel->setBuddy( mImap.identityCombo );
+ grid->addWidget( mImap.identityCombo, row, 1 );
+
+ QWidget *page2 = new QWidget( tabWidget );
+ tabWidget->addTab( page2, i18n("S&ecurity") );
+ QVBoxLayout *vlay = new QVBoxLayout( page2, marginHint(), spacingHint() );
+
+ vlay->addSpacing( KDialog::spacingHint() );
+
+ QHBoxLayout *buttonLay = new QHBoxLayout( vlay );
+ mImap.checkCapabilities =
+ new QPushButton( i18n("Check &What the Server Supports"), page2 );
+ connect(mImap.checkCapabilities, SIGNAL(clicked()),
+ SLOT(slotCheckImapCapabilities()));
+ buttonLay->addStretch();
+ buttonLay->addWidget( mImap.checkCapabilities );
+ buttonLay->addStretch();
+
+ vlay->addSpacing( KDialog::spacingHint() );
+
+ mImap.encryptionGroup = new QButtonGroup( 1, Qt::Horizontal,
+ i18n("Encryption"), page2 );
+ mImap.encryptionNone =
+ new QRadioButton( i18n("&None"), mImap.encryptionGroup );
+ mImap.encryptionSSL =
+ new QRadioButton( i18n("Use &SSL for secure mail download"),
+ mImap.encryptionGroup );
+ mImap.encryptionTLS =
+ new QRadioButton( i18n("Use &TLS for secure mail download"),
+ mImap.encryptionGroup );
+ connect(mImap.encryptionGroup, SIGNAL(clicked(int)),
+ SLOT(slotImapEncryptionChanged(int)));
+ vlay->addWidget( mImap.encryptionGroup );
+
+ mImap.authGroup = new QButtonGroup( 1, Qt::Horizontal,
+ i18n("Authentication Method"), page2 );
+ mImap.authUser = new QRadioButton( i18n("Clear te&xt"), mImap.authGroup );
+ mImap.authLogin = new QRadioButton( i18n("Please translate this "
+ "authentication method only if you have a good reason", "&LOGIN"),
+ mImap.authGroup );
+ mImap.authPlain = new QRadioButton( i18n("Please translate this "
+ "authentication method only if you have a good reason", "&PLAIN"),
+ mImap.authGroup );
+ mImap.authCramMd5 = new QRadioButton( i18n("CRAM-MD&5"), mImap.authGroup );
+ mImap.authDigestMd5 = new QRadioButton( i18n("&DIGEST-MD5"), mImap.authGroup );
+ mImap.authNTLM = new QRadioButton( i18n("&NTLM"), mImap.authGroup );
+ mImap.authGSSAPI = new QRadioButton( i18n("&GSSAPI"), mImap.authGroup );
+ mImap.authAnonymous = new QRadioButton( i18n("&Anonymous"), mImap.authGroup );
+ vlay->addWidget( mImap.authGroup );
+
+ vlay->addStretch();
+
+ // TODO (marc/bo): Test this
+ mSieveConfigEditor = new SieveConfigEditor( tabWidget );
+ mSieveConfigEditor->layout()->setMargin( KDialog::marginHint() );
+ tabWidget->addTab( mSieveConfigEditor, i18n("&Filtering") );
+
+ connect(kapp,SIGNAL(kdisplayFontChanged()),SLOT(slotFontChanged()));
+}
+
+
+void AccountDialog::setupSettings()
+{
+ QComboBox *folderCombo = 0;
+ int interval = mAccount->checkInterval();
+
+ QString accountType = mAccount->type();
+ if( accountType == "local" )
+ {
+ ProcmailRCParser procmailrcParser;
+ KMAcctLocal *acctLocal = dynamic_cast<KMAcctLocal*>(mAccount);
+
+ if ( acctLocal->location().isEmpty() )
+ acctLocal->setLocation( procmailrcParser.getSpoolFilesList().first() );
+ else
+ mLocal.locationEdit->insertItem( acctLocal->location() );
+
+ if ( acctLocal->procmailLockFileName().isEmpty() )
+ acctLocal->setProcmailLockFileName( procmailrcParser.getLockFilesList().first() );
+ else
+ mLocal.procmailLockFileName->insertItem( acctLocal->procmailLockFileName() );
+
+ mLocal.nameEdit->setText( mAccount->name() );
+ mLocal.nameEdit->setFocus();
+ mLocal.locationEdit->setEditText( acctLocal->location() );
+ if (acctLocal->lockType() == mutt_dotlock)
+ mLocal.lockMutt->setChecked(true);
+ else if (acctLocal->lockType() == mutt_dotlock_privileged)
+ mLocal.lockMuttPriv->setChecked(true);
+ else if (acctLocal->lockType() == procmail_lockfile) {
+ mLocal.lockProcmail->setChecked(true);
+ mLocal.procmailLockFileName->setEditText(acctLocal->procmailLockFileName());
+ } else if (acctLocal->lockType() == FCNTL)
+ mLocal.lockFcntl->setChecked(true);
+ else if (acctLocal->lockType() == lock_none)
+ mLocal.lockNone->setChecked(true);
+
+ if ( interval <= 0 ) mLocal.intervalSpin->setValue( defaultmailcheckintervalmin );
+ else mLocal.intervalSpin->setValue( interval );
+ mLocal.intervalCheck->setChecked( interval >= 1 );
+#if 0
+ mLocal.resourceCheck->setChecked( mAccount->resource() );
+#endif
+ mLocal.includeInCheck->setChecked( !mAccount->checkExclude() );
+ mLocal.precommand->setText( mAccount->precommand() );
+
+ slotEnableLocalInterval( interval >= 1 );
+ folderCombo = mLocal.folderCombo;
+ mLocal.identityCombo-> setCurrentIdentity( mAccount->identityId() );
+ }
+ else if( accountType == "pop" )
+ {
+ PopAccount &ap = *(PopAccount*)mAccount;
+ mPop.nameEdit->setText( mAccount->name() );
+ mPop.nameEdit->setFocus();
+ mPop.loginEdit->setText( ap.login() );
+ mPop.passwordEdit->setText( ap.passwd());
+ mPop.hostEdit->setText( ap.host() );
+ mPop.portEdit->setText( QString("%1").arg( ap.port() ) );
+ mPop.usePipeliningCheck->setChecked( ap.usePipelining() );
+ mPop.storePasswordCheck->setChecked( ap.storePasswd() );
+ mPop.leaveOnServerCheck->setChecked( ap.leaveOnServer() );
+ mPop.leaveOnServerDaysCheck->setEnabled( ap.leaveOnServer() );
+ mPop.leaveOnServerDaysCheck->setChecked( ap.leaveOnServerDays() >= 1 );
+ mPop.leaveOnServerDaysSpin->setValue( ap.leaveOnServerDays() >= 1 ?
+ ap.leaveOnServerDays() : 7 );
+ mPop.leaveOnServerCountCheck->setEnabled( ap.leaveOnServer() );
+ mPop.leaveOnServerCountCheck->setChecked( ap.leaveOnServerCount() >= 1 );
+ mPop.leaveOnServerCountSpin->setValue( ap.leaveOnServerCount() >= 1 ?
+ ap.leaveOnServerCount() : 100 );
+ mPop.leaveOnServerSizeCheck->setEnabled( ap.leaveOnServer() );
+ mPop.leaveOnServerSizeCheck->setChecked( ap.leaveOnServerSize() >= 1 );
+ mPop.leaveOnServerSizeSpin->setValue( ap.leaveOnServerSize() >= 1 ?
+ ap.leaveOnServerSize() : 10 );
+ mPop.filterOnServerCheck->setChecked( ap.filterOnServer() );
+ mPop.filterOnServerSizeSpin->setValue( ap.filterOnServerCheckSize() );
+ mPop.intervalCheck->setChecked( interval >= 1 );
+ if ( interval <= 0 ) mPop.intervalSpin->setValue( defaultmailcheckintervalmin );
+ else mPop.intervalSpin->setValue( interval );
+#if 0
+ mPop.resourceCheck->setChecked( mAccount->resource() );
+#endif
+ mPop.includeInCheck->setChecked( !mAccount->checkExclude() );
+ mPop.precommand->setText( ap.precommand() );
+ mPop.identityCombo-> setCurrentIdentity( mAccount->identityId() );
+ if (ap.useSSL())
+ mPop.encryptionSSL->setChecked( true );
+ else if (ap.useTLS())
+ mPop.encryptionTLS->setChecked( true );
+ else mPop.encryptionNone->setChecked( true );
+ if (ap.auth() == "LOGIN")
+ mPop.authLogin->setChecked( true );
+ else if (ap.auth() == "PLAIN")
+ mPop.authPlain->setChecked( true );
+ else if (ap.auth() == "CRAM-MD5")
+ mPop.authCRAM_MD5->setChecked( true );
+ else if (ap.auth() == "DIGEST-MD5")
+ mPop.authDigestMd5->setChecked( true );
+ else if (ap.auth() == "NTLM")
+ mPop.authNTLM->setChecked( true );
+ else if (ap.auth() == "GSSAPI")
+ mPop.authGSSAPI->setChecked( true );
+ else if (ap.auth() == "APOP")
+ mPop.authAPOP->setChecked( true );
+ else mPop.authUser->setChecked( true );
+
+ slotEnableLeaveOnServerDays( mPop.leaveOnServerDaysCheck->isEnabled() ?
+ ap.leaveOnServerDays() >= 1 : 0);
+ slotEnableLeaveOnServerCount( mPop.leaveOnServerCountCheck->isEnabled() ?
+ ap.leaveOnServerCount() >= 1 : 0);
+ slotEnableLeaveOnServerSize( mPop.leaveOnServerSizeCheck->isEnabled() ?
+ ap.leaveOnServerSize() >= 1 : 0);
+ slotEnablePopInterval( interval >= 1 );
+ folderCombo = mPop.folderCombo;
+ }
+ else if( accountType == "imap" )
+ {
+ KMAcctImap &ai = *(KMAcctImap*)mAccount;
+ mImap.nameEdit->setText( mAccount->name() );
+ mImap.nameEdit->setFocus();
+ mImap.loginEdit->setText( ai.login() );
+ mImap.passwordEdit->setText( ai.passwd());
+ mImap.hostEdit->setText( ai.host() );
+ mImap.portEdit->setText( QString("%1").arg( ai.port() ) );
+ mImap.autoExpungeCheck->setChecked( ai.autoExpunge() );
+ mImap.hiddenFoldersCheck->setChecked( ai.hiddenFolders() );
+ mImap.subscribedFoldersCheck->setChecked( ai.onlySubscribedFolders() );
+ mImap.locallySubscribedFoldersCheck->setChecked( ai.onlyLocallySubscribedFolders() );
+ mImap.loadOnDemandCheck->setChecked( ai.loadOnDemand() );
+ mImap.listOnlyOpenCheck->setChecked( ai.listOnlyOpenFolders() );
+ mImap.storePasswordCheck->setChecked( ai.storePasswd() );
+#if 0
+ mImap.resourceCheck->setChecked( ai.resource() );
+#endif
+ mImap.includeInCheck->setChecked( !ai.checkExclude() );
+ mImap.intervalCheck->setChecked( interval >= 1 );
+ if ( interval <= 0 ) mImap.intervalSpin->setValue( defaultmailcheckintervalmin );
+ else mImap.intervalSpin->setValue( interval );
+ QString trashfolder = ai.trash();
+ if (trashfolder.isEmpty())
+ trashfolder = kmkernel->trashFolder()->idString();
+ mImap.trashCombo->setFolder( trashfolder );
+ slotEnableImapInterval( interval >= 1 );
+ mImap.identityCombo-> setCurrentIdentity( mAccount->identityId() );
+ //mImap.identityCombo->insertStringList( kmkernel->identityManager()->shadowIdentities() );
+ if (ai.useSSL())
+ mImap.encryptionSSL->setChecked( true );
+ else if (ai.useTLS())
+ mImap.encryptionTLS->setChecked( true );
+ else mImap.encryptionNone->setChecked( true );
+ if (ai.auth() == "CRAM-MD5")
+ mImap.authCramMd5->setChecked( true );
+ else if (ai.auth() == "DIGEST-MD5")
+ mImap.authDigestMd5->setChecked( true );
+ else if (ai.auth() == "NTLM")
+ mImap.authNTLM->setChecked( true );
+ else if (ai.auth() == "GSSAPI")
+ mImap.authGSSAPI->setChecked( true );
+ else if (ai.auth() == "ANONYMOUS")
+ mImap.authAnonymous->setChecked( true );
+ else if (ai.auth() == "PLAIN")
+ mImap.authPlain->setChecked( true );
+ else if (ai.auth() == "LOGIN")
+ mImap.authLogin->setChecked( true );
+ else mImap.authUser->setChecked( true );
+ if ( mSieveConfigEditor )
+ mSieveConfigEditor->setConfig( ai.sieveConfig() );
+ }
+ else if( accountType == "cachedimap" )
+ {
+ KMAcctCachedImap &ai = *(KMAcctCachedImap*)mAccount;
+ mImap.nameEdit->setText( mAccount->name() );
+ mImap.nameEdit->setFocus();
+ mImap.loginEdit->setText( ai.login() );
+ mImap.passwordEdit->setText( ai.passwd());
+ mImap.hostEdit->setText( ai.host() );
+ mImap.portEdit->setText( QString("%1").arg( ai.port() ) );
+#if 0
+ mImap.resourceCheck->setChecked( ai.resource() );
+#endif
+ mImap.hiddenFoldersCheck->setChecked( ai.hiddenFolders() );
+ mImap.subscribedFoldersCheck->setChecked( ai.onlySubscribedFolders() );
+ mImap.locallySubscribedFoldersCheck->setChecked( ai.onlyLocallySubscribedFolders() );
+ mImap.storePasswordCheck->setChecked( ai.storePasswd() );
+ mImap.intervalCheck->setChecked( interval >= 1 );
+ if ( interval <= 0 ) mImap.intervalSpin->setValue( defaultmailcheckintervalmin );
+ else mImap.intervalSpin->setValue( interval );
+ mImap.includeInCheck->setChecked( !ai.checkExclude() );
+ QString trashfolder = ai.trash();
+ if (trashfolder.isEmpty())
+ trashfolder = kmkernel->trashFolder()->idString();
+ mImap.trashCombo->setFolder( trashfolder );
+ slotEnableImapInterval( interval >= 1 );
+ mImap.identityCombo-> setCurrentIdentity( mAccount->identityId() );
+ //mImap.identityCombo->insertStringList( kmkernel->identityManager()->shadowIdentities() );
+ if (ai.useSSL())
+ mImap.encryptionSSL->setChecked( true );
+ else if (ai.useTLS())
+ mImap.encryptionTLS->setChecked( true );
+ else mImap.encryptionNone->setChecked( true );
+ if (ai.auth() == "CRAM-MD5")
+ mImap.authCramMd5->setChecked( true );
+ else if (ai.auth() == "DIGEST-MD5")
+ mImap.authDigestMd5->setChecked( true );
+ else if (ai.auth() == "GSSAPI")
+ mImap.authGSSAPI->setChecked( true );
+ else if (ai.auth() == "NTLM")
+ mImap.authNTLM->setChecked( true );
+ else if (ai.auth() == "ANONYMOUS")
+ mImap.authAnonymous->setChecked( true );
+ else if (ai.auth() == "PLAIN")
+ mImap.authPlain->setChecked( true );
+ else if (ai.auth() == "LOGIN")
+ mImap.authLogin->setChecked( true );
+ else mImap.authUser->setChecked( true );
+ if ( mSieveConfigEditor )
+ mSieveConfigEditor->setConfig( ai.sieveConfig() );
+ }
+ else if( accountType == "maildir" )
+ {
+ KMAcctMaildir *acctMaildir = dynamic_cast<KMAcctMaildir*>(mAccount);
+
+ mMaildir.nameEdit->setText( mAccount->name() );
+ mMaildir.nameEdit->setFocus();
+ mMaildir.locationEdit->setEditText( acctMaildir->location() );
+
+ if ( interval <= 0 ) mMaildir.intervalSpin->setValue( defaultmailcheckintervalmin );
+ else mMaildir.intervalSpin->setValue( interval );
+ mMaildir.intervalCheck->setChecked( interval >= 1 );
+#if 0
+ mMaildir.resourceCheck->setChecked( mAccount->resource() );
+#endif
+ mMaildir.includeInCheck->setChecked( !mAccount->checkExclude() );
+ mMaildir.precommand->setText( mAccount->precommand() );
+ mMaildir.identityCombo-> setCurrentIdentity( mAccount->identityId() );
+ slotEnableMaildirInterval( interval >= 1 );
+ folderCombo = mMaildir.folderCombo;
+ }
+ else // Unknown account type
+ return;
+
+ if ( accountType == "imap" || accountType == "cachedimap" )
+ {
+ // settings for imap in general
+ ImapAccountBase &ai = *(ImapAccountBase*)mAccount;
+ // namespaces
+ if ( ( ai.namespaces().isEmpty() || ai.namespaceToDelimiter().isEmpty() ) &&
+ !ai.login().isEmpty() && !ai.passwd().isEmpty() && !ai.host().isEmpty() )
+ {
+ slotReloadNamespaces();
+ } else {
+ slotSetupNamespaces( ai.namespacesWithDelimiter() );
+ }
+ }
+
+ if (!folderCombo) return;
+
+ KMFolderDir *fdir = (KMFolderDir*)&kmkernel->folderMgr()->dir();
+ KMFolder *acctFolder = mAccount->folder();
+ if( acctFolder == 0 )
+ {
+ acctFolder = (KMFolder*)fdir->first();
+ }
+ if( acctFolder == 0 )
+ {
+ folderCombo->insertItem( i18n("<none>") );
+ }
+ else
+ {
+ uint i = 0;
+ int curIndex = -1;
+ kmkernel->folderMgr()->createI18nFolderList(&mFolderNames, &mFolderList);
+ while (i < mFolderNames.count())
+ {
+ QValueList<QGuardedPtr<KMFolder> >::Iterator it = mFolderList.at(i);
+ KMFolder *folder = *it;
+ if (folder->isSystemFolder())
+ {
+ mFolderList.remove(it);
+ mFolderNames.remove(mFolderNames.at(i));
+ } else {
+ if (folder == acctFolder) curIndex = i;
+ i++;
+ }
+ }
+ mFolderNames.prepend(i18n("inbox"));
+ mFolderList.prepend(kmkernel->inboxFolder());
+ folderCombo->insertStringList(mFolderNames);
+ folderCombo->setCurrentItem(curIndex + 1);
+
+ // -sanders hack for startup users. Must investigate this properly
+ if (folderCombo->count() == 0)
+ folderCombo->insertItem( i18n("inbox") );
+ }
+}
+
+void AccountDialog::slotLeaveOnServerClicked()
+{
+ bool state = mPop.leaveOnServerCheck->isChecked();
+ mPop.leaveOnServerDaysCheck->setEnabled( state );
+ mPop.leaveOnServerCountCheck->setEnabled( state );
+ mPop.leaveOnServerSizeCheck->setEnabled( state );
+ if ( state ) {
+ if ( mPop.leaveOnServerDaysCheck->isChecked() ) {
+ slotEnableLeaveOnServerDays( state );
+ }
+ if ( mPop.leaveOnServerCountCheck->isChecked() ) {
+ slotEnableLeaveOnServerCount( state );
+ }
+ if ( mPop.leaveOnServerSizeCheck->isChecked() ) {
+ slotEnableLeaveOnServerSize( state );
+ }
+ } else {
+ slotEnableLeaveOnServerDays( state );
+ slotEnableLeaveOnServerCount( state );
+ slotEnableLeaveOnServerSize( state );
+ }
+ if ( !( mCurCapa & UIDL ) && mPop.leaveOnServerCheck->isChecked() ) {
+ KMessageBox::information( topLevelWidget(),
+ i18n("The server does not seem to support unique "
+ "message numbers, but this is a "
+ "requirement for leaving messages on the "
+ "server.\n"
+ "Since some servers do not correctly "
+ "announce their capabilities you still "
+ "have the possibility to turn leaving "
+ "fetched messages on the server on.") );
+ }
+}
+
+void AccountDialog::slotFilterOnServerClicked()
+{
+ if ( !( mCurCapa & TOP ) && mPop.filterOnServerCheck->isChecked() ) {
+ KMessageBox::information( topLevelWidget(),
+ i18n("The server does not seem to support "
+ "fetching message headers, but this is a "
+ "requirement for filtering messages on the "
+ "server.\n"
+ "Since some servers do not correctly "
+ "announce their capabilities you still "
+ "have the possibility to turn filtering "
+ "messages on the server on.") );
+ }
+}
+
+void AccountDialog::slotPipeliningClicked()
+{
+ if (mPop.usePipeliningCheck->isChecked())
+ KMessageBox::information( topLevelWidget(),
+ i18n("Please note that this feature can cause some POP3 servers "
+ "that do not support pipelining to send corrupted mail;\n"
+ "this is configurable, though, because some servers support pipelining "
+ "but do not announce their capabilities. To check whether your POP3 server "
+ "announces pipelining support use the \"Check What the Server "
+ "Supports\" button at the bottom of the dialog;\n"
+ "if your server does not announce it, but you want more speed, then "
+ "you should do some testing first by sending yourself a batch "
+ "of mail and downloading it."), QString::null,
+ "pipelining");
+}
+
+
+void AccountDialog::slotPopEncryptionChanged(int id)
+{
+ kdDebug(5006) << "slotPopEncryptionChanged( " << id << " )" << endl;
+ // adjust port
+ if ( id == SSL || mPop.portEdit->text() == "995" )
+ mPop.portEdit->setText( ( id == SSL ) ? "995" : "110" );
+
+ // switch supported auth methods
+ mCurCapa = ( id == TLS ) ? mCapaTLS
+ : ( id == SSL ) ? mCapaSSL
+ : mCapaNormal;
+ enablePopFeatures( mCurCapa );
+ const QButton *old = mPop.authGroup->selected();
+ if ( !old->isEnabled() )
+ checkHighest( mPop.authGroup );
+}
+
+
+void AccountDialog::slotImapEncryptionChanged(int id)
+{
+ kdDebug(5006) << "slotImapEncryptionChanged( " << id << " )" << endl;
+ // adjust port
+ if ( id == SSL || mImap.portEdit->text() == "993" )
+ mImap.portEdit->setText( ( id == SSL ) ? "993" : "143" );
+
+ // switch supported auth methods
+ int authMethods = ( id == TLS ) ? mCapaTLS
+ : ( id == SSL ) ? mCapaSSL
+ : mCapaNormal;
+ enableImapAuthMethods( authMethods );
+ QButton *old = mImap.authGroup->selected();
+ if ( !old->isEnabled() )
+ checkHighest( mImap.authGroup );
+}
+
+
+void AccountDialog::slotCheckPopCapabilities()
+{
+ if ( mPop.hostEdit->text().isEmpty() || mPop.portEdit->text().isEmpty() )
+ {
+ KMessageBox::sorry( this, i18n( "Please specify a server and port on "
+ "the General tab first." ) );
+ return;
+ }
+ delete mServerTest;
+ mServerTest = new KMServerTest(POP_PROTOCOL, mPop.hostEdit->text(),
+ mPop.portEdit->text().toInt());
+ connect( mServerTest, SIGNAL( capabilities( const QStringList &,
+ const QStringList & ) ),
+ this, SLOT( slotPopCapabilities( const QStringList &,
+ const QStringList & ) ) );
+ mPop.checkCapabilities->setEnabled(false);
+}
+
+
+void AccountDialog::slotCheckImapCapabilities()
+{
+ if ( mImap.hostEdit->text().isEmpty() || mImap.portEdit->text().isEmpty() )
+ {
+ KMessageBox::sorry( this, i18n( "Please specify a server and port on "
+ "the General tab first." ) );
+ return;
+ }
+ delete mServerTest;
+ mServerTest = new KMServerTest(IMAP_PROTOCOL, mImap.hostEdit->text(),
+ mImap.portEdit->text().toInt());
+ connect( mServerTest, SIGNAL( capabilities( const QStringList &,
+ const QStringList & ) ),
+ this, SLOT( slotImapCapabilities( const QStringList &,
+ const QStringList & ) ) );
+ mImap.checkCapabilities->setEnabled(false);
+}
+
+
+unsigned int AccountDialog::popCapabilitiesFromStringList( const QStringList & l )
+{
+ unsigned int capa = 0;
+ kdDebug( 5006 ) << k_funcinfo << l << endl;
+ for ( QStringList::const_iterator it = l.begin() ; it != l.end() ; ++it ) {
+ QString cur = (*it).upper();
+ if ( cur == "PLAIN" )
+ capa |= Plain;
+ else if ( cur == "LOGIN" )
+ capa |= Login;
+ else if ( cur == "CRAM-MD5" )
+ capa |= CRAM_MD5;
+ else if ( cur == "DIGEST-MD5" )
+ capa |= Digest_MD5;
+ else if ( cur == "NTLM" )
+ capa |= NTLM;
+ else if ( cur == "GSSAPI" )
+ capa |= GSSAPI;
+ else if ( cur == "APOP" )
+ capa |= APOP;
+ else if ( cur == "PIPELINING" )
+ capa |= Pipelining;
+ else if ( cur == "TOP" )
+ capa |= TOP;
+ else if ( cur == "UIDL" )
+ capa |= UIDL;
+ else if ( cur == "STLS" )
+ capa |= STLS;
+ }
+ return capa;
+}
+
+
+void AccountDialog::slotPopCapabilities( const QStringList & capaNormal,
+ const QStringList & capaSSL )
+{
+ mPop.checkCapabilities->setEnabled( true );
+ mCapaNormal = popCapabilitiesFromStringList( capaNormal );
+ if ( mCapaNormal & STLS )
+ mCapaTLS = mCapaNormal;
+ else
+ mCapaTLS = 0;
+ mCapaSSL = popCapabilitiesFromStringList( capaSSL );
+ kdDebug(5006) << "mCapaNormal = " << mCapaNormal
+ << "; mCapaSSL = " << mCapaSSL
+ << "; mCapaTLS = " << mCapaTLS << endl;
+ mPop.encryptionNone->setEnabled( !capaNormal.isEmpty() );
+ mPop.encryptionSSL->setEnabled( !capaSSL.isEmpty() );
+ mPop.encryptionTLS->setEnabled( mCapaTLS != 0 );
+ checkHighest( mPop.encryptionGroup );
+ delete mServerTest;
+ mServerTest = 0;
+}
+
+
+void AccountDialog::enablePopFeatures( unsigned int capa )
+{
+ kdDebug(5006) << "enablePopFeatures( " << capa << " )" << endl;
+ mPop.authPlain->setEnabled( capa & Plain );
+ mPop.authLogin->setEnabled( capa & Login );
+ mPop.authCRAM_MD5->setEnabled( capa & CRAM_MD5 );
+ mPop.authDigestMd5->setEnabled( capa & Digest_MD5 );
+ mPop.authNTLM->setEnabled( capa & NTLM );
+ mPop.authGSSAPI->setEnabled( capa & GSSAPI );
+ mPop.authAPOP->setEnabled( capa & APOP );
+ if ( !( capa & Pipelining ) && mPop.usePipeliningCheck->isChecked() ) {
+ mPop.usePipeliningCheck->setChecked( false );
+ KMessageBox::information( topLevelWidget(),
+ i18n("The server does not seem to support "
+ "pipelining; therefore, this option has "
+ "been disabled.\n"
+ "Since some servers do not correctly "
+ "announce their capabilities you still "
+ "have the possibility to turn pipelining "
+ "on. But please note that this feature can "
+ "cause some POP servers that do not "
+ "support pipelining to send corrupt "
+ "messages. So before using this feature "
+ "with important mail you should first "
+ "test it by sending yourself a larger "
+ "number of test messages which you all "
+ "download in one go from the POP "
+ "server.") );
+ }
+ if ( !( capa & UIDL ) && mPop.leaveOnServerCheck->isChecked() ) {
+ mPop.leaveOnServerCheck->setChecked( false );
+ KMessageBox::information( topLevelWidget(),
+ i18n("The server does not seem to support unique "
+ "message numbers, but this is a "
+ "requirement for leaving messages on the "
+ "server; therefore, this option has been "
+ "disabled.\n"
+ "Since some servers do not correctly "
+ "announce their capabilities you still "
+ "have the possibility to turn leaving "
+ "fetched messages on the server on.") );
+ }
+ if ( !( capa & TOP ) && mPop.filterOnServerCheck->isChecked() ) {
+ mPop.filterOnServerCheck->setChecked( false );
+ KMessageBox::information( topLevelWidget(),
+ i18n("The server does not seem to support "
+ "fetching message headers, but this is a "
+ "requirement for filtering messages on the "
+ "server; therefore, this option has been "
+ "disabled.\n"
+ "Since some servers do not correctly "
+ "announce their capabilities you still "
+ "have the possibility to turn filtering "
+ "messages on the server on.") );
+ }
+}
+
+
+unsigned int AccountDialog::imapCapabilitiesFromStringList( const QStringList & l )
+{
+ unsigned int capa = 0;
+ for ( QStringList::const_iterator it = l.begin() ; it != l.end() ; ++it ) {
+ QString cur = (*it).upper();
+ if ( cur == "AUTH=PLAIN" )
+ capa |= Plain;
+ else if ( cur == "AUTH=LOGIN" )
+ capa |= Login;
+ else if ( cur == "AUTH=CRAM-MD5" )
+ capa |= CRAM_MD5;
+ else if ( cur == "AUTH=DIGEST-MD5" )
+ capa |= Digest_MD5;
+ else if ( cur == "AUTH=NTLM" )
+ capa |= NTLM;
+ else if ( cur == "AUTH=GSSAPI" )
+ capa |= GSSAPI;
+ else if ( cur == "AUTH=ANONYMOUS" )
+ capa |= Anonymous;
+ else if ( cur == "STARTTLS" )
+ capa |= STARTTLS;
+ }
+ return capa;
+}
+
+
+void AccountDialog::slotImapCapabilities( const QStringList & capaNormal,
+ const QStringList & capaSSL )
+{
+ mImap.checkCapabilities->setEnabled( true );
+ mCapaNormal = imapCapabilitiesFromStringList( capaNormal );
+ if ( mCapaNormal & STARTTLS )
+ mCapaTLS = mCapaNormal;
+ else
+ mCapaTLS = 0;
+ mCapaSSL = imapCapabilitiesFromStringList( capaSSL );
+ kdDebug(5006) << "mCapaNormal = " << mCapaNormal
+ << "; mCapaSSL = " << mCapaSSL
+ << "; mCapaTLS = " << mCapaTLS << endl;
+ mImap.encryptionNone->setEnabled( !capaNormal.isEmpty() );
+ mImap.encryptionSSL->setEnabled( !capaSSL.isEmpty() );
+ mImap.encryptionTLS->setEnabled( mCapaTLS != 0 );
+ checkHighest( mImap.encryptionGroup );
+ delete mServerTest;
+ mServerTest = 0;
+}
+
+void AccountDialog::slotLeaveOnServerDaysChanged ( int value )
+{
+ mPop.leaveOnServerDaysSpin->setSuffix( i18n(" day", " days", value) );
+}
+
+
+void AccountDialog::slotLeaveOnServerCountChanged ( int value )
+{
+ mPop.leaveOnServerCountSpin->setSuffix( i18n(" message", " messages", value) );
+}
+
+
+void AccountDialog::slotFilterOnServerSizeChanged ( int value )
+{
+ mPop.filterOnServerSizeSpin->setSuffix( i18n(" byte", " bytes", value) );
+}
+
+
+void AccountDialog::enableImapAuthMethods( unsigned int capa )
+{
+ kdDebug(5006) << "enableImapAuthMethods( " << capa << " )" << endl;
+ mImap.authPlain->setEnabled( capa & Plain );
+ mImap.authLogin->setEnabled( capa & Login );
+ mImap.authCramMd5->setEnabled( capa & CRAM_MD5 );
+ mImap.authDigestMd5->setEnabled( capa & Digest_MD5 );
+ mImap.authNTLM->setEnabled( capa & NTLM );
+ mImap.authGSSAPI->setEnabled( capa & GSSAPI );
+ mImap.authAnonymous->setEnabled( capa & Anonymous );
+}
+
+
+void AccountDialog::checkHighest( QButtonGroup *btnGroup )
+{
+ kdDebug(5006) << "checkHighest( " << btnGroup << " )" << endl;
+ for ( int i = btnGroup->count() - 1; i >= 0 ; --i ) {
+ QButton * btn = btnGroup->find( i );
+ if ( btn && btn->isEnabled() ) {
+ btn->animateClick();
+ return;
+ }
+ }
+}
+
+
+void AccountDialog::slotOk()
+{
+ saveSettings();
+ accept();
+}
+
+
+void AccountDialog::saveSettings()
+{
+ QString accountType = mAccount->type();
+ if( accountType == "local" )
+ {
+ KMAcctLocal *acctLocal = dynamic_cast<KMAcctLocal*>(mAccount);
+
+ if (acctLocal) {
+ mAccount->setName( mLocal.nameEdit->text() );
+ acctLocal->setLocation( mLocal.locationEdit->currentText() );
+ if (mLocal.lockMutt->isChecked())
+ acctLocal->setLockType(mutt_dotlock);
+ else if (mLocal.lockMuttPriv->isChecked())
+ acctLocal->setLockType(mutt_dotlock_privileged);
+ else if (mLocal.lockProcmail->isChecked()) {
+ acctLocal->setLockType(procmail_lockfile);
+ acctLocal->setProcmailLockFileName(mLocal.procmailLockFileName->currentText());
+ }
+ else if (mLocal.lockNone->isChecked())
+ acctLocal->setLockType(lock_none);
+ else acctLocal->setLockType(FCNTL);
+ }
+
+ mAccount->setCheckInterval( mLocal.intervalCheck->isChecked() ?
+ mLocal.intervalSpin->value() : 0 );
+#if 0
+ mAccount->setResource( mLocal.resourceCheck->isChecked() );
+#endif
+ mAccount->setCheckExclude( !mLocal.includeInCheck->isChecked() );
+
+ mAccount->setPrecommand( mLocal.precommand->text() );
+
+ mAccount->setFolder( *mFolderList.at(mLocal.folderCombo->currentItem()) );
+
+ mAccount->setIdentityId( mLocal.identityCombo->currentIdentity() );
+
+ }
+ else if( accountType == "pop" )
+ {
+ mAccount->setName( mPop.nameEdit->text() );
+ mAccount->setCheckInterval( mPop.intervalCheck->isChecked() ?
+ mPop.intervalSpin->value() : 0 );
+#if 0
+ mAccount->setResource( mPop.resourceCheck->isChecked() );
+#endif
+ mAccount->setCheckExclude( !mPop.includeInCheck->isChecked() );
+
+ mAccount->setFolder( *mFolderList.at(mPop.folderCombo->currentItem()) );
+
+ mAccount->setIdentityId( mPop.identityCombo->currentIdentity() );
+
+ initAccountForConnect();
+ PopAccount &epa = *(PopAccount*)mAccount;
+ epa.setUsePipelining( mPop.usePipeliningCheck->isChecked() );
+ epa.setLeaveOnServer( mPop.leaveOnServerCheck->isChecked() );
+ epa.setLeaveOnServerDays( mPop.leaveOnServerCheck->isChecked() ?
+ ( mPop.leaveOnServerDaysCheck->isChecked() ?
+ mPop.leaveOnServerDaysSpin->value() : -1 ) : 0);
+ epa.setLeaveOnServerCount( mPop.leaveOnServerCheck->isChecked() ?
+ ( mPop.leaveOnServerCountCheck->isChecked() ?
+ mPop.leaveOnServerCountSpin->value() : -1 ) : 0 );
+ epa.setLeaveOnServerSize( mPop.leaveOnServerCheck->isChecked() ?
+ ( mPop.leaveOnServerSizeCheck->isChecked() ?
+ mPop.leaveOnServerSizeSpin->value() : -1 ) : 0 );
+ epa.setFilterOnServer( mPop.filterOnServerCheck->isChecked() );
+ epa.setFilterOnServerCheckSize (mPop.filterOnServerSizeSpin->value() );
+ epa.setPrecommand( mPop.precommand->text() );
+
+ }
+ else if( accountType == "imap" )
+ {
+ mAccount->setName( mImap.nameEdit->text() );
+ mAccount->setCheckInterval( mImap.intervalCheck->isChecked() ?
+ mImap.intervalSpin->value() : 0 );
+ mAccount->setIdentityId( mImap.identityCombo->currentIdentity() );
+
+#if 0
+ mAccount->setResource( mImap.resourceCheck->isChecked() );
+#endif
+ mAccount->setCheckExclude( !mImap.includeInCheck->isChecked() );
+ mAccount->setFolder( kmkernel->imapFolderMgr()->findById(mAccount->id()) );
+
+ initAccountForConnect();
+ KMAcctImap &epa = *(KMAcctImap*)mAccount;
+ epa.setAutoExpunge( mImap.autoExpungeCheck->isChecked() );
+ epa.setHiddenFolders( mImap.hiddenFoldersCheck->isChecked() );
+ epa.setOnlySubscribedFolders( mImap.subscribedFoldersCheck->isChecked() );
+ epa.setOnlyLocallySubscribedFolders( mImap.locallySubscribedFoldersCheck->isChecked() );
+ epa.setLoadOnDemand( mImap.loadOnDemandCheck->isChecked() );
+ epa.setListOnlyOpenFolders( mImap.listOnlyOpenCheck->isChecked() );
+ KMFolder *t = mImap.trashCombo->folder();
+ if ( t )
+ epa.setTrash( mImap.trashCombo->folder()->idString() );
+ else
+ epa.setTrash( kmkernel->trashFolder()->idString() );
+#if 0
+ epa.setResource( mImap.resourceCheck->isChecked() );
+#endif
+ epa.setCheckExclude( !mImap.includeInCheck->isChecked() );
+ if ( mSieveConfigEditor )
+ epa.setSieveConfig( mSieveConfigEditor->config() );
+ }
+ else if( accountType == "cachedimap" )
+ {
+ mAccount->setName( mImap.nameEdit->text() );
+ mAccount->setCheckInterval( mImap.intervalCheck->isChecked() ?
+ mImap.intervalSpin->value() : 0 );
+ mAccount->setIdentityId( mImap.identityCombo->currentIdentity() );
+
+#if 0
+ mAccount->setResource( mImap.resourceCheck->isChecked() );
+#endif
+ mAccount->setCheckExclude( !mImap.includeInCheck->isChecked() );
+ //mAccount->setFolder( NULL );
+ mAccount->setFolder( kmkernel->dimapFolderMgr()->findById(mAccount->id()) );
+ //kdDebug(5006) << "account for folder " << mAccount->folder()->name() << endl;
+
+ initAccountForConnect();
+ KMAcctCachedImap &epa = *(KMAcctCachedImap*)mAccount;
+ epa.setHiddenFolders( mImap.hiddenFoldersCheck->isChecked() );
+ epa.setOnlySubscribedFolders( mImap.subscribedFoldersCheck->isChecked() );
+ epa.setOnlyLocallySubscribedFolders( mImap.locallySubscribedFoldersCheck->isChecked() );
+ epa.setStorePasswd( mImap.storePasswordCheck->isChecked() );
+ epa.setPasswd( mImap.passwordEdit->text(), epa.storePasswd() );
+ KMFolder *t = mImap.trashCombo->folder();
+ if ( t )
+ epa.setTrash( mImap.trashCombo->folder()->idString() );
+ else
+ epa.setTrash( kmkernel->trashFolder()->idString() );
+#if 0
+ epa.setResource( mImap.resourceCheck->isChecked() );
+#endif
+ epa.setCheckExclude( !mImap.includeInCheck->isChecked() );
+ if ( mSieveConfigEditor )
+ epa.setSieveConfig( mSieveConfigEditor->config() );
+ }
+ else if( accountType == "maildir" )
+ {
+ KMAcctMaildir *acctMaildir = dynamic_cast<KMAcctMaildir*>(mAccount);
+
+ if (acctMaildir) {
+ mAccount->setName( mMaildir.nameEdit->text() );
+ acctMaildir->setLocation( mMaildir.locationEdit->currentText() );
+
+ KMFolder *targetFolder = *mFolderList.at(mMaildir.folderCombo->currentItem());
+ if ( targetFolder->location() == acctMaildir->location() ) {
+ /*
+ Prevent data loss if the user sets the destination folder to be the same as the
+ source account maildir folder by setting the target folder to the inbox.
+ ### FIXME post 3.2: show dialog and let the user chose another target folder
+ */
+ targetFolder = kmkernel->inboxFolder();
+ }
+ mAccount->setFolder( targetFolder );
+ }
+ mAccount->setCheckInterval( mMaildir.intervalCheck->isChecked() ?
+ mMaildir.intervalSpin->value() : 0 );
+#if 0
+ mAccount->setResource( mMaildir.resourceCheck->isChecked() );
+#endif
+ mAccount->setCheckExclude( !mMaildir.includeInCheck->isChecked() );
+
+ mAccount->setPrecommand( mMaildir.precommand->text() );
+
+ mAccount->setIdentityId( mMaildir.identityCombo->currentIdentity() );
+ }
+
+ if ( accountType == "imap" || accountType == "cachedimap" )
+ {
+ // settings for imap in general
+ ImapAccountBase &ai = *(ImapAccountBase*)mAccount;
+ // namespace
+ ImapAccountBase::nsMap map;
+ ImapAccountBase::namespaceDelim delimMap;
+ ImapAccountBase::nsDelimMap::Iterator it;
+ ImapAccountBase::namespaceDelim::Iterator it2;
+ for ( it = mImap.nsMap.begin(); it != mImap.nsMap.end(); ++it ) {
+ QStringList list;
+ for ( it2 = it.data().begin(); it2 != it.data().end(); ++it2 ) {
+ list << it2.key();
+ delimMap[it2.key()] = it2.data();
+ }
+ map[it.key()] = list;
+ }
+ ai.setNamespaces( map );
+ ai.setNamespaceToDelimiter( delimMap );
+ }
+
+ kmkernel->acctMgr()->writeConfig( true );
+ // get the new account and register the new destination folder
+ // this is the target folder for local or pop accounts and the root folder
+ // of the account for (d)imap
+ KMAccount* newAcct = kmkernel->acctMgr()->find(mAccount->id());
+ if (newAcct)
+ {
+ if( accountType == "local" ) {
+ newAcct->setFolder( *mFolderList.at(mLocal.folderCombo->currentItem()), true );
+ } else if ( accountType == "pop" ) {
+ newAcct->setFolder( *mFolderList.at(mPop.folderCombo->currentItem()), true );
+ } else if ( accountType == "maildir" ) {
+ newAcct->setFolder( *mFolderList.at(mMaildir.folderCombo->currentItem()), true );
+ } else if ( accountType == "imap" ) {
+ newAcct->setFolder( kmkernel->imapFolderMgr()->findById(mAccount->id()), true );
+ } else if ( accountType == "cachedimap" ) {
+ newAcct->setFolder( kmkernel->dimapFolderMgr()->findById(mAccount->id()), true );
+ }
+ }
+}
+
+
+void AccountDialog::slotLocationChooser()
+{
+ static QString directory( "/" );
+
+ KFileDialog dialog( directory, QString::null, this, 0, true );
+ dialog.setCaption( i18n("Choose Location") );
+
+ bool result = dialog.exec();
+ if( result == false )
+ {
+ return;
+ }
+
+ KURL url = dialog.selectedURL();
+ if( url.isEmpty() )
+ {
+ return;
+ }
+ if( url.isLocalFile() == false )
+ {
+ KMessageBox::sorry( 0, i18n( "Only local files are currently supported." ) );
+ return;
+ }
+
+ mLocal.locationEdit->setEditText( url.path() );
+ directory = url.directory();
+}
+
+void AccountDialog::slotMaildirChooser()
+{
+ static QString directory( "/" );
+
+ QString dir = KFileDialog::getExistingDirectory(directory, this, i18n("Choose Location"));
+
+ if( dir.isEmpty() )
+ return;
+
+ mMaildir.locationEdit->setEditText( dir );
+ directory = dir;
+}
+
+void AccountDialog::slotEnableLeaveOnServerDays( bool state )
+{
+ if ( state && !mPop.leaveOnServerDaysCheck->isEnabled()) return;
+ mPop.leaveOnServerDaysSpin->setEnabled( state );
+}
+
+void AccountDialog::slotEnableLeaveOnServerCount( bool state )
+{
+ if ( state && !mPop.leaveOnServerCountCheck->isEnabled()) return;
+ mPop.leaveOnServerCountSpin->setEnabled( state );
+ return;
+}
+
+void AccountDialog::slotEnableLeaveOnServerSize( bool state )
+{
+ if ( state && !mPop.leaveOnServerSizeCheck->isEnabled()) return;
+ mPop.leaveOnServerSizeSpin->setEnabled( state );
+ return;
+}
+
+void AccountDialog::slotEnablePopInterval( bool state )
+{
+ mPop.intervalSpin->setEnabled( state );
+ mPop.intervalLabel->setEnabled( state );
+}
+
+void AccountDialog::slotEnableImapInterval( bool state )
+{
+ mImap.intervalSpin->setEnabled( state );
+ mImap.intervalLabel->setEnabled( state );
+}
+
+void AccountDialog::slotEnableLocalInterval( bool state )
+{
+ mLocal.intervalSpin->setEnabled( state );
+ mLocal.intervalLabel->setEnabled( state );
+}
+
+void AccountDialog::slotEnableMaildirInterval( bool state )
+{
+ mMaildir.intervalSpin->setEnabled( state );
+ mMaildir.intervalLabel->setEnabled( state );
+}
+
+void AccountDialog::slotFontChanged( void )
+{
+ QString accountType = mAccount->type();
+ if( accountType == "local" )
+ {
+ QFont titleFont( mLocal.titleLabel->font() );
+ titleFont.setBold( true );
+ mLocal.titleLabel->setFont(titleFont);
+ }
+ else if( accountType == "pop" )
+ {
+ QFont titleFont( mPop.titleLabel->font() );
+ titleFont.setBold( true );
+ mPop.titleLabel->setFont(titleFont);
+ }
+ else if( accountType == "imap" )
+ {
+ QFont titleFont( mImap.titleLabel->font() );
+ titleFont.setBold( true );
+ mImap.titleLabel->setFont(titleFont);
+ }
+}
+
+#if 0
+void AccountDialog::slotClearResourceAllocations()
+{
+ mAccount->clearIntervals();
+}
+
+
+void AccountDialog::slotClearPastResourceAllocations()
+{
+ mAccount->clearOldIntervals();
+}
+#endif
+
+void AccountDialog::slotReloadNamespaces()
+{
+ if ( mAccount->type() == "imap" || mAccount->type() == "cachedimap" )
+ {
+ initAccountForConnect();
+ mImap.personalNS->setText( i18n("Fetching Namespaces...") );
+ mImap.otherUsersNS->setText( QString::null );
+ mImap.sharedNS->setText( QString::null );
+ ImapAccountBase* ai = static_cast<ImapAccountBase*>( mAccount );
+ connect( ai, SIGNAL( namespacesFetched( const ImapAccountBase::nsDelimMap& ) ),
+ this, SLOT( slotSetupNamespaces( const ImapAccountBase::nsDelimMap& ) ) );
+ connect( ai, SIGNAL( connectionResult(int, const QString&) ),
+ this, SLOT( slotConnectionResult(int, const QString&) ) );
+ ai->getNamespaces();
+ }
+}
+
+void AccountDialog::slotConnectionResult( int errorCode, const QString& )
+{
+ if ( errorCode > 0 ) {
+ ImapAccountBase* ai = static_cast<ImapAccountBase*>( mAccount );
+ disconnect( ai, SIGNAL( namespacesFetched( const ImapAccountBase::nsDelimMap& ) ),
+ this, SLOT( slotSetupNamespaces( const ImapAccountBase::nsDelimMap& ) ) );
+ disconnect( ai, SIGNAL( connectionResult(int, const QString&) ),
+ this, SLOT( slotConnectionResult(int, const QString&) ) );
+ mImap.personalNS->setText( QString::null );
+ }
+}
+
+void AccountDialog::slotSetupNamespaces( const ImapAccountBase::nsDelimMap& map )
+{
+ disconnect( this, SLOT( slotSetupNamespaces( const ImapAccountBase::nsDelimMap& ) ) );
+ mImap.personalNS->setText( QString::null );
+ mImap.otherUsersNS->setText( QString::null );
+ mImap.sharedNS->setText( QString::null );
+ mImap.nsMap = map;
+
+ ImapAccountBase::namespaceDelim ns = map[ImapAccountBase::PersonalNS];
+ ImapAccountBase::namespaceDelim::ConstIterator it;
+ if ( !ns.isEmpty() ) {
+ mImap.personalNS->setText( namespaceListToString( ns.keys() ) );
+ mImap.editPNS->setEnabled( true );
+ } else {
+ mImap.editPNS->setEnabled( false );
+ }
+ ns = map[ImapAccountBase::OtherUsersNS];
+ if ( !ns.isEmpty() ) {
+ mImap.otherUsersNS->setText( namespaceListToString( ns.keys() ) );
+ mImap.editONS->setEnabled( true );
+ } else {
+ mImap.editONS->setEnabled( false );
+ }
+ ns = map[ImapAccountBase::SharedNS];
+ if ( !ns.isEmpty() ) {
+ mImap.sharedNS->setText( namespaceListToString( ns.keys() ) );
+ mImap.editSNS->setEnabled( true );
+ } else {
+ mImap.editSNS->setEnabled( false );
+ }
+}
+
+const QString AccountDialog::namespaceListToString( const QStringList& list )
+{
+ QStringList myList = list;
+ for ( QStringList::Iterator it = myList.begin(); it != myList.end(); ++it ) {
+ if ( (*it).isEmpty() ) {
+ (*it) = "<" + i18n("Empty") + ">";
+ }
+ }
+ return myList.join(",");
+}
+
+void AccountDialog::initAccountForConnect()
+{
+ QString type = mAccount->type();
+ if ( type == "local" )
+ return;
+
+ NetworkAccount &na = *(NetworkAccount*)mAccount;
+
+ if ( type == "pop" ) {
+ na.setHost( mPop.hostEdit->text().stripWhiteSpace() );
+ na.setPort( mPop.portEdit->text().toInt() );
+ na.setLogin( mPop.loginEdit->text().stripWhiteSpace() );
+ na.setStorePasswd( mPop.storePasswordCheck->isChecked() );
+ na.setPasswd( mPop.passwordEdit->text(), na.storePasswd() );
+ na.setUseSSL( mPop.encryptionSSL->isChecked() );
+ na.setUseTLS( mPop.encryptionTLS->isChecked() );
+ if (mPop.authUser->isChecked())
+ na.setAuth("USER");
+ else if (mPop.authLogin->isChecked())
+ na.setAuth("LOGIN");
+ else if (mPop.authPlain->isChecked())
+ na.setAuth("PLAIN");
+ else if (mPop.authCRAM_MD5->isChecked())
+ na.setAuth("CRAM-MD5");
+ else if (mPop.authDigestMd5->isChecked())
+ na.setAuth("DIGEST-MD5");
+ else if (mPop.authNTLM->isChecked())
+ na.setAuth("NTLM");
+ else if (mPop.authGSSAPI->isChecked())
+ na.setAuth("GSSAPI");
+ else if (mPop.authAPOP->isChecked())
+ na.setAuth("APOP");
+ else na.setAuth("AUTO");
+ }
+ else if ( type == "imap" || type == "cachedimap" ) {
+ na.setHost( mImap.hostEdit->text().stripWhiteSpace() );
+ na.setPort( mImap.portEdit->text().toInt() );
+ na.setLogin( mImap.loginEdit->text().stripWhiteSpace() );
+ na.setStorePasswd( mImap.storePasswordCheck->isChecked() );
+ na.setPasswd( mImap.passwordEdit->text(), na.storePasswd() );
+ na.setUseSSL( mImap.encryptionSSL->isChecked() );
+ na.setUseTLS( mImap.encryptionTLS->isChecked() );
+ if (mImap.authCramMd5->isChecked())
+ na.setAuth("CRAM-MD5");
+ else if (mImap.authDigestMd5->isChecked())
+ na.setAuth("DIGEST-MD5");
+ else if (mImap.authNTLM->isChecked())
+ na.setAuth("NTLM");
+ else if (mImap.authGSSAPI->isChecked())
+ na.setAuth("GSSAPI");
+ else if (mImap.authAnonymous->isChecked())
+ na.setAuth("ANONYMOUS");
+ else if (mImap.authLogin->isChecked())
+ na.setAuth("LOGIN");
+ else if (mImap.authPlain->isChecked())
+ na.setAuth("PLAIN");
+ else na.setAuth("*");
+ }
+}
+
+void AccountDialog::slotEditPersonalNamespace()
+{
+ NamespaceEditDialog dialog( this, ImapAccountBase::PersonalNS, &mImap.nsMap );
+ if ( dialog.exec() == QDialog::Accepted ) {
+ slotSetupNamespaces( mImap.nsMap );
+ }
+}
+
+void AccountDialog::slotEditOtherUsersNamespace()
+{
+ NamespaceEditDialog dialog( this, ImapAccountBase::OtherUsersNS, &mImap.nsMap );
+ if ( dialog.exec() == QDialog::Accepted ) {
+ slotSetupNamespaces( mImap.nsMap );
+ }
+}
+
+void AccountDialog::slotEditSharedNamespace()
+{
+ NamespaceEditDialog dialog( this, ImapAccountBase::SharedNS, &mImap.nsMap );
+ if ( dialog.exec() == QDialog::Accepted ) {
+ slotSetupNamespaces( mImap.nsMap );
+ }
+}
+
+NamespaceLineEdit::NamespaceLineEdit( QWidget* parent )
+ : KLineEdit( parent )
+{
+}
+
+void NamespaceLineEdit::setText( const QString& text )
+{
+ mLastText = text;
+ KLineEdit::setText( text );
+}
+
+NamespaceEditDialog::NamespaceEditDialog( QWidget *parent,
+ ImapAccountBase::imapNamespace type, ImapAccountBase::nsDelimMap* map )
+ : KDialogBase( parent, "edit_namespace", false, QString::null,
+ Ok|Cancel, Ok, true ), mType( type ), mNamespaceMap( map )
+{
+ QVBox *page = makeVBoxMainWidget();
+
+ QString ns;
+ if ( mType == ImapAccountBase::PersonalNS ) {
+ ns = i18n("Personal");
+ } else if ( mType == ImapAccountBase::OtherUsersNS ) {
+ ns = i18n("Other Users");
+ } else {
+ ns = i18n("Shared");
+ }
+ setCaption( i18n("Edit Namespace '%1'").arg(ns) );
+ QGrid* grid = new QGrid( 2, page );
+
+ mBg = new QButtonGroup( 0 );
+ connect( mBg, SIGNAL( clicked(int) ), this, SLOT( slotRemoveEntry(int) ) );
+ mDelimMap = mNamespaceMap->find( mType ).data();
+ ImapAccountBase::namespaceDelim::Iterator it;
+ for ( it = mDelimMap.begin(); it != mDelimMap.end(); ++it ) {
+ NamespaceLineEdit* edit = new NamespaceLineEdit( grid );
+ edit->setText( it.key() );
+ QToolButton* button = new QToolButton( grid );
+ button->setIconSet(
+ KGlobal::iconLoader()->loadIconSet( "editdelete", KIcon::Small, 0 ) );
+ button->setAutoRaise( true );
+ button->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ button->setFixedSize( 22, 22 );
+ mLineEditMap[ mBg->insert( button ) ] = edit;
+ }
+}
+
+void NamespaceEditDialog::slotRemoveEntry( int id )
+{
+ if ( mLineEditMap.contains( id ) ) {
+ // delete the lineedit and remove namespace from map
+ NamespaceLineEdit* edit = mLineEditMap[id];
+ mDelimMap.remove( edit->text() );
+ if ( edit->isModified() ) {
+ mDelimMap.remove( edit->lastText() );
+ }
+ mLineEditMap.remove( id );
+ delete edit;
+ }
+ if ( mBg->find( id ) ) {
+ // delete the button
+ delete mBg->find( id );
+ }
+ adjustSize();
+}
+
+void NamespaceEditDialog::slotOk()
+{
+ QMap<int, NamespaceLineEdit*>::Iterator it;
+ for ( it = mLineEditMap.begin(); it != mLineEditMap.end(); ++it ) {
+ NamespaceLineEdit* edit = it.data();
+ if ( edit->isModified() ) {
+ // register delimiter for new namespace
+ mDelimMap[edit->text()] = mDelimMap[edit->lastText()];
+ mDelimMap.remove( edit->lastText() );
+ }
+ }
+ mNamespaceMap->replace( mType, mDelimMap );
+ KDialogBase::slotOk();
+}
+
+} // namespace KMail
+
+#include "accountdialog.moc"
diff --git a/kmail/accountdialog.h b/kmail/accountdialog.h
new file mode 100644
index 00000000..784cee00
--- /dev/null
+++ b/kmail/accountdialog.h
@@ -0,0 +1,340 @@
+/* -*- c++ -*-
+ * accountdialog.h
+ *
+ * kmail: KDE mail client
+ * This file: Copyright (C) 2000 Espen Sand, espen@kde.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _ACCOUNT_DIALOG_H_
+#define _ACCOUNT_DIALOG_H_
+
+#include <kdialogbase.h>
+#include <klistview.h>
+#include <klineedit.h>
+#include <qguardedptr.h>
+#include "imapaccountbase.h"
+
+class QRegExpValidator;
+class QCheckBox;
+class QComboBox;
+class QPushButton;
+class QLabel;
+class QLineEdit;
+class QRadioButton;
+class QToolButton;
+class KIntNumInput;
+class KMAccount;
+class KMFolder;
+class KMServerTest;
+class QButtonGroup;
+
+namespace KPIM {
+class IdentityCombo;
+}
+
+namespace KMail {
+
+class SieveConfigEditor;
+class FolderRequester;
+
+class AccountDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ AccountDialog( const QString & caption, KMAccount *account,
+ QWidget *parent=0, const char *name=0, bool modal=true );
+ virtual ~AccountDialog();
+ private:
+ struct LocalWidgets
+ {
+ QLabel *titleLabel;
+ QLineEdit *nameEdit;
+ QComboBox *locationEdit;
+ QRadioButton *lockMutt;
+ QRadioButton *lockMuttPriv;
+ QRadioButton *lockProcmail;
+ QComboBox *procmailLockFileName;
+ QRadioButton *lockFcntl;
+ QRadioButton *lockNone;
+ QLineEdit *precommand;
+#if 0
+ QCheckBox *resourceCheck;
+ QPushButton *resourceClearButton;
+ QPushButton *resourceClearPastButton;
+#endif
+ QCheckBox *includeInCheck;
+ QCheckBox *intervalCheck;
+ QLabel *intervalLabel;
+ KIntNumInput *intervalSpin;
+ QComboBox *folderCombo;
+ //QComboBox *identityCombo;
+ KPIM::IdentityCombo *identityCombo;
+ QLabel *identityLabel;
+ };
+
+ struct MaildirWidgets
+ {
+ QLabel *titleLabel;
+ QLineEdit *nameEdit;
+ QComboBox *locationEdit;
+ QLineEdit *precommand;
+#if 0
+ QCheckBox *resourceCheck;
+ QPushButton *resourceClearButton;
+ QPushButton *resourceClearPastButton;
+#endif
+ QCheckBox *includeInCheck;
+ QCheckBox *intervalCheck;
+ QLabel *intervalLabel;
+ KIntNumInput *intervalSpin;
+ QComboBox *folderCombo;
+ //QComboBox *identityCombo;
+ KPIM::IdentityCombo *identityCombo;
+ QLabel *identityLabel;
+ };
+
+ struct PopWidgets
+ {
+ QLabel *titleLabel;
+ QLineEdit *nameEdit;
+ QLineEdit *loginEdit;
+ QLineEdit *passwordEdit;
+ QLineEdit *hostEdit;
+ QLineEdit *portEdit;
+ QLineEdit *precommand;
+ QButtonGroup *encryptionGroup;
+ QRadioButton *encryptionNone;
+ QRadioButton *encryptionSSL;
+ QRadioButton *encryptionTLS;
+ QButtonGroup *authGroup;
+ QRadioButton *authUser;
+ QRadioButton *authPlain;
+ QRadioButton *authLogin;
+ QRadioButton *authCRAM_MD5;
+ QRadioButton *authDigestMd5;
+ QRadioButton *authNTLM;
+ QRadioButton *authGSSAPI;
+ QRadioButton *authAPOP;
+
+ QPushButton *checkCapabilities;
+ QCheckBox *usePipeliningCheck;
+ QCheckBox *storePasswordCheck;
+ QCheckBox *leaveOnServerCheck;
+ QCheckBox *leaveOnServerDaysCheck;
+ KIntNumInput *leaveOnServerDaysSpin;
+ QCheckBox *leaveOnServerCountCheck;
+ KIntNumInput *leaveOnServerCountSpin;
+ QCheckBox *leaveOnServerSizeCheck;
+ KIntNumInput *leaveOnServerSizeSpin;
+#if 0
+ QCheckBox *resourceCheck;
+ QPushButton *resourceClearButton;
+ QPushButton *resourceClearPastButton;
+#endif
+ QCheckBox *includeInCheck;
+ QCheckBox *intervalCheck;
+ QCheckBox *filterOnServerCheck;
+ QLabel *intervalLabel;
+ KIntNumInput *intervalSpin;
+ KIntNumInput *filterOnServerSizeSpin;
+ QComboBox *folderCombo;
+ //QComboBox *identityCombo;
+ KPIM::IdentityCombo *identityCombo;
+ QLabel *identityLabel;
+ };
+
+ struct ImapWidgets
+ {
+ QLabel *titleLabel;
+ QLineEdit *nameEdit;
+ QLineEdit *loginEdit;
+ QLineEdit *passwordEdit;
+ QLineEdit *hostEdit;
+ QLineEdit *portEdit;
+#if 0
+ QCheckBox *resourceCheck;
+ QPushButton *resourceClearButton;
+ QPushButton *resourceClearPastButton;
+#endif
+ QCheckBox *autoExpungeCheck; // only used by normal (online) IMAP
+ QCheckBox *hiddenFoldersCheck;
+ QCheckBox *subscribedFoldersCheck;
+ QCheckBox *locallySubscribedFoldersCheck;
+ QCheckBox *loadOnDemandCheck;
+ QCheckBox *storePasswordCheck;
+ QCheckBox *progressDialogCheck; // only used by Disconnected IMAP
+ QCheckBox *includeInCheck;
+ QCheckBox *intervalCheck;
+ QCheckBox *listOnlyOpenCheck;
+ QLabel *intervalLabel;
+ KIntNumInput *intervalSpin;
+ QButtonGroup *encryptionGroup;
+ QRadioButton *encryptionNone;
+ QRadioButton *encryptionSSL;
+ QRadioButton *encryptionTLS;
+ QButtonGroup *authGroup;
+ QRadioButton *authUser;
+ QRadioButton *authPlain;
+ QRadioButton *authLogin;
+ QRadioButton *authCramMd5;
+ QRadioButton *authDigestMd5;
+ QRadioButton *authGSSAPI;
+ QRadioButton *authNTLM;
+ QRadioButton *authAnonymous;
+ QPushButton *checkCapabilities;
+ FolderRequester *trashCombo;
+ KLineEdit *personalNS;
+ KLineEdit *otherUsersNS;
+ KLineEdit *sharedNS;
+ QToolButton *editPNS;
+ QToolButton *editONS;
+ QToolButton *editSNS;
+ ImapAccountBase::nsDelimMap nsMap;
+ KPIM::IdentityCombo *identityCombo;
+ QLabel *identityLabel;
+ };
+
+ private slots:
+ virtual void slotOk();
+ void slotLocationChooser();
+ void slotMaildirChooser();
+ void slotEnablePopInterval( bool state );
+ void slotEnableImapInterval( bool state );
+ void slotEnableLocalInterval( bool state );
+ void slotEnableMaildirInterval( bool state );
+ void slotFontChanged();
+ void slotLeaveOnServerClicked();
+ void slotEnableLeaveOnServerDays( bool state );
+ void slotEnableLeaveOnServerCount( bool state );
+ void slotEnableLeaveOnServerSize( bool state );
+ void slotFilterOnServerClicked();
+ void slotPipeliningClicked();
+ void slotPopEncryptionChanged(int);
+ void slotImapEncryptionChanged(int);
+ void slotCheckPopCapabilities();
+ void slotCheckImapCapabilities();
+ void slotPopCapabilities( const QStringList &, const QStringList & );
+ void slotImapCapabilities( const QStringList &, const QStringList & );
+ void slotReloadNamespaces();
+ void slotSetupNamespaces( const ImapAccountBase::nsDelimMap& map );
+ void slotEditPersonalNamespace();
+ void slotEditOtherUsersNamespace();
+ void slotEditSharedNamespace();
+ void slotConnectionResult( int errorCode, const QString& );
+ void slotLeaveOnServerDaysChanged( int value );
+ void slotLeaveOnServerCountChanged( int value );
+ void slotFilterOnServerSizeChanged( int value );
+#if 0
+ // Moc doesn't understand #if 0, so they are also commented out
+ // void slotClearResourceAllocations();
+ // void slotClearPastResourceAllocations();
+#endif
+
+ private:
+ void makeLocalAccountPage();
+ void makeMaildirAccountPage();
+ void makePopAccountPage();
+ void makeImapAccountPage( bool disconnected = false );
+ void setupSettings();
+ void saveSettings();
+ void checkHighest( QButtonGroup * );
+ static unsigned int popCapabilitiesFromStringList( const QStringList & );
+ static unsigned int imapCapabilitiesFromStringList( const QStringList & );
+ void enablePopFeatures( unsigned int );
+ void enableImapAuthMethods( unsigned int );
+ void initAccountForConnect();
+ const QString namespaceListToString( const QStringList& list );
+
+ private:
+ LocalWidgets mLocal;
+ MaildirWidgets mMaildir;
+ PopWidgets mPop;
+ ImapWidgets mImap;
+ KMAccount *mAccount;
+ QValueList<QGuardedPtr<KMFolder> > mFolderList;
+ QStringList mFolderNames;
+ KMServerTest *mServerTest;
+ enum EncryptionMethods {
+ NoEncryption = 0,
+ SSL = 1,
+ TLS = 2
+ };
+ enum Capabilities {
+ Plain = 1,
+ Login = 2,
+ CRAM_MD5 = 4,
+ Digest_MD5 = 8,
+ Anonymous = 16,
+ APOP = 32,
+ Pipelining = 64,
+ TOP = 128,
+ UIDL = 256,
+ STLS = 512, // TLS for POP
+ STARTTLS = 512, // TLS for IMAP
+ GSSAPI = 1024,
+ NTLM = 2048,
+ AllCapa = 0xffffffff
+ };
+ unsigned int mCurCapa;
+ unsigned int mCapaNormal;
+ unsigned int mCapaSSL;
+ unsigned int mCapaTLS;
+ KMail::SieveConfigEditor *mSieveConfigEditor;
+ QRegExpValidator *mValidator;
+};
+
+class NamespaceLineEdit: public KLineEdit
+{
+ Q_OBJECT
+
+ public:
+ NamespaceLineEdit( QWidget* parent );
+
+ const QString& lastText() { return mLastText; }
+
+ public slots:
+ virtual void setText ( const QString & );
+
+ private:
+ QString mLastText;
+};
+
+class NamespaceEditDialog: public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ NamespaceEditDialog( QWidget* parent, ImapAccountBase::imapNamespace type,
+ ImapAccountBase::nsDelimMap* map );
+
+ protected slots:
+ void slotOk();
+ void slotRemoveEntry( int );
+
+ private:
+ ImapAccountBase::imapNamespace mType;
+ ImapAccountBase::nsDelimMap* mNamespaceMap;
+ ImapAccountBase::namespaceDelim mDelimMap;
+ QMap<int, NamespaceLineEdit*> mLineEditMap;
+ QButtonGroup* mBg;
+};
+
+} // namespace KMail
+
+#endif
diff --git a/kmail/accountmanager.cpp b/kmail/accountmanager.cpp
new file mode 100644
index 00000000..c27432ae
--- /dev/null
+++ b/kmail/accountmanager.cpp
@@ -0,0 +1,415 @@
+// KMail Account Manager
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "accountmanager.h"
+
+#include "kmaccount.h"
+#include "kmacctfolder.h"
+#include "kmacctmaildir.h"
+#include "kmacctlocal.h"
+#include "popaccount.h"
+#include "kmacctimap.h"
+#include "networkaccount.h"
+#include "kmacctcachedimap.h"
+#include "broadcaststatus.h"
+#include "kmfiltermgr.h"
+#include "globalsettings.h"
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kapplication.h>
+
+#include <qregexp.h>
+#include <qvaluelist.h>
+
+using namespace KMail;
+
+//-----------------------------------------------------------------------------
+AccountManager::AccountManager()
+ :QObject(), mNewMailArrived( false ), mInteractive( false ),
+ mTotalNewMailsArrived( 0 ), mDisplaySummary( false )
+{
+ mAcctChecking.clear();
+ mAcctTodo.clear();
+}
+
+//-----------------------------------------------------------------------------
+AccountManager::~AccountManager()
+{
+ writeConfig( false );
+}
+
+
+//-----------------------------------------------------------------------------
+void AccountManager::writeConfig( bool withSync )
+{
+ KConfig* config = KMKernel::config();
+ QString groupName;
+
+ KConfigGroupSaver saver(config, "General");
+ config->writeEntry("accounts", mAcctList.count());
+
+ // first delete all account groups in the config file:
+ QStringList accountGroups =
+ config->groupList().grep( QRegExp( "Account \\d+" ) );
+ for ( QStringList::Iterator it = accountGroups.begin() ;
+ it != accountGroups.end() ; ++it )
+ config->deleteGroup( *it );
+
+ // now write new account groups:
+ int i = 1;
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it, ++i ) {
+ groupName.sprintf("Account %d", i);
+ KConfigGroupSaver saver(config, groupName);
+ (*it)->writeConfig(*config);
+ }
+ if (withSync) config->sync();
+}
+
+
+//-----------------------------------------------------------------------------
+void AccountManager::readConfig(void)
+{
+ KConfig* config = KMKernel::config();
+ KMAccount* acct;
+ QString acctType, acctName;
+ QCString groupName;
+ int i, num;
+ uint id;
+
+ for ( AccountList::Iterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it )
+ delete *it;
+ mAcctList.clear();
+
+ KConfigGroup general(config, "General");
+ num = general.readNumEntry("accounts", 0);
+
+ for (i=1; i<=num; i++)
+ {
+ groupName.sprintf("Account %d", i);
+ KConfigGroupSaver saver(config, groupName);
+ acctType = config->readEntry("Type");
+ // Provide backwards compatibility
+ if (acctType == "advanced pop" || acctType == "experimental pop")
+ acctType = "pop";
+ acctName = config->readEntry("Name");
+ id = config->readUnsignedNumEntry("Id", 0);
+ if (acctName.isEmpty()) acctName = i18n("Account %1").arg(i);
+ acct = create(acctType, acctName, id);
+ if (!acct) continue;
+ add(acct);
+ acct->readConfig(*config);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void AccountManager::singleCheckMail(KMAccount *account, bool interactive)
+{
+ mNewMailArrived = false;
+ mInteractive = interactive;
+
+ // if sync has been requested by the user then check if check-interval was disabled by user, if yes, then
+ // de-install the timer
+ // Safe guard against an infinite sync loop (kolab/issue2607)
+ if ( mInteractive )
+ account->readTimerConfig();
+
+ // queue the account
+ mAcctTodo.append(account);
+
+ if (account->checkingMail())
+ {
+ kdDebug(5006) << "account " << account->name() << " busy, queuing" << endl;
+ return;
+ }
+
+ processNextCheck(false);
+}
+
+//-----------------------------------------------------------------------------
+void AccountManager::processNextCheck( bool _newMail )
+{
+ kdDebug(5006) << "processNextCheck, remaining " << mAcctTodo.count() << endl;
+ if ( _newMail )
+ mNewMailArrived = true;
+
+ for ( AccountList::Iterator it( mAcctChecking.begin() ), end( mAcctChecking.end() ); it != end; ) {
+ KMAccount* acct = *it;
+ ++it;
+ if ( acct->checkingMail() )
+ continue;
+ // check done
+ kdDebug(5006) << "account " << acct->name() << " finished check" << endl;
+ mAcctChecking.remove( acct );
+ kmkernel->filterMgr()->deref();
+ disconnect( acct, SIGNAL( finishedCheck( bool, CheckStatus ) ),
+ this, SLOT( processNextCheck( bool ) ) );
+ }
+ if ( mAcctChecking.isEmpty() ) {
+ // all checks finished, display summary
+ if ( mDisplaySummary )
+ KPIM::BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
+ mTotalNewMailsArrived );
+ emit checkedMail( mNewMailArrived, mInteractive, mTotalNewInFolder );
+ mTotalNewMailsArrived = 0;
+ mTotalNewInFolder.clear();
+ mDisplaySummary = false;
+ }
+ if ( mAcctTodo.isEmpty() ) return;
+
+ QString accountHostName;
+
+ KMAccount *curAccount = 0;
+ for ( AccountList::Iterator it ( mAcctTodo.begin() ), last ( mAcctTodo.end() ); it != last; ) {
+ KMAccount *acct = *it;
+ ++it;
+ if ( !acct->checkingMail() && acct->mailCheckCanProceed() ) {
+ curAccount = acct;
+ mAcctTodo.remove( acct );
+ break;
+ }
+ }
+ if ( !curAccount ) return; // no account or all of them are already checking
+
+ if ( curAccount->type() != "imap" && curAccount->type() != "cachedimap" &&
+ curAccount->folder() == 0 ) {
+ QString tmp = i18n("Account %1 has no mailbox defined:\n"
+ "mail checking aborted;\n"
+ "check your account settings.")
+ .arg(curAccount->name());
+ KMessageBox::information(0,tmp);
+ emit checkedMail( false, mInteractive, mTotalNewInFolder );
+ mTotalNewMailsArrived = 0;
+ mTotalNewInFolder.clear();
+ return;
+ }
+
+ connect( curAccount, SIGNAL( finishedCheck( bool, CheckStatus ) ),
+ this, SLOT( processNextCheck( bool ) ) );
+
+ KPIM::BroadcastStatus::instance()->setStatusMsg(
+ i18n("Checking account %1 for new mail").arg(curAccount->name()));
+
+ kdDebug(5006) << "processing next mail check for " << curAccount->name() << endl;
+
+ curAccount->setCheckingMail( true );
+ mAcctChecking.append( curAccount );
+ kmkernel->filterMgr()->ref();
+ curAccount->processNewMail( mInteractive );
+}
+
+//-----------------------------------------------------------------------------
+KMAccount* AccountManager::create( const QString &aType, const QString &aName, uint id )
+{
+ KMAccount* act = 0;
+ if ( id == 0 )
+ id = createId();
+
+ if ( aType == "local" ) {
+ act = new KMAcctLocal(this, aName.isEmpty() ? i18n("Local Account") : aName, id);
+ act->setFolder( kmkernel->inboxFolder() );
+ } else if ( aType == "maildir" ) {
+ act = new KMAcctMaildir(this, aName.isEmpty() ? i18n("Local Account") : aName, id);
+ act->setFolder( kmkernel->inboxFolder() );
+ } else if ( aType == "pop" ) {
+ act = new KMail::PopAccount(this, aName.isEmpty() ? i18n("POP Account") : aName, id);
+ act->setFolder( kmkernel->inboxFolder() );
+ } else if ( aType == "imap" ) {
+ act = new KMAcctImap(this, aName.isEmpty() ? i18n("IMAP Account") : aName, id);
+ } else if (aType == "cachedimap") {
+ act = new KMAcctCachedImap(this, aName.isEmpty() ? i18n("IMAP Account") : aName, id);
+ }
+ if ( !act ) {
+ kdWarning(5006) << "Attempt to instantiate a non-existing account type!" << endl;
+ return 0;
+ }
+ connect( act, SIGNAL( newMailsProcessed( const QMap<QString, int> & ) ),
+ this, SLOT( addToTotalNewMailCount( const QMap<QString, int> & ) ) );
+ return act;
+}
+
+
+//-----------------------------------------------------------------------------
+void AccountManager::add( KMAccount *account )
+{
+ if ( account ) {
+ mAcctList.append( account );
+ // init folder's account list
+ KMAcctFolder *folder = static_cast<KMAcctFolder*>( account->folder() );
+ if ( folder && !folder->hasAccounts() ) {
+ folder->addAccount( account );
+ }
+ emit accountAdded( account );
+ account->installTimer();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+KMAccount* AccountManager::findByName(const QString &aName) const
+{
+ if ( aName.isEmpty() ) return 0;
+
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
+ if ( (*it)->name() == aName ) return (*it);
+ }
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+KMAccount* AccountManager::find( const uint id ) const
+{
+ if (id == 0) return 0;
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
+ if ( (*it)->id() == id ) return (*it);
+ }
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+KMAccount* AccountManager::first()
+{
+ if ( !mAcctList.empty() ) {
+ mPtrListInterfaceProxyIterator = mAcctList.begin();
+ return *mPtrListInterfaceProxyIterator;
+ } else {
+ return 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+KMAccount* AccountManager::next()
+{
+ ++mPtrListInterfaceProxyIterator;
+ if ( mPtrListInterfaceProxyIterator == mAcctList.end() )
+ return 0;
+ else
+ return *mPtrListInterfaceProxyIterator;
+}
+
+//-----------------------------------------------------------------------------
+bool AccountManager::remove( KMAccount* acct )
+{
+ if( !acct )
+ return false;
+ mAcctList.remove( acct );
+ emit accountRemoved( acct );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void AccountManager::checkMail( bool _interactive )
+{
+ mNewMailArrived = false;
+
+ if ( mAcctList.isEmpty() ) {
+ KMessageBox::information( 0,i18n("You need to add an account in the network "
+ "section of the settings in order to receive mail.") );
+ return;
+ }
+ mDisplaySummary = true;
+
+ mTotalNewMailsArrived=0;
+ mTotalNewInFolder.clear();
+
+ for ( AccountList::Iterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
+ if ( !(*it)->checkExclude() )
+ singleCheckMail( (*it), _interactive);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void AccountManager::singleInvalidateIMAPFolders(KMAccount *account) {
+ account->invalidateIMAPFolders();
+}
+
+
+void AccountManager::invalidateIMAPFolders()
+{
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it )
+ singleInvalidateIMAPFolders( *it );
+}
+
+
+//-----------------------------------------------------------------------------
+QStringList AccountManager::getAccounts() const
+{
+ QStringList strList;
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
+ strList.append( (*it)->name() );
+ }
+ return strList;
+}
+
+//-----------------------------------------------------------------------------
+void AccountManager::intCheckMail(int item, bool _interactive)
+{
+ mNewMailArrived = false;
+ mTotalNewMailsArrived = 0;
+ mTotalNewInFolder.clear();
+ if ( KMAccount *acct = mAcctList[ item ] )
+ singleCheckMail( acct, _interactive );
+ mDisplaySummary = false;
+}
+
+
+//-----------------------------------------------------------------------------
+void AccountManager::addToTotalNewMailCount( const QMap<QString, int> & newInFolder )
+{
+ for ( QMap<QString, int>::const_iterator it = newInFolder.begin();
+ it != newInFolder.end(); ++it ) {
+ mTotalNewMailsArrived += it.data();
+ if ( mTotalNewInFolder.find( it.key() ) == mTotalNewInFolder.end() )
+ mTotalNewInFolder[it.key()] = it.data();
+ else
+ mTotalNewInFolder[it.key()] += it.data();
+ }
+}
+
+//-----------------------------------------------------------------------------
+uint AccountManager::createId()
+{
+ QValueList<uint> usedIds;
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
+ usedIds << (*it)->id();
+ }
+
+ usedIds << 0; // 0 is default for unknown
+ int newId;
+ do
+ {
+ newId = kapp->random();
+ } while ( usedIds.find(newId) != usedIds.end() );
+
+ return newId;
+}
+
+//-----------------------------------------------------------------------------
+void AccountManager::cancelMailCheck()
+{
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
+ (*it)->cancelMailCheck();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void AccountManager::readPasswords()
+{
+ for ( AccountList::ConstIterator it( mAcctList.begin() ), end( mAcctList.end() ); it != end; ++it ) {
+ NetworkAccount *acct = dynamic_cast<NetworkAccount*>( (*it) );
+ if ( acct )
+ acct->readPassword();
+ }
+}
+
+#include "accountmanager.moc"
diff --git a/kmail/accountmanager.h b/kmail/accountmanager.h
new file mode 100644
index 00000000..fda0591f
--- /dev/null
+++ b/kmail/accountmanager.h
@@ -0,0 +1,141 @@
+/* -*- mode: C++ -*-
+ * kmail: KDE mail client
+ * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef accountmanager_h
+#define accountmanager_h
+
+#include <qobject.h>
+#include "kmaccount.h"
+#include <kdepimmacros.h>
+
+class QString;
+class QStringList;
+
+namespace KMail {
+/**
+ * The account manager is responsible for creating accounts of various types
+ * via the factory method create() and for keeping track of them.
+ */
+class KDE_EXPORT AccountManager: public QObject
+{
+ Q_OBJECT
+ friend class ::KMAccount;
+
+public:
+ /** Initializes the account manager. readConfig() needs to be called in
+ * order to fill it with persisted account information from the config file. */
+ AccountManager();
+ ~AccountManager();
+
+ /** Completely reload accounts from config. */
+ void readConfig(void);
+
+ /** Write accounts to config. */
+ void writeConfig( bool withSync=true );
+
+ /** Create a new account of given type with given name. Currently
+ the types "local" for local mail folders and "pop" are supported. */
+ KMAccount* create( const QString& type,
+ const QString& name = QString::null,
+ uint id = 0);
+
+ /** Adds an account to the list of accounts */
+ void add( KMAccount *account );
+
+ /** Find account by name. Returns 0 if account does not exist.
+ Search is done case sensitive. */
+ KMAccount* findByName( const QString& name ) const;
+
+ /** Find account by id. Returns 0 if account does not exist.
+ */
+ KMAccount* find( const uint id ) const;
+
+ /** Physically remove account. Also deletes the given account object !
+ Returns FALSE and does nothing if the account cannot be removed. */
+ bool remove( KMAccount* );
+
+ /** First account of the list */
+ const KMAccount* first() const { return first(); }
+ KMAccount* first();
+
+ /** Next account of the list */
+ const KMAccount* next() const { return next(); }
+ KMAccount* next();
+
+ /** Processes all accounts looking for new mail */
+ void checkMail( bool interactive = true );
+
+ /** Delete all IMAP folders and resync them */
+ void invalidateIMAPFolders();
+
+ QStringList getAccounts() const;
+
+ /// Called on exit (KMMainWin::queryExit)
+ void cancelMailCheck();
+
+ /** Read passwords of all accounts from the wallet */
+ void readPasswords();
+
+public slots:
+ void singleCheckMail( KMAccount *, bool interactive = true );
+ void singleInvalidateIMAPFolders( KMAccount * );
+
+ void intCheckMail( int, bool interactive = true );
+ void processNextCheck( bool newMail );
+
+ /** this slot increases the count of new mails to show a total number
+ after checking in multiple accounts. */
+ void addToTotalNewMailCount( const QMap<QString, int> & newInFolder );
+
+
+signals:
+ /**
+ * Emitted if new mail has been collected.
+ * @param newMail true if there was new mail
+ * @param interactive true if the mail check was initiated by the user
+ * @param newInFolder number of new messages for each folder
+ **/
+ void checkedMail( bool newMail, bool interactive,
+ const QMap<QString, int> & newInFolder );
+ /** emitted when an account is removed */
+ void accountRemoved( KMAccount* account );
+ /** emitted when an account is added */
+ void accountAdded( KMAccount* account );
+
+private:
+ /** Create a new unique ID */
+ uint createId();
+
+ AccountList mAcctList;
+ AccountList::Iterator mPtrListInterfaceProxyIterator;
+ AccountList mAcctChecking;
+ AccountList mAcctTodo;
+ bool mNewMailArrived;
+ bool mInteractive;
+ int mTotalNewMailsArrived;
+
+ // for detailed (per folder) new mail notification
+ QMap<QString, int> mTotalNewInFolder;
+
+ // if a summary should be displayed
+ bool mDisplaySummary;
+};
+
+} // namespace KMail
+#endif /*accountmanager_h*/
diff --git a/kmail/accountwizard.cpp b/kmail/accountwizard.cpp
new file mode 100644
index 00000000..cc831790
--- /dev/null
+++ b/kmail/accountwizard.cpp
@@ -0,0 +1,799 @@
+/*******************************************************************************
+**
+** Filename : accountwizard.cpp
+** Created on : 07 February, 2005
+** Copyright : (c) 2005 Tobias Koenig
+** Email : tokoe@kde.org
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** In addition, as a special exception, the copyright holders give
+** permission to link the code of this program with any edition of
+** the Qt library by Trolltech AS, Norway (or with modified versions
+** of Qt that use the same license as Qt), and distribute linked
+** combinations including the two. You must obey the GNU General
+** Public License in all respects for all of the code used other than
+** Qt. If you modify this file, you may extend this exception to
+** your version of the file, but you are not obligated to do so. If
+** you do not wish to do so, delete this exception statement from
+** your version.
+*******************************************************************************/
+
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <klineedit.h>
+#include <klistbox.h>
+#include <klocale.h>
+
+#include <qcheckbox.h>
+#include <qdir.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qvbox.h>
+
+#include "kmacctlocal.h"
+#include "kmkernel.h"
+#include "popaccount.h"
+#include "kmacctimap.h"
+#include "kmacctcachedimap.h"
+#include "kmacctmaildir.h"
+#include "accountmanager.h"
+using KMail::AccountManager;
+
+#include "globalsettings.h"
+#include "kmservertest.h"
+#include "kmtransport.h"
+#include "libkpimidentities/identity.h"
+#include "libkpimidentities/identitymanager.h"
+#include "protocols.h"
+
+#include "accountwizard.h"
+
+enum Capabilities
+{
+ Plain = 1,
+ Login = 2,
+ CRAM_MD5 = 4,
+ Digest_MD5 = 8,
+ Anonymous = 16,
+ APOP = 32,
+ Pipelining = 64,
+ TOP = 128,
+ UIDL = 256,
+ STLS = 512, // TLS for POP
+ STARTTLS = 512, // TLS for IMAP
+ GSSAPI = 1024,
+ NTLM = 2048,
+ AllCapa = 0xffffffff
+};
+
+class AccountTypeBox : public KListBox
+{
+ public:
+ enum Type { Local, POP3, IMAP, dIMAP, Maildir };
+
+ AccountTypeBox( QWidget *parent )
+ : KListBox( parent, "AccountTypeBox" )
+ {
+ mTypeList << i18n( "Local mailbox" );
+ mTypeList << i18n( "POP3" );
+ mTypeList << i18n( "IMAP" );
+ mTypeList << i18n( "Disconnected IMAP" );
+ mTypeList << i18n( "Maildir mailbox" );
+
+ insertStringList( mTypeList );
+ }
+
+ void setType( Type type )
+ {
+ setCurrentItem( (int)type );
+ }
+
+ Type type() const
+ {
+ return (Type)currentItem();
+ }
+
+ private:
+ QStringList mTypeList;
+};
+
+AccountWizard::AccountWizard( KMKernel *kernel, QWidget *parent )
+ : KWizard( parent, "KWizard" ), mKernel( kernel ),
+ mAccount( 0 ), mTransportInfo( 0 ), mServerTest( 0 )
+{
+ setupWelcomePage();
+ setupAccountTypePage();
+ setupAccountInformationPage();
+ setupLoginInformationPage();
+ setupServerInformationPage();
+}
+
+void AccountWizard::start( KMKernel *kernel, QWidget *parent )
+{
+ KConfigGroup wizardConfig( KMKernel::config(), "AccountWizard" );
+
+ if ( wizardConfig.readBoolEntry( "ShowOnStartup", true ) ) {
+ AccountWizard wizard( kernel, parent );
+ int result = wizard.exec();
+ if ( result == QDialog::Accepted ) {
+ wizardConfig.writeEntry( "ShowOnStartup", false );
+ kernel->slotConfigChanged();
+ }
+ }
+}
+
+void AccountWizard::showPage( QWidget *page )
+{
+ if ( page == mWelcomePage ) {
+ // do nothing
+ } else if ( page == mAccountTypePage ) {
+ if ( mTypeBox->currentItem() == -1 )
+ mTypeBox->setType( AccountTypeBox::POP3 );
+ } else if ( page == mAccountInformationPage ) {
+ if ( mRealName->text().isEmpty() && mEMailAddress->text().isEmpty() &&
+ mOrganization->text().isEmpty() ) {
+ KPIM::IdentityManager *manager = mKernel->identityManager();
+ const KPIM::Identity &identity = manager->defaultIdentity();
+
+ mRealName->setText( identity.fullName() );
+ mEMailAddress->setText( identity.emailAddr() );
+ mOrganization->setText( identity.organization() );
+ }
+ } else if ( page == mLoginInformationPage ) {
+ if ( mLoginName->text().isEmpty() ) {
+ // try to extract login from email address
+ QString email = mEMailAddress->text();
+ int pos = email.find( '@' );
+ if ( pos != -1 )
+ mLoginName->setText( email.left( pos ) );
+
+ // take the whole email as login otherwise?!?
+ }
+ } else if ( page == mServerInformationPage ) {
+ if ( mTypeBox->type() == AccountTypeBox::Local ||
+ mTypeBox->type() == AccountTypeBox::Maildir ) {
+ mIncomingServerWdg->hide();
+ mIncomingLocationWdg->show();
+ mIncomingLabel->setText( i18n( "Location:" ) );
+
+ if ( mTypeBox->type() == AccountTypeBox::Local )
+ mIncomingLocation->setText( QDir::homeDirPath() + "/inbox" );
+ else
+ mIncomingLocation->setText( QDir::homeDirPath() + "/Mail/" );
+ } else {
+ mIncomingLocationWdg->hide();
+ mIncomingServerWdg->show();
+ mIncomingLabel->setText( i18n( "Incoming server:" ) );
+ }
+
+ setFinishEnabled( mServerInformationPage, true );
+ }
+
+ QWizard::showPage( page );
+}
+
+void AccountWizard::setupWelcomePage()
+{
+ mWelcomePage = new QVBox( this );
+ ((QVBox*)mWelcomePage)->setSpacing( KDialog::spacingHint() );
+
+ QLabel *label = new QLabel( i18n( "Welcome to KMail" ), mWelcomePage );
+ QFont font = label->font();
+ font.setBold( true );
+ label->setFont( font );
+
+ new QLabel( i18n( "<qt>It seems you have started KMail for the first time. "
+ "You can use this wizard to setup your mail accounts. Just "
+ "enter the connection data that you received from your email provider "
+ "into the following pages.</qt>" ), mWelcomePage );
+
+ addPage( mWelcomePage, i18n( "Welcome" ) );
+}
+
+void AccountWizard::setupAccountTypePage()
+{
+ mAccountTypePage = new QVBox( this );
+ ((QVBox*)mAccountTypePage)->setSpacing( KDialog::spacingHint() );
+
+ new QLabel( i18n( "Select what kind of account you would like to create" ), mAccountTypePage );
+
+ mTypeBox = new AccountTypeBox( mAccountTypePage );
+
+ addPage( mAccountTypePage, i18n( "Account Type" ) );
+}
+
+void AccountWizard::setupAccountInformationPage()
+{
+ mAccountInformationPage = new QWidget( this );
+ QGridLayout *layout = new QGridLayout( mAccountInformationPage, 3, 2,
+ KDialog::marginHint(), KDialog::spacingHint() );
+
+ QLabel *label = new QLabel( i18n( "Real name:" ), mAccountInformationPage );
+ mRealName = new KLineEdit( mAccountInformationPage );
+ label->setBuddy( mRealName );
+
+ layout->addWidget( label, 0, 0 );
+ layout->addWidget( mRealName, 0, 1 );
+
+ label = new QLabel( i18n( "E-mail address:" ), mAccountInformationPage );
+ mEMailAddress = new KLineEdit( mAccountInformationPage );
+ label->setBuddy( mEMailAddress );
+
+ layout->addWidget( label, 1, 0 );
+ layout->addWidget( mEMailAddress, 1, 1 );
+
+ label = new QLabel( i18n( "Organization:" ), mAccountInformationPage );
+ mOrganization = new KLineEdit( mAccountInformationPage );
+ label->setBuddy( mOrganization );
+
+ layout->addWidget( label, 2, 0 );
+ layout->addWidget( mOrganization, 2, 1 );
+
+ addPage( mAccountInformationPage, i18n( "Account Information" ) );
+}
+
+void AccountWizard::setupLoginInformationPage()
+{
+ mLoginInformationPage = new QWidget( this );
+ QGridLayout *layout = new QGridLayout( mLoginInformationPage, 2, 2,
+ KDialog::marginHint(), KDialog::spacingHint() );
+
+ QLabel *label = new QLabel( i18n( "Login name:" ), mLoginInformationPage );
+ mLoginName = new KLineEdit( mLoginInformationPage );
+ label->setBuddy( mLoginName );
+
+ layout->addWidget( label, 0, 0 );
+ layout->addWidget( mLoginName, 0, 1 );
+
+ label = new QLabel( i18n( "Password:" ), mLoginInformationPage );
+ mPassword = new KLineEdit( mLoginInformationPage );
+ mPassword->setEchoMode( QLineEdit::Password );
+ label->setBuddy( mPassword );
+
+ layout->addWidget( label, 1, 0 );
+ layout->addWidget( mPassword, 1, 1 );
+
+ addPage( mLoginInformationPage, i18n( "Login Information" ) );
+}
+
+void AccountWizard::setupServerInformationPage()
+{
+ mServerInformationPage = new QWidget( this );
+ QGridLayout *layout = new QGridLayout( mServerInformationPage, 3, 2,
+ KDialog::marginHint(), KDialog::spacingHint() );
+
+ mIncomingLabel = new QLabel( mServerInformationPage );
+
+ mIncomingServerWdg = new QVBox( mServerInformationPage );
+ mIncomingServer = new KLineEdit( mIncomingServerWdg );
+ mIncomingUseSSL = new QCheckBox( i18n( "Use secure connection (SSL)" ), mIncomingServerWdg );
+
+ mIncomingLocationWdg = new QHBox( mServerInformationPage );
+ mIncomingLocation = new KLineEdit( mIncomingLocationWdg );
+ mChooseLocation = new QPushButton( i18n( "Choose..." ), mIncomingLocationWdg );
+
+ connect( mChooseLocation, SIGNAL( clicked() ),
+ this, SLOT( chooseLocation() ) );
+
+ layout->addWidget( mIncomingLabel, 0, 0, AlignTop );
+ layout->addWidget( mIncomingLocationWdg, 0, 1 );
+ layout->addWidget( mIncomingServerWdg, 0, 1 );
+
+ QLabel *label = new QLabel( i18n( "Outgoing server:" ), mServerInformationPage );
+ mOutgoingServer = new KLineEdit( mServerInformationPage );
+ label->setBuddy( mOutgoingServer );
+
+ layout->addWidget( label, 1, 0 );
+ layout->addWidget( mOutgoingServer, 1, 1 );
+
+ mOutgoingUseSSL = new QCheckBox( i18n( "Use secure connection (SSL)" ), mServerInformationPage );
+ layout->addWidget( mOutgoingUseSSL, 2, 1 );
+
+ mLocalDelivery = new QCheckBox( i18n( "Use local delivery" ),
+ mServerInformationPage );
+ layout->addWidget( mLocalDelivery, 3, 0 );
+
+ connect( mLocalDelivery, SIGNAL( toggled( bool ) ),
+ mOutgoingServer, SLOT( setDisabled( bool ) ) );
+
+ addPage( mServerInformationPage, i18n( "Server Information" ) );
+}
+
+void AccountWizard::chooseLocation()
+{
+ QString location;
+
+ if ( mTypeBox->type() == AccountTypeBox::Local ) {
+ location = KFileDialog::getSaveFileName( QString(), QString(), this );
+ } else if ( mTypeBox->type() == AccountTypeBox::Maildir ) {
+ location = KFileDialog::getExistingDirectory( QString(), this );
+ }
+
+ if ( !location.isEmpty() )
+ mIncomingLocation->setText( location );
+}
+
+QString AccountWizard::accountName() const
+{
+ // create account name
+ QString name( i18n( "None" ) );
+
+ QString email = mEMailAddress->text();
+ int pos = email.find( '@' );
+ if ( pos != -1 ) {
+ name = email.mid( pos + 1 );
+ name[ 0 ] = name[ 0 ].upper();
+ }
+
+ return name;
+}
+
+QLabel *AccountWizard::createInfoLabel( const QString &msg )
+{
+ QLabel *label = new QLabel( msg, this );
+ label->setFrameStyle( QFrame::Panel | QFrame::Raised );
+ label->resize( fontMetrics().width( msg ) + 20, label->height() * 2 );
+ label->move( width() / 2 - label->width() / 2, height() / 2 - label->height() / 2 );
+ label->show();
+
+ return label;
+}
+
+void AccountWizard::accept()
+{
+ // store identity information
+ KPIM::IdentityManager *manager = mKernel->identityManager();
+ KPIM::Identity &identity = manager->modifyIdentityForUoid( manager->defaultIdentity().uoid() );
+
+ identity.setFullName( mRealName->text() );
+ identity.setEmailAddr( mEMailAddress->text() );
+ identity.setOrganization( mOrganization->text() );
+
+ manager->commit();
+
+ QTimer::singleShot( 0, this, SLOT( createTransport() ) );
+}
+
+void AccountWizard::createTransport()
+{
+ // create outgoing account
+ KConfigGroup general( KMKernel::config(), "General" );
+
+ uint numTransports = general.readNumEntry( "transports", 0 );
+
+ for ( uint i = 1 ; i <= numTransports ; i++ ) {
+ KMTransportInfo *info = new KMTransportInfo();
+ info->readConfig( i );
+ mTransportInfoList.append( info );
+ }
+
+ mTransportInfo = new KMTransportInfo();
+
+ if ( mLocalDelivery->isChecked() ) { // local delivery
+ mTransportInfo->type = "sendmail";
+ mTransportInfo->name = i18n( "Sendmail" );
+ mTransportInfo->host = "/usr/sbin/sendmail"; // TODO: search for sendmail in PATH
+ mTransportInfo->auth = false;
+ mTransportInfo->setStorePasswd( false );
+
+ QTimer::singleShot( 0, this, SLOT( transportCreated() ) );
+ } else { // delivery via SMTP
+ mTransportInfo->type = "smtp";
+ mTransportInfo->name = accountName();
+ mTransportInfo->host = mOutgoingServer->text();
+ mTransportInfo->user = mLoginName->text();
+ mTransportInfo->setPasswd( mPassword->text() );
+
+ int port = (mOutgoingUseSSL->isChecked() ? 465 : 25);
+ checkSmtpCapabilities( mTransportInfo->host, port );
+ }
+}
+
+void AccountWizard::transportCreated()
+{
+ mTransportInfoList.append( mTransportInfo );
+
+ KConfigGroup general( KMKernel::config(), "General" );
+ general.writeEntry( "transports", mTransportInfoList.count() );
+
+ for ( uint i = 0 ; i < mTransportInfoList.count() ; i++ )
+ mTransportInfo->writeConfig( i + 1 );
+
+ // No default transport? => set the first transport as the default
+ if ( GlobalSettings::self()->defaultTransport().isEmpty() ) {
+ KConfigGroup general( KMKernel::config(), "General" );
+
+ if ( mTransportInfoList.count() > 0 ) {
+ KMTransportInfo info;
+ info.readConfig( 1 );
+ KConfigGroup composer( KMKernel::config(), "Composer" );
+ GlobalSettings::self()->setDefaultTransport( info.name );
+ GlobalSettings::self()->setCurrentTransport( info.name );
+ }
+ }
+
+ mTransportInfoList.setAutoDelete( true );
+ mTransportInfoList.clear();
+
+ QTimer::singleShot( 0, this, SLOT( createAccount() ) );
+}
+
+void AccountWizard::createAccount()
+{
+ // create incoming account
+ AccountManager *acctManager = mKernel->acctMgr();
+
+ int port = 0;
+
+ switch ( mTypeBox->type() ) {
+ case AccountTypeBox::Local:
+ {
+ mAccount = acctManager->create( "local", i18n( "Local Account" ) );
+ static_cast<KMAcctLocal*>( mAccount )->setLocation( mIncomingLocation->text() );
+ break;
+ }
+ case AccountTypeBox::POP3:
+ {
+ mAccount = acctManager->create( "pop", accountName() );
+ KMail::PopAccount *acct = static_cast<KMail::PopAccount*>( mAccount );
+ acct->setLogin( mLoginName->text() );
+ acct->setPasswd( mPassword->text() );
+ acct->setHost( mIncomingServer->text() );
+ port = mIncomingUseSSL->isChecked() ? 995 : 110;
+ break;
+ }
+ case AccountTypeBox::IMAP:
+ {
+ mAccount = acctManager->create( "imap", accountName() );
+ KMAcctImap *acct = static_cast<KMAcctImap*>( mAccount );
+ acct->setLogin( mLoginName->text() );
+ acct->setPasswd( mPassword->text() );
+ acct->setHost( mIncomingServer->text() );
+ port = mIncomingUseSSL->isChecked() ? 993 : 143;
+ break;
+ }
+ case AccountTypeBox::dIMAP:
+ {
+ mAccount = acctManager->create( "cachedimap", accountName() );
+ KMAcctCachedImap *acct = static_cast<KMAcctCachedImap*>( mAccount );
+ acct->setLogin( mLoginName->text() );
+ acct->setPasswd( mPassword->text() );
+ acct->setHost( mIncomingServer->text() );
+ port = mIncomingUseSSL->isChecked() ? 993 : 143;
+ break;
+ }
+ case AccountTypeBox::Maildir:
+ {
+ mAccount = acctManager->create( "maildir", i18n( "Local Account" ) );
+ static_cast<KMAcctMaildir*>( mAccount )->setLocation( mIncomingLocation->text() );
+ break;
+ }
+ }
+
+ if ( mTypeBox->type() == AccountTypeBox::POP3 )
+ checkPopCapabilities( mIncomingServer->text(), port );
+ else if ( mTypeBox->type() == AccountTypeBox::IMAP || mTypeBox->type() == AccountTypeBox::dIMAP )
+ checkImapCapabilities( mIncomingServer->text(), port );
+ else
+ QTimer::singleShot( 0, this, SLOT( accountCreated() ) );
+}
+
+void AccountWizard::accountCreated()
+{
+ if ( mAccount )
+ {
+ mKernel->acctMgr()->add( mAccount );
+ mKernel->cleanupImapFolders();
+ }
+
+ finished();
+}
+
+void AccountWizard::finished()
+{
+ GlobalSettings::self()->writeConfig();
+
+ QWizard::accept();
+}
+
+// ----- Security Checks --------------
+
+void AccountWizard::checkPopCapabilities( const QString &server, int port )
+{
+ delete mServerTest;
+ mServerTest = new KMServerTest( POP_PROTOCOL, server, port );
+
+ connect( mServerTest, SIGNAL( capabilities( const QStringList&, const QStringList& ) ),
+ this, SLOT( popCapabilities( const QStringList&, const QStringList& ) ) );
+
+ mAuthInfoLabel = createInfoLabel( i18n( "Check for supported security capabilities of %1..." ).arg( server ) );
+}
+
+void AccountWizard::checkImapCapabilities( const QString &server, int port )
+{
+ delete mServerTest;
+ mServerTest = new KMServerTest( IMAP_PROTOCOL, server, port );
+
+ connect( mServerTest, SIGNAL( capabilities( const QStringList&, const QStringList& ) ),
+ this, SLOT( imapCapabilities( const QStringList&, const QStringList& ) ) );
+
+ mAuthInfoLabel = createInfoLabel( i18n( "Check for supported security capabilities of %1..." ).arg( server ) );
+}
+
+void AccountWizard::checkSmtpCapabilities( const QString &server, int port )
+{
+ delete mServerTest;
+ mServerTest = new KMServerTest( SMTP_PROTOCOL, server, port );
+
+ connect( mServerTest, SIGNAL( capabilities( const QStringList&, const QStringList&,
+ const QString&, const QString&, const QString& ) ),
+ this, SLOT( smtpCapabilities( const QStringList&, const QStringList&,
+ const QString&, const QString&, const QString& ) ) );
+
+ mAuthInfoLabel = createInfoLabel( i18n( "Check for supported security capabilities of %1..." ).arg( server ) );
+}
+
+void AccountWizard::popCapabilities( const QStringList &capaNormalList,
+ const QStringList &capaSSLList )
+{
+ uint capaNormal = popCapabilitiesFromStringList( capaNormalList );
+ uint capaTLS = 0;
+
+ if ( capaNormal & STLS )
+ capaTLS = capaNormal;
+
+ uint capaSSL = popCapabilitiesFromStringList( capaSSLList );
+
+ KMail::NetworkAccount *account = static_cast<KMail::NetworkAccount*>( mAccount );
+
+ bool useSSL = !capaSSLList.isEmpty();
+ bool useTLS = capaTLS != 0;
+
+ account->setUseSSL( useSSL );
+ account->setUseTLS( useTLS );
+
+ uint capa = (useSSL ? capaSSL : (useTLS ? capaTLS : capaNormal));
+
+ if ( capa & Plain )
+ account->setAuth( "PLAIN" );
+ else if ( capa & Login )
+ account->setAuth( "LOGIN" );
+ else if ( capa & CRAM_MD5 )
+ account->setAuth( "CRAM-MD5" );
+ else if ( capa & Digest_MD5 )
+ account->setAuth( "DIGEST-MD5" );
+ else if ( capa & NTLM )
+ account->setAuth( "NTLM" );
+ else if ( capa & GSSAPI )
+ account->setAuth( "GSSAPI" );
+ else if ( capa & APOP )
+ account->setAuth( "APOP" );
+ else
+ account->setAuth( "USER" );
+
+ account->setPort( useSSL ? 995 : 110 );
+
+ mServerTest->deleteLater();
+ mServerTest = 0;
+
+ delete mAuthInfoLabel;
+ mAuthInfoLabel = 0;
+
+ accountCreated();
+}
+
+
+void AccountWizard::imapCapabilities( const QStringList &capaNormalList,
+ const QStringList &capaSSLList )
+{
+ uint capaNormal = imapCapabilitiesFromStringList( capaNormalList );
+ uint capaTLS = 0;
+ if ( capaNormal & STARTTLS )
+ capaTLS = capaNormal;
+
+ uint capaSSL = imapCapabilitiesFromStringList( capaSSLList );
+
+ KMail::NetworkAccount *account = static_cast<KMail::NetworkAccount*>( mAccount );
+
+ bool useSSL = !capaSSLList.isEmpty();
+ bool useTLS = (capaTLS != 0);
+
+ account->setUseSSL( useSSL );
+ account->setUseTLS( useTLS );
+
+ uint capa = (useSSL ? capaSSL : (useTLS ? capaTLS : capaNormal));
+
+ if ( capa & CRAM_MD5 )
+ account->setAuth( "CRAM-MD5" );
+ else if ( capa & Digest_MD5 )
+ account->setAuth( "DIGEST-MD5" );
+ else if ( capa & NTLM )
+ account->setAuth( "NTLM" );
+ else if ( capa & GSSAPI )
+ account->setAuth( "GSSAPI" );
+ else if ( capa & Anonymous )
+ account->setAuth( "ANONYMOUS" );
+ else if ( capa & Login )
+ account->setAuth( "LOGIN" );
+ else if ( capa & Plain )
+ account->setAuth( "PLAIN" );
+ else
+ account->setAuth( "*" );
+
+ account->setPort( useSSL ? 993 : 143 );
+
+ mServerTest->deleteLater();
+ mServerTest = 0;
+
+ delete mAuthInfoLabel;
+ mAuthInfoLabel = 0;
+
+ accountCreated();
+}
+
+void AccountWizard::smtpCapabilities( const QStringList &capaNormal,
+ const QStringList &capaSSL,
+ const QString &authNone,
+ const QString &authSSL,
+ const QString &authTLS )
+{
+ uint authBitsNone, authBitsSSL, authBitsTLS;
+
+ if ( authNone.isEmpty() && authSSL.isEmpty() && authTLS.isEmpty() ) {
+ // slave doesn't seem to support "* AUTH METHODS" metadata (or server can't do AUTH)
+ authBitsNone = authMethodsFromStringList( capaNormal );
+ if ( capaNormal.findIndex( "STARTTLS" ) != -1 )
+ authBitsTLS = authBitsNone;
+ else
+ authBitsTLS = 0;
+ authBitsSSL = authMethodsFromStringList( capaSSL );
+ } else {
+ authBitsNone = authMethodsFromString( authNone );
+ authBitsSSL = authMethodsFromString( authSSL );
+ authBitsTLS = authMethodsFromString( authTLS );
+ }
+
+ uint authBits = 0;
+ if ( capaNormal.findIndex( "STARTTLS" ) != -1 ) {
+ mTransportInfo->encryption = "TLS";
+ authBits = authBitsTLS;
+ } else if ( !capaSSL.isEmpty() ) {
+ mTransportInfo->encryption = "SSL";
+ authBits = authBitsSSL;
+ } else {
+ mTransportInfo->encryption = "NONE";
+ authBits = authBitsNone;
+ }
+
+ if ( authBits & Login )
+ mTransportInfo->authType = "LOGIN";
+ else if ( authBits & CRAM_MD5 )
+ mTransportInfo->authType = "CRAM-MD5";
+ else if ( authBits & Digest_MD5 )
+ mTransportInfo->authType = "DIGEST-MD5";
+ else if ( authBits & NTLM )
+ mTransportInfo->authType = "NTLM";
+ else if ( authBits & GSSAPI )
+ mTransportInfo->authType = "GSSAPI";
+ else
+ mTransportInfo->authType = "PLAIN";
+
+ mTransportInfo->port = ( !capaSSL.isEmpty() ? "465" : "25" );
+
+ mServerTest->deleteLater();
+ mServerTest = 0;
+
+ delete mAuthInfoLabel;
+ mAuthInfoLabel = 0;
+
+ transportCreated();
+}
+
+uint AccountWizard::popCapabilitiesFromStringList( const QStringList & l )
+{
+ unsigned int capa = 0;
+
+ for ( QStringList::const_iterator it = l.begin() ; it != l.end() ; ++it ) {
+ QString cur = (*it).upper();
+ if ( cur == "PLAIN" )
+ capa |= Plain;
+ else if ( cur == "LOGIN" )
+ capa |= Login;
+ else if ( cur == "CRAM-MD5" )
+ capa |= CRAM_MD5;
+ else if ( cur == "DIGEST-MD5" )
+ capa |= Digest_MD5;
+ else if ( cur == "NTLM" )
+ capa |= NTLM;
+ else if ( cur == "GSSAPI" )
+ capa |= GSSAPI;
+ else if ( cur == "APOP" )
+ capa |= APOP;
+ else if ( cur == "STLS" )
+ capa |= STLS;
+ }
+
+ return capa;
+}
+
+uint AccountWizard::imapCapabilitiesFromStringList( const QStringList & l )
+{
+ unsigned int capa = 0;
+
+ for ( QStringList::const_iterator it = l.begin() ; it != l.end() ; ++it ) {
+ QString cur = (*it).upper();
+ if ( cur == "AUTH=PLAIN" )
+ capa |= Plain;
+ else if ( cur == "AUTH=LOGIN" )
+ capa |= Login;
+ else if ( cur == "AUTH=CRAM-MD5" )
+ capa |= CRAM_MD5;
+ else if ( cur == "AUTH=DIGEST-MD5" )
+ capa |= Digest_MD5;
+ else if ( cur == "AUTH=NTLM" )
+ capa |= NTLM;
+ else if ( cur == "AUTH=GSSAPI" )
+ capa |= GSSAPI;
+ else if ( cur == "AUTH=ANONYMOUS" )
+ capa |= Anonymous;
+ else if ( cur == "STARTTLS" )
+ capa |= STARTTLS;
+ }
+
+ return capa;
+}
+
+uint AccountWizard::authMethodsFromString( const QString & s )
+{
+ unsigned int result = 0;
+
+ QStringList sl = QStringList::split( '\n', s.upper() );
+ for ( QStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it )
+ if ( *it == "SASL/LOGIN" )
+ result |= Login;
+ else if ( *it == "SASL/PLAIN" )
+ result |= Plain;
+ else if ( *it == "SASL/CRAM-MD5" )
+ result |= CRAM_MD5;
+ else if ( *it == "SASL/DIGEST-MD5" )
+ result |= Digest_MD5;
+ else if ( *it == "SASL/NTLM" )
+ result |= NTLM;
+ else if ( *it == "SASL/GSSAPI" )
+ result |= GSSAPI;
+
+ return result;
+}
+
+uint AccountWizard::authMethodsFromStringList( const QStringList & sl )
+{
+ unsigned int result = 0;
+
+ for ( QStringList::const_iterator it = sl.begin() ; it != sl.end() ; ++it )
+ if ( *it == "LOGIN" )
+ result |= Login;
+ else if ( *it == "PLAIN" )
+ result |= Plain;
+ else if ( *it == "CRAM-MD5" )
+ result |= CRAM_MD5;
+ else if ( *it == "DIGEST-MD5" )
+ result |= Digest_MD5;
+ else if ( *it == "NTLM" )
+ result |= NTLM;
+ else if ( *it == "GSSAPI" )
+ result |= GSSAPI;
+
+ return result;
+}
+
+#include "accountwizard.moc"
diff --git a/kmail/accountwizard.h b/kmail/accountwizard.h
new file mode 100644
index 00000000..0dea0e44
--- /dev/null
+++ b/kmail/accountwizard.h
@@ -0,0 +1,138 @@
+/*******************************************************************************
+**
+** Filename : accountwizard.h
+** Created on : 07 February, 2005
+** Copyright : (c) 2005 Tobias Koenig
+** Email : tokoe@kde.org
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** In addition, as a special exception, the copyright holders give
+** permission to link the code of this program with any edition of
+** the Qt library by Trolltech AS, Norway (or with modified versions
+** of Qt that use the same license as Qt), and distribute linked
+** combinations including the two. You must obey the GNU General
+** Public License in all respects for all of the code used other than
+** Qt. If you modify this file, you may extend this exception to
+** your version of the file, but you are not obligated to do so. If
+** you do not wish to do so, delete this exception statement from
+** your version.
+*******************************************************************************/
+
+#ifndef KMWIZARD_H
+#define KMWIZARD_H
+
+#include <kwizard.h>
+
+class KLineEdit;
+class QCheckBox;
+class QLabel;
+class QPushButton;
+
+class KMAccount;
+class KMKernel;
+class KMServerTest;
+class AccountTypeBox;
+class KMTransportInfo;
+
+class AccountWizard : public KWizard
+{
+ Q_OBJECT
+
+ public:
+ /**
+ Starts the wizard. The wizard is only shown when it has not be
+ run successfully before.
+
+ @param kernel The mail kernel the wizard should work on.
+ @param parent The parent widget of the dialog.
+ */
+ static void start( KMKernel *kernel, QWidget *parent = 0 );
+
+ /**
+ Reimplemented
+ */
+ void showPage( QWidget *page );
+
+ protected:
+ AccountWizard( KMKernel *kernel, QWidget *parent );
+ ~AccountWizard() {};
+
+ void setupWelcomePage();
+ void setupAccountTypePage();
+ void setupAccountInformationPage();
+ void setupLoginInformationPage();
+ void setupServerInformationPage();
+
+ protected slots:
+ void chooseLocation();
+ virtual void accept();
+ void createTransport();
+ void transportCreated();
+ void createAccount();
+ void accountCreated();
+ void finished();
+
+ private slots:
+ void popCapabilities( const QStringList&, const QStringList& );
+ void imapCapabilities( const QStringList&, const QStringList& );
+ void smtpCapabilities( const QStringList&, const QStringList&,
+ const QString&, const QString&, const QString& );
+
+ private:
+ QString accountName() const;
+ QLabel *createInfoLabel( const QString &msg );
+
+ void checkPopCapabilities( const QString&, int );
+ void checkImapCapabilities( const QString&, int );
+ void checkSmtpCapabilities( const QString&, int );
+ uint popCapabilitiesFromStringList( const QStringList& );
+ uint imapCapabilitiesFromStringList( const QStringList& );
+ uint authMethodsFromString( const QString& );
+ uint authMethodsFromStringList( const QStringList& );
+
+ QWidget *mWelcomePage;
+
+ QWidget *mAccountTypePage;
+ AccountTypeBox *mTypeBox;
+
+ QWidget *mAccountInformationPage;
+ KLineEdit *mRealName;
+ KLineEdit *mEMailAddress;
+ KLineEdit *mOrganization;
+
+ QWidget *mLoginInformationPage;
+ KLineEdit *mLoginName;
+ KLineEdit *mPassword;
+
+ QWidget *mServerInformationPage;
+ QLabel *mIncomingLabel;
+ KLineEdit *mIncomingServer;
+ QCheckBox *mIncomingUseSSL;
+ KLineEdit *mIncomingLocation;
+
+ QPushButton *mChooseLocation;
+ KLineEdit *mOutgoingServer;
+ QCheckBox *mOutgoingUseSSL;
+ QCheckBox *mLocalDelivery;
+
+ QWidget *mIncomingServerWdg;
+ QWidget *mIncomingLocationWdg;
+
+ QLabel *mAuthInfoLabel;
+
+ KMKernel *mKernel;
+ KMAccount *mAccount;
+ KMTransportInfo *mTransportInfo;
+ QPtrList<KMTransportInfo> mTransportInfoList;
+ KMServerTest *mServerTest;
+};
+
+#endif
diff --git a/kmail/acljobs.cpp b/kmail/acljobs.cpp
new file mode 100644
index 00000000..568a6f4b
--- /dev/null
+++ b/kmail/acljobs.cpp
@@ -0,0 +1,261 @@
+/**
+ * acljobs.cpp
+ *
+ * Copyright (c) 2004 David Faure <faure@kde.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+#include "acljobs.h"
+#include <kio/scheduler.h>
+#include <kdebug.h>
+
+using namespace KMail;
+
+// Convert str to an ACLPermissions value.
+// url and user are there only for the error message
+static unsigned int IMAPRightsToPermission( const QString& str, const KURL& url, const QString& user ) {
+ unsigned int perm = 0;
+ uint len = str.length();
+ for (uint i = 0; i < len; ++i) {
+ QChar ch = str[i];
+ switch ( ch.latin1() ) {
+ case 'l': perm |= ACLJobs::List; break;
+ case 'r': perm |= ACLJobs::Read; break;
+ case 's': perm |= ACLJobs::WriteSeenFlag; break;
+ case 'w': perm |= ACLJobs::WriteFlags; break;
+ case 'i': perm |= ACLJobs::Insert; break;
+ case 'p': perm |= ACLJobs::Post; break;
+ case 'c': perm |= ACLJobs::Create; break;
+ case 'd': perm |= ACLJobs::Delete; break;
+ case 'a': perm |= ACLJobs::Administer; break;
+ default: break;
+ }
+ }
+ if ( ( perm & ACLJobs::Read ) && !( perm & ACLJobs::WriteSeenFlag ) ) {
+ // Reading without 'seen' is, well, annoying. Unusable, even.
+ // So we treat 'rs' as a single one.
+ // But if the permissions were set out of kmail, better check that both are set
+ kdWarning(5006) << "IMAPRightsToPermission: found read (r) but not seen (s). Things will not work well for folder " << url << " and user " << ( user.isEmpty() ? "myself" : user ) << endl;
+ if ( perm & ACLJobs::Administer )
+ kdWarning(5006) << "You can change this yourself in the ACL dialog" << endl;
+ else
+ kdWarning(5006) << "Ask your admin for 's' permissions." << endl;
+ // Is the above correct enough to be turned into a KMessageBox?
+ }
+
+ return perm;
+}
+
+static QCString permissionsToIMAPRights( unsigned int permissions ) {
+ QCString str = "";
+ if ( permissions & ACLJobs::List )
+ str += 'l';
+ if ( permissions & ACLJobs::Read )
+ str += 'r';
+ if ( permissions & ACLJobs::WriteSeenFlag )
+ str += 's';
+ if ( permissions & ACLJobs::WriteFlags )
+ str += 'w';
+ if ( permissions & ACLJobs::Insert )
+ str += 'i';
+ if ( permissions & ACLJobs::Post )
+ str += 'p';
+ if ( permissions & ACLJobs::Create )
+ str += 'c';
+ if ( permissions & ACLJobs::Delete )
+ str += 'd';
+ if ( permissions & ACLJobs::Administer )
+ str += 'a';
+ return str;
+}
+
+#ifndef NDEBUG
+QString ACLJobs::permissionsToString( unsigned int permissions )
+{
+ QString str;
+ if ( permissions & ACLJobs::List )
+ str += "List ";
+ if ( permissions & ACLJobs::Read )
+ str += "Read ";
+ if ( permissions & ACLJobs::WriteFlags )
+ str += "Write ";
+ if ( permissions & ACLJobs::Insert )
+ str += "Insert ";
+ if ( permissions & ACLJobs::Post )
+ str += "Post ";
+ if ( permissions & ACLJobs::Create )
+ str += "Create ";
+ if ( permissions & ACLJobs::Delete )
+ str += "Delete ";
+ if ( permissions & ACLJobs::Administer )
+ str += "Administer ";
+ if ( !str.isEmpty() )
+ str.truncate( str.length() - 1 );
+ return str;
+}
+#endif
+
+KIO::SimpleJob* ACLJobs::setACL( KIO::Slave* slave, const KURL& url, const QString& user, unsigned int permissions )
+{
+ QString perm = QString::fromLatin1( permissionsToIMAPRights( permissions ) );
+
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)'A' << (int)'S' << url << user << perm;
+
+ KIO::SimpleJob* job = KIO::special( url, packedArgs, false );
+ KIO::Scheduler::assignJobToSlave( slave, job );
+ return job;
+}
+
+ACLJobs::DeleteACLJob* ACLJobs::deleteACL( KIO::Slave* slave, const KURL& url, const QString& user )
+{
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)'A' << (int)'D' << url << user;
+
+ ACLJobs::DeleteACLJob* job = new ACLJobs::DeleteACLJob( url, user, packedArgs, false );
+ KIO::Scheduler::assignJobToSlave( slave, job );
+ return job;
+}
+
+ACLJobs::GetACLJob* ACLJobs::getACL( KIO::Slave* slave, const KURL& url )
+{
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)'A' << (int)'G' << url;
+
+ ACLJobs::GetACLJob* job = new ACLJobs::GetACLJob( url, packedArgs, false );
+ KIO::Scheduler::assignJobToSlave( slave, job );
+ return job;
+}
+
+ACLJobs::GetUserRightsJob* ACLJobs::getUserRights( KIO::Slave* slave, const KURL& url )
+{
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)'A' << (int)'M' << url;
+
+ ACLJobs::GetUserRightsJob* job = new ACLJobs::GetUserRightsJob( url, packedArgs, false );
+ KIO::Scheduler::assignJobToSlave( slave, job );
+ return job;
+}
+
+ACLJobs::GetACLJob::GetACLJob( const KURL& url, const QByteArray &packedArgs,
+ bool showProgressInfo )
+ : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo )
+{
+ connect( this, SIGNAL(infoMessage(KIO::Job*,const QString&)),
+ SLOT(slotInfoMessage(KIO::Job*,const QString&)) );
+}
+
+void ACLJobs::GetACLJob::slotInfoMessage( KIO::Job*, const QString& str )
+{
+ // Parse the result
+ QStringList lst = QStringList::split( "\"", str, true );
+ while ( lst.count() >= 2 ) // we take items 2 by 2
+ {
+ QString user = lst.front(); lst.pop_front();
+ QString imapRights = lst.front(); lst.pop_front();
+ unsigned int perm = IMAPRightsToPermission( imapRights, url(), user );
+ m_entries.append( ACLListEntry( user, imapRights, perm ) );
+ }
+}
+
+ACLJobs::GetUserRightsJob::GetUserRightsJob( const KURL& url, const QByteArray &packedArgs,
+ bool showProgressInfo )
+ : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo )
+{
+ connect( this, SIGNAL(infoMessage(KIO::Job*,const QString&)),
+ SLOT(slotInfoMessage(KIO::Job*,const QString&)) );
+}
+
+void ACLJobs::GetUserRightsJob::slotInfoMessage( KIO::Job*, const QString& str )
+{
+ // Parse the result
+ m_permissions = IMAPRightsToPermission( str, url(), QString::null );
+}
+
+ACLJobs::DeleteACLJob::DeleteACLJob( const KURL& url, const QString& userId,
+ const QByteArray &packedArgs,
+ bool showProgressInfo )
+ : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ),
+ mUserId( userId )
+{
+}
+
+////
+
+ACLJobs::MultiSetACLJob::MultiSetACLJob( KIO::Slave* slave, const KURL& url, const ACLList& acl, bool showProgressInfo )
+ : KIO::Job( showProgressInfo ),
+ mSlave( slave ),
+ mUrl( url ), mACLList( acl ), mACLListIterator( mACLList.begin() )
+{
+ QTimer::singleShot(0, this, SLOT(slotStart()));
+}
+
+void ACLJobs::MultiSetACLJob::slotStart()
+{
+ // Skip over unchanged entries
+ while ( mACLListIterator != mACLList.end() && !(*mACLListIterator).changed )
+ ++mACLListIterator;
+
+ if ( mACLListIterator != mACLList.end() )
+ {
+ const ACLListEntry& entry = *mACLListIterator;
+ KIO::Job* job = 0;
+ if ( entry.permissions > -1 )
+ job = setACL( mSlave, mUrl, entry.userId, entry.permissions );
+ else
+ job = deleteACL( mSlave, mUrl, entry.userId );
+
+ addSubjob( job );
+ } else { // done!
+ emitResult();
+ }
+}
+
+void ACLJobs::MultiSetACLJob::slotResult( KIO::Job *job )
+{
+ if ( job->error() ) {
+ KIO::Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ subjobs.remove(job);
+ const ACLListEntry& entry = *mACLListIterator;
+ emit aclChanged( entry.userId, entry.permissions );
+
+ // Move on to next one
+ ++mACLListIterator;
+ slotStart();
+}
+
+ACLJobs::MultiSetACLJob* ACLJobs::multiSetACL( KIO::Slave* slave, const KURL& url, const ACLList& acl )
+{
+ return new MultiSetACLJob( slave, url, acl, false /*showProgressInfo*/ );
+}
+
+#include "acljobs.moc"
diff --git a/kmail/acljobs.h b/kmail/acljobs.h
new file mode 100644
index 00000000..0d4a731d
--- /dev/null
+++ b/kmail/acljobs.h
@@ -0,0 +1,177 @@
+/*
+ * acljobs.h
+ *
+ * Copyright (c) 2004 David Faure <faure@kde.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+
+#ifndef KMACLJOBS_H
+#define KMACLJOBS_H
+
+#include <kio/job.h>
+#include <qvaluevector.h>
+
+namespace KMail {
+
+ /// One entry in the ACL list: user and permissions
+ struct ACLListEntry {
+ ACLListEntry() {} // for QValueVector
+ ACLListEntry( const QString& u, const QString& irl, int p )
+ : userId( u ), internalRightsList( irl ), permissions( p ), changed( false ) {}
+ QString userId;
+ QString internalRightsList; ///< protocol-dependent string (e.g. IMAP rights list)
+ int permissions; ///< based on the ACLPermissions enum
+ bool changed; ///< special flag for KMFolderCachedImap
+ };
+
+ typedef QValueVector<ACLListEntry> ACLList;
+
+/**
+ * This namespace contains functions that return jobs for ACL operations.
+ *
+ * The current implementation is tied to IMAP.
+ * If someone wants to extend this to other protocols, turn the class into a namespace
+ * and use virtual methods.
+ */
+namespace ACLJobs {
+
+ /// Bitfield modelling the possible permissions.
+ /// This is modelled after the imap4 permissions except that Read is "rs".
+ /// The semantics of the bits is protocol-dependent.
+ enum ACLPermissions {
+ List = 1,
+ Read = 2,
+ WriteFlags = 4,
+ Insert = 8,
+ Create = 16,
+ Delete = 32,
+ Administer = 64,
+ Post = 128,
+ WriteSeenFlag = 256,
+ // alias for "all read/write permissions except admin"
+ AllWrite = List | Read | WriteFlags | Insert | Post | Create | Delete | WriteSeenFlag,
+ // alias for "all permissions"
+ All = List | Read | WriteFlags | Insert | Post | Create | Delete | Administer | WriteSeenFlag
+ };
+ /// Set the permissions for a given user on a given url
+ KIO::SimpleJob* setACL( KIO::Slave* slave, const KURL& url, const QString& user, unsigned int permissions );
+
+ class DeleteACLJob;
+ /// Delete the permissions for a given user on a given url
+ DeleteACLJob* deleteACL( KIO::Slave* slave, const KURL& url, const QString& user );
+
+ class GetACLJob;
+ /// List all ACLs for a given url
+ GetACLJob* getACL( KIO::Slave* slave, const KURL& url );
+
+ class GetUserRightsJob;
+ /// Get the users' rights for a given url
+ GetUserRightsJob* getUserRights( KIO::Slave* slave, const KURL& url );
+
+ class MultiSetACLJob;
+ /// Set and delete a list of permissions for different users on a given url
+ MultiSetACLJob* multiSetACL( KIO::Slave* slave, const KURL& url, const ACLList& acl );
+
+ /// List all ACLs for a given url
+ class GetACLJob : public KIO::SimpleJob
+ {
+ Q_OBJECT
+ public:
+ GetACLJob( const KURL& url, const QByteArray &packedArgs,
+ bool showProgressInfo );
+
+ const ACLList& entries() const { return m_entries; }
+
+ protected slots:
+ void slotInfoMessage( KIO::Job*, const QString& );
+ private:
+ ACLList m_entries;
+ };
+
+ /// Get the users' rights for a given url
+ class GetUserRightsJob : public KIO::SimpleJob
+ {
+ Q_OBJECT
+ public:
+ GetUserRightsJob( const KURL& url, const QByteArray &packedArgs,
+ bool showProgressInfo );
+ unsigned int permissions() const { return m_permissions; }
+
+ protected slots:
+ void slotInfoMessage( KIO::Job*, const QString& );
+ private:
+ unsigned int m_permissions;
+ };
+
+ /// Delete the permissions for a given user on a given url
+ /// This class only exists to store the userid in the job
+ class DeleteACLJob : public KIO::SimpleJob
+ {
+ Q_OBJECT
+ public:
+ DeleteACLJob( const KURL& url, const QString& userId,
+ const QByteArray &packedArgs,
+ bool showProgressInfo );
+
+ QString userId() const { return mUserId; }
+
+ private:
+ QString mUserId;
+ };
+
+ /// Set and delete a list of permissions for different users on a given url
+ class MultiSetACLJob : public KIO::Job {
+ Q_OBJECT
+
+ public:
+ MultiSetACLJob( KIO::Slave* slave, const KURL& url, const ACLList& acl, bool showProgressInfo );
+
+ signals:
+ // Emitted when a given user's permissions were successfully changed.
+ // This allows the caller to keep track of what exactly was done (and handle errors better)
+ void aclChanged( const QString& userId, int permissions );
+
+ protected slots:
+ virtual void slotStart();
+ virtual void slotResult( KIO::Job *job );
+
+ private:
+ KIO::Slave* mSlave;
+ const KURL mUrl;
+ const ACLList mACLList;
+ ACLList::const_iterator mACLListIterator;
+ };
+
+
+#ifndef NDEBUG
+ QString permissionsToString( unsigned int permissions );
+#endif
+}
+
+} // namespace
+
+#endif /* KMACLJOBS_H */
diff --git a/kmail/actionscheduler.cpp b/kmail/actionscheduler.cpp
new file mode 100644
index 00000000..3d92cd7a
--- /dev/null
+++ b/kmail/actionscheduler.cpp
@@ -0,0 +1,836 @@
+/* Action Scheduler
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) Don Sanders <sanders@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#include <kdebug.h> // FIXME
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "actionscheduler.h"
+
+#include "filterlog.h"
+#include "messageproperty.h"
+#include "kmfilter.h"
+#include "kmfolderindex.h"
+#include "kmfoldermgr.h"
+#include "kmmsgdict.h"
+#include "kmcommands.h"
+#include "kmheaders.h"
+#include "accountmanager.h"
+using KMail::AccountManager;
+
+#include <qtimer.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+
+using namespace KMail;
+typedef QPtrList<KMMsgBase> KMMessageList;
+
+
+KMFolderMgr* ActionScheduler::tempFolderMgr = 0;
+int ActionScheduler::refCount = 0;
+int ActionScheduler::count = 0;
+QValueList<ActionScheduler*> *ActionScheduler::schedulerList = 0;
+bool ActionScheduler::sEnabled = false;
+bool ActionScheduler::sEnabledChecked = false;
+
+ActionScheduler::ActionScheduler(KMFilterMgr::FilterSet set,
+ QValueList<KMFilter*> filters,
+ KMHeaders *headers,
+ KMFolder *srcFolder)
+ :mSet( set ), mHeaders( headers )
+{
+ ++count;
+ ++refCount;
+ mExecuting = false;
+ mExecutingLock = false;
+ mFetchExecuting = false;
+ mFiltersAreQueued = false;
+ mResult = ResultOk;
+ mIgnore = false;
+ mAutoDestruct = false;
+ mAlwaysMatch = false;
+ mAccountId = 0;
+ mAccount = false;
+ lastCommand = 0;
+ lastJob = 0;
+ finishTimer = new QTimer( this, "finishTimer" );
+ connect( finishTimer, SIGNAL(timeout()), this, SLOT(finish()));
+ fetchMessageTimer = new QTimer( this, "fetchMessageTimer" );
+ connect( fetchMessageTimer, SIGNAL(timeout()), this, SLOT(fetchMessage()));
+ tempCloseFoldersTimer = new QTimer( this, "tempCloseFoldersTimer" );
+ connect( tempCloseFoldersTimer, SIGNAL(timeout()), this, SLOT(tempCloseFolders()));
+ processMessageTimer = new QTimer( this, "processMessageTimer" );
+ connect( processMessageTimer, SIGNAL(timeout()), this, SLOT(processMessage()));
+ filterMessageTimer = new QTimer( this, "filterMessageTimer" );
+ connect( filterMessageTimer, SIGNAL(timeout()), this, SLOT(filterMessage()));
+ timeOutTimer = new QTimer( this, "timeOutTimer" );
+ connect( timeOutTimer, SIGNAL(timeout()), this, SLOT(timeOut()));
+ fetchTimeOutTimer = new QTimer( this, "fetchTimeOutTimer" );
+ connect( fetchTimeOutTimer, SIGNAL(timeout()), this, SLOT(fetchTimeOut()));
+
+ QValueList<KMFilter*>::Iterator it = filters.begin();
+ for (; it != filters.end(); ++it)
+ mFilters.append( **it );
+ mDestFolder = 0;
+ if (srcFolder) {
+ mDeleteSrcFolder = false;
+ setSourceFolder( srcFolder );
+ } else {
+ QString tmpName;
+ tmpName.setNum( count );
+ if (!tempFolderMgr)
+ tempFolderMgr = new KMFolderMgr(locateLocal("data","kmail/filter"));
+ KMFolder *tempFolder = tempFolderMgr->findOrCreate( tmpName );
+ tempFolder->expunge();
+ mDeleteSrcFolder = true;
+ setSourceFolder( tempFolder );
+ }
+ if (!schedulerList)
+ schedulerList = new QValueList<ActionScheduler*>;
+ schedulerList->append( this );
+}
+
+ActionScheduler::~ActionScheduler()
+{
+ schedulerList->remove( this );
+ tempCloseFolders();
+ disconnect( mSrcFolder, SIGNAL(closed()),
+ this, SLOT(folderClosedOrExpunged()) );
+ disconnect( mSrcFolder, SIGNAL(expunged(KMFolder*)),
+ this, SLOT(folderClosedOrExpunged()) );
+ mSrcFolder->close("actionschedsrc");
+
+ if (mDeleteSrcFolder)
+ tempFolderMgr->remove(mSrcFolder);
+
+ --refCount;
+ if (refCount == 0) {
+ delete tempFolderMgr;
+ tempFolderMgr = 0;
+ }
+}
+
+void ActionScheduler::setAutoDestruct( bool autoDestruct )
+{
+ mAutoDestruct = autoDestruct;
+}
+
+void ActionScheduler::setAlwaysMatch( bool alwaysMatch )
+{
+ mAlwaysMatch = alwaysMatch;
+}
+
+void ActionScheduler::setDefaultDestinationFolder( KMFolder *destFolder )
+{
+ mDestFolder = destFolder;
+}
+
+void ActionScheduler::setSourceFolder( KMFolder *srcFolder )
+{
+ srcFolder->open("actionschedsrc");
+ if (mSrcFolder) {
+ disconnect( mSrcFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
+ this, SLOT(msgAdded(KMFolder*, Q_UINT32)) );
+ disconnect( mSrcFolder, SIGNAL(closed()),
+ this, SLOT(folderClosedOrExpunged()) );
+ disconnect( mSrcFolder, SIGNAL(expunged(KMFolder*)),
+ this, SLOT(folderClosedOrExpunged()) );
+ mSrcFolder->close("actionschedsrc");
+ }
+ mSrcFolder = srcFolder;
+ int i = 0;
+ for (i = 0; i < mSrcFolder->count(); ++i)
+ enqueue( mSrcFolder->getMsgBase( i )->getMsgSerNum() );
+ if (mSrcFolder) {
+ connect( mSrcFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
+ this, SLOT(msgAdded(KMFolder*, Q_UINT32)) );
+ connect( mSrcFolder, SIGNAL(closed()),
+ this, SLOT(folderClosedOrExpunged()) );
+ connect( mSrcFolder, SIGNAL(expunged(KMFolder*)),
+ this, SLOT(folderClosedOrExpunged()) );
+ }
+}
+
+void ActionScheduler::setFilterList( QValueList<KMFilter*> filters )
+{
+ mFiltersAreQueued = true;
+ mQueuedFilters.clear();
+
+ QValueList<KMFilter*>::Iterator it = filters.begin();
+ for (; it != filters.end(); ++it)
+ mQueuedFilters.append( **it );
+ if (!mExecuting) {
+ mFilters = mQueuedFilters;
+ mFiltersAreQueued = false;
+ mQueuedFilters.clear();
+ }
+}
+
+void ActionScheduler::folderClosedOrExpunged()
+{
+ // mSrcFolder has been closed. reopen it.
+ if ( mSrcFolder )
+ {
+ mSrcFolder->open( "actionsched" );
+ }
+}
+
+int ActionScheduler::tempOpenFolder( KMFolder* aFolder )
+{
+ assert( aFolder );
+ tempCloseFoldersTimer->stop();
+ if ( aFolder == mSrcFolder.operator->() )
+ return 0;
+
+ int rc = aFolder->open("actionsched");
+ if (rc)
+ return rc;
+
+ mOpenFolders.append( aFolder );
+ return 0;
+}
+
+void ActionScheduler::tempCloseFolders()
+{
+ // close temp opened folders
+ QValueListConstIterator<QGuardedPtr<KMFolder> > it;
+ for (it = mOpenFolders.begin(); it != mOpenFolders.end(); ++it) {
+ KMFolder *folder = *it;
+ if (folder)
+ folder->close("actionsched");
+ }
+ mOpenFolders.clear();
+}
+
+void ActionScheduler::execFilters(const QValueList<Q_UINT32> serNums)
+{
+ QValueListConstIterator<Q_UINT32> it;
+ for (it = serNums.begin(); it != serNums.end(); ++it)
+ execFilters( *it );
+}
+
+void ActionScheduler::execFilters(const QPtrList<KMMsgBase> msgList)
+{
+ KMMsgBase *msgBase;
+ QPtrList<KMMsgBase> list = msgList;
+ for (msgBase = list.first(); msgBase; msgBase = list.next())
+ execFilters( msgBase->getMsgSerNum() );
+}
+
+void ActionScheduler::execFilters(KMMsgBase* msgBase)
+{
+ execFilters( msgBase->getMsgSerNum() );
+}
+
+void ActionScheduler::execFilters(Q_UINT32 serNum)
+{
+ if (mResult != ResultOk) {
+ if ((mResult != ResultCriticalError) &&
+ !mExecuting && !mExecutingLock && !mFetchExecuting) {
+ mResult = ResultOk; // Recoverable error
+ if (!mFetchSerNums.isEmpty()) {
+ mFetchSerNums.push_back( mFetchSerNums.first() );
+ mFetchSerNums.pop_front();
+ }
+ } else
+ return; // An error has already occurred don't even try to process this msg
+ }
+ if (MessageProperty::filtering( serNum )) {
+ // Not good someone else is already filtering this msg
+ mResult = ResultError;
+ if (!mExecuting && !mFetchExecuting)
+ finishTimer->start( 0, true );
+ } else {
+ // Everything is ok async fetch this message
+ mFetchSerNums.append( serNum );
+ if (!mFetchExecuting) {
+ //Need to (re)start incomplete msg fetching chain
+ mFetchExecuting = true;
+ fetchMessageTimer->start( 0, true );
+ }
+ }
+}
+
+KMMsgBase *ActionScheduler::messageBase(Q_UINT32 serNum)
+{
+ int idx = -1;
+ KMFolder *folder = 0;
+ KMMsgBase *msg = 0;
+ KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
+ // It's possible that the message has been deleted or moved into a
+ // different folder
+ if (folder && (idx != -1)) {
+ // everything is ok
+ tempOpenFolder( folder ); // just in case msg has moved
+ msg = folder->getMsgBase( idx );
+ } else {
+ // the message is gone!
+ mResult = ResultError;
+ finishTimer->start( 0, true );
+ }
+ return msg;
+}
+
+KMMessage *ActionScheduler::message(Q_UINT32 serNum)
+{
+ int idx = -1;
+ KMFolder *folder = 0;
+ KMMessage *msg = 0;
+ KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
+ // It's possible that the message has been deleted or moved into a
+ // different folder
+ if (folder && (idx != -1)) {
+ // everything is ok
+ msg = folder->getMsg( idx );
+ tempOpenFolder( folder ); // just in case msg has moved
+ } else {
+ // the message is gone!
+ mResult = ResultError;
+ finishTimer->start( 0, true );
+ }
+ return msg;
+}
+
+void ActionScheduler::finish()
+{
+ if (mResult != ResultOk) {
+ // Must handle errors immediately
+ emit result( mResult );
+ return;
+ }
+
+ if (!mExecuting) {
+
+ if (!mFetchSerNums.isEmpty()) {
+ // Possibly if (mResult == ResultOk) should cancel job and start again.
+ // Believe smarter logic to bail out if an error has occurred is required.
+ // Perhaps should be testing for mFetchExecuting or at least set it to true
+ fetchMessageTimer->start( 0, true ); // give it a bit of time at a test
+ return;
+ } else {
+ mFetchExecuting = false;
+ }
+
+ if (mSerNums.begin() != mSerNums.end()) {
+ mExecuting = true;
+ processMessageTimer->start( 0, true );
+ return;
+ }
+
+ // If an error has occurred and a permanent source folder has
+ // been set then move all the messages left in the source folder
+ // to the inbox. If no permanent source folder has been set
+ // then abandon filtering of queued messages.
+ if (!mDeleteSrcFolder && !mDestFolder.isNull() ) {
+ while ( mSrcFolder->count() > 0 ) {
+ KMMessage *msg = mSrcFolder->getMsg( 0 );
+ mDestFolder->moveMsg( msg );
+ }
+
+ // Wait a little while before closing temp folders, just in case
+ // new messages arrive for filtering.
+ tempCloseFoldersTimer->start( 60*1000, true );
+ }
+ mSerNums.clear(); //abandon
+ mFetchSerNums.clear(); //abandon
+
+ if (mFiltersAreQueued)
+ mFilters = mQueuedFilters;
+ mQueuedFilters.clear();
+ mFiltersAreQueued = false;
+ ReturnCode aResult = mResult;
+ mResult = ResultOk;
+ mExecutingLock = false;
+ emit result( aResult );
+ if (mAutoDestruct)
+ delete this;
+ }
+ // else a message may be in the process of being fetched or filtered
+ // wait until both of these commitments are finished then this
+ // method should be called again.
+}
+
+void ActionScheduler::fetchMessage()
+{
+ QValueListIterator<Q_UINT32> mFetchMessageIt = mFetchSerNums.begin();
+ while (mFetchMessageIt != mFetchSerNums.end()) {
+ if (!MessageProperty::transferInProgress(*mFetchMessageIt))
+ break;
+ ++mFetchMessageIt;
+ }
+
+ // Note: Perhaps this could be improved. We shouldn't give up straight away
+ // if !mFetchSerNums.isEmpty (becausing transferInProgress is true
+ // for some messages). Instead we should delay for a minute or so and
+ // again.
+ if (mFetchMessageIt == mFetchSerNums.end() && !mFetchSerNums.isEmpty()) {
+ mResult = ResultError;
+ }
+ if ((mFetchMessageIt == mFetchSerNums.end()) || (mResult != ResultOk)) {
+ mFetchExecuting = false;
+ if (!mSrcFolder->count())
+ mSrcFolder->expunge();
+ finishTimer->start( 0, true );
+ return;
+ }
+
+ //If we got this far then there's a valid message to work with
+ KMMsgBase *msgBase = messageBase( *mFetchMessageIt );
+
+ if ((mResult != ResultOk) || (!msgBase)) {
+ mFetchExecuting = false;
+ return;
+ }
+ mFetchUnget = msgBase->isMessage();
+ KMMessage *msg = message( *mFetchMessageIt );
+ if (mResult != ResultOk) {
+ mFetchExecuting = false;
+ return;
+ }
+
+ if (msg && msg->isComplete()) {
+ messageFetched( msg );
+ } else if (msg) {
+ fetchTimeOutTime = QTime::currentTime();
+ fetchTimeOutTimer->start( 60 * 1000, true );
+ FolderJob *job = msg->parent()->createJob( msg );
+ connect( job, SIGNAL(messageRetrieved( KMMessage* )),
+ SLOT(messageFetched( KMMessage* )) );
+ lastJob = job;
+ job->start();
+ } else {
+ mFetchExecuting = false;
+ mResult = ResultError;
+ finishTimer->start( 0, true );
+ return;
+ }
+}
+
+void ActionScheduler::messageFetched( KMMessage *msg )
+{
+ fetchTimeOutTimer->stop();
+ if (!msg) {
+ // Should never happen, but sometimes does;
+ fetchMessageTimer->start( 0, true );
+ return;
+ }
+
+ mFetchSerNums.remove( msg->getMsgSerNum() );
+
+ // Note: This may not be necessary. What about when it's time to
+ // delete the original message?
+ // Is the new serial number being set correctly then?
+ if ((mSet & KMFilterMgr::Explicit) ||
+ (msg->headerField( "X-KMail-Filtered" ).isEmpty())) {
+ QString serNumS;
+ serNumS.setNum( msg->getMsgSerNum() );
+ KMMessage *newMsg = new KMMessage;
+ newMsg->fromString(msg->asString());
+ newMsg->setStatus(msg->status());
+ newMsg->setComplete(msg->isComplete());
+ newMsg->setHeaderField( "X-KMail-Filtered", serNumS );
+ mSrcFolder->addMsg( newMsg );
+ } else {
+ fetchMessageTimer->start( 0, true );
+ }
+ if (mFetchUnget && msg->parent())
+ msg->parent()->unGetMsg( msg->parent()->find( msg ));
+ return;
+}
+
+void ActionScheduler::msgAdded( KMFolder*, Q_UINT32 serNum )
+{
+ if (!mIgnore)
+ enqueue( serNum );
+}
+
+void ActionScheduler::enqueue(Q_UINT32 serNum)
+{
+ if (mResult != ResultOk)
+ return; // An error has already occurred don't even try to process this msg
+
+ if (MessageProperty::filtering( serNum )) {
+ // Not good someone else is already filtering this msg
+ mResult = ResultError;
+ if (!mExecuting && !mFetchExecuting)
+ finishTimer->start( 0, true );
+ } else {
+ // Everything is ok async filter this message
+ mSerNums.append( serNum );
+
+ if (!mExecuting) {
+ // Note: Need to (re)start incomplete msg filtering chain
+ // The state of mFetchExecuting is of some concern.
+ mExecuting = true;
+ mMessageIt = mSerNums.begin();
+ processMessageTimer->start( 0, true );
+ }
+ }
+}
+
+void ActionScheduler::processMessage()
+{
+ if (mExecutingLock)
+ return;
+ mExecutingLock = true;
+ mMessageIt = mSerNums.begin();
+ while (mMessageIt != mSerNums.end()) {
+ if (!MessageProperty::transferInProgress(*mMessageIt))
+ break;
+ ++mMessageIt;
+ }
+
+ if (mMessageIt == mSerNums.end() && !mSerNums.isEmpty()) {
+ mExecuting = false;
+ processMessageTimer->start( 600, true );
+ }
+
+ if ((mMessageIt == mSerNums.end()) || (mResult != ResultOk)) {
+ mExecutingLock = false;
+ mExecuting = false;
+ finishTimer->start( 0, true );
+ return;
+ }
+
+ //If we got this far then there's a valid message to work with
+ KMMsgBase *msgBase = messageBase( *mMessageIt );
+ if (!msgBase || mResult != ResultOk) {
+ mExecuting = false;
+ return;
+ }
+
+ MessageProperty::setFiltering( *mMessageIt, true );
+ MessageProperty::setFilterHandler( *mMessageIt, this );
+ MessageProperty::setFilterFolder( *mMessageIt, mDestFolder );
+ if ( FilterLog::instance()->isLogging() ) {
+ FilterLog::instance()->addSeparator();
+ }
+ mFilterIt = mFilters.begin();
+
+ mUnget = msgBase->isMessage();
+ KMMessage *msg = message( *mMessageIt );
+ if (mResult != ResultOk) {
+ mExecuting = false;
+ return;
+ }
+
+ bool mdnEnabled = true;
+ {
+ KConfigGroup mdnConfig( kmkernel->config(), "MDN" );
+ int mode = mdnConfig.readNumEntry( "default-policy", 0 );
+ if (!mode || mode < 0 || mode > 3)
+ mdnEnabled = false;
+ }
+ mdnEnabled = true; // For 3.2 force all mails to be complete
+
+ if ((msg && msg->isComplete()) ||
+ (msg && !(*mFilterIt).requiresBody(msg) && !mdnEnabled))
+ {
+ // We have a complete message or
+ // we can work with an incomplete message
+ // Get a write lock on the message while it's being filtered
+ msg->setTransferInProgress( true );
+ filterMessageTimer->start( 0, true );
+ return;
+ }
+ if (msg) {
+ FolderJob *job = msg->parent()->createJob( msg );
+ connect( job, SIGNAL(messageRetrieved( KMMessage* )),
+ SLOT(messageRetrieved( KMMessage* )) );
+ job->start();
+ } else {
+ mExecuting = false;
+ mResult = ResultError;
+ finishTimer->start( 0, true );
+ return;
+ }
+}
+
+void ActionScheduler::messageRetrieved(KMMessage* msg)
+{
+ // Get a write lock on the message while it's being filtered
+ msg->setTransferInProgress( true );
+ filterMessageTimer->start( 0, true );
+}
+
+void ActionScheduler::filterMessage()
+{
+ if (mFilterIt == mFilters.end()) {
+ moveMessage();
+ return;
+ }
+ if (((mSet & KMFilterMgr::Outbound) && (*mFilterIt).applyOnOutbound()) ||
+ ((mSet & KMFilterMgr::Inbound) && (*mFilterIt).applyOnInbound() &&
+ (!mAccount ||
+ (mAccount && (*mFilterIt).applyOnAccount(mAccountId)))) ||
+ ((mSet & KMFilterMgr::Explicit) && (*mFilterIt).applyOnExplicit())) {
+
+ // filter is applicable
+ if ( FilterLog::instance()->isLogging() ) {
+ QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
+ logText.append( (*mFilterIt).pattern()->asString() );
+ FilterLog::instance()->add( logText, FilterLog::patternDesc );
+ }
+ if (mAlwaysMatch ||
+ (*mFilterIt).pattern()->matches( *mMessageIt )) {
+ if ( FilterLog::instance()->isLogging() ) {
+ FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
+ FilterLog::patternResult );
+ }
+ mFilterAction = (*mFilterIt).actions()->first();
+ actionMessage();
+ return;
+ }
+ }
+ ++mFilterIt;
+ filterMessageTimer->start( 0, true );
+}
+
+void ActionScheduler::actionMessage(KMFilterAction::ReturnCode res)
+{
+ if (res == KMFilterAction::CriticalError) {
+ mResult = ResultCriticalError;
+ finish(); //must handle critical errors immediately
+ }
+ if (mFilterAction) {
+ KMMessage *msg = message( *mMessageIt );
+ if (msg) {
+ if ( FilterLog::instance()->isLogging() ) {
+ QString logText( i18n( "<b>Applying filter action:</b> %1" )
+ .arg( mFilterAction->displayString() ) );
+ FilterLog::instance()->add( logText, FilterLog::appliedAction );
+ }
+ KMFilterAction *action = mFilterAction;
+ mFilterAction = (*mFilterIt).actions()->next();
+ action->processAsync( msg );
+ }
+ } else {
+ // there are no more actions
+ if ((*mFilterIt).stopProcessingHere())
+ mFilterIt = mFilters.end();
+ else
+ ++mFilterIt;
+ filterMessageTimer->start( 0, true );
+ }
+}
+
+void ActionScheduler::moveMessage()
+{
+ KMMsgBase *msgBase = messageBase( *mMessageIt );
+ if (!msgBase)
+ return;
+
+ MessageProperty::setTransferInProgress( *mMessageIt, false, true );
+ KMMessage *msg = message( *mMessageIt );
+ KMFolder *folder = MessageProperty::filterFolder( *mMessageIt );
+ QString serNumS = msg->headerField( "X-KMail-Filtered" );
+ if (!serNumS.isEmpty())
+ mOriginalSerNum = serNumS.toUInt();
+ else
+ mOriginalSerNum = 0;
+ MessageProperty::setFilterHandler( *mMessageIt, 0 );
+ MessageProperty::setFiltering( *mMessageIt, false );
+ mSerNums.remove( *mMessageIt );
+
+ KMMessage *orgMsg = 0;
+ ReturnCode mOldReturnCode = mResult;
+ if (mOriginalSerNum)
+ orgMsg = message( mOriginalSerNum );
+ mResult = mOldReturnCode; // ignore errors in deleting original message
+ if (!orgMsg || !orgMsg->parent()) {
+ // Original message is gone, no point filtering it anymore
+ mSrcFolder->removeMsg( mSrcFolder->find( msg ) );
+ kdDebug(5006) << "The original serial number is missing. "
+ << "Cannot complete the filtering." << endl;
+ mExecutingLock = false;
+ processMessageTimer->start( 0, true );
+ return;
+ } else {
+ if (!folder) // no filter folder specified leave in current place
+ folder = orgMsg->parent();
+ }
+
+ mIgnore = true;
+ assert( msg->parent() == mSrcFolder.operator->() );
+ mSrcFolder->take( mSrcFolder->find( msg ) );
+ mSrcFolder->addMsg( msg );
+ mIgnore = false;
+
+ if (msg && folder && kmkernel->folderIsTrash( folder ))
+ KMFilterAction::sendMDN( msg, KMime::MDN::Deleted );
+
+ timeOutTime = QTime::currentTime();
+ KMCommand *cmd = new KMMoveCommand( folder, msg );
+ connect( cmd, SIGNAL( completed( KMCommand * ) ),
+ this, SLOT( moveMessageFinished( KMCommand * ) ) );
+ cmd->start();
+ // sometimes the move command doesn't complete so time out after a minute
+ // and move onto the next message
+ lastCommand = cmd;
+ timeOutTimer->start( 60 * 1000, true );
+}
+
+void ActionScheduler::moveMessageFinished( KMCommand *command )
+{
+ timeOutTimer->stop();
+ if ( command->result() != KMCommand::OK )
+ mResult = ResultError;
+
+ if (!mSrcFolder->count())
+ mSrcFolder->expunge();
+
+ // in case the message stayed in the current folder TODO optimize
+ if ( mHeaders )
+ mHeaders->clearSelectableAndAboutToBeDeleted( mOriginalSerNum );
+ KMMessage *msg = 0;
+ ReturnCode mOldReturnCode = mResult;
+ if (mOriginalSerNum) {
+ msg = message( mOriginalSerNum );
+ emit filtered( mOriginalSerNum );
+ }
+
+ mResult = mOldReturnCode; // ignore errors in deleting original message
+ KMCommand *cmd = 0;
+ if (msg && msg->parent()) {
+ cmd = new KMMoveCommand( 0, msg );
+// cmd->start(); // Note: sensitive logic here.
+ }
+
+ if (mResult == ResultOk) {
+ mExecutingLock = false;
+ if (cmd)
+ connect( cmd, SIGNAL( completed( KMCommand * ) ),
+ this, SLOT( processMessage() ) );
+ else
+ processMessageTimer->start( 0, true );
+ } else {
+ // Note: An alternative to consider is just calling
+ // finishTimer->start and returning
+ if (cmd)
+ connect( cmd, SIGNAL( completed( KMCommand * ) ),
+ this, SLOT( finish() ) );
+ else
+ finishTimer->start( 0, true );
+ }
+ if (cmd)
+ cmd->start();
+ // else moveMessageFinished should call finish
+}
+
+void ActionScheduler::copyMessageFinished( KMCommand *command )
+{
+ if ( command->result() != KMCommand::OK )
+ actionMessage( KMFilterAction::ErrorButGoOn );
+ else
+ actionMessage();
+}
+
+void ActionScheduler::timeOut()
+{
+ // Note: This is a good place for a debug statement
+ assert( lastCommand );
+ // sometimes imap jobs seem to just stall so give up and move on
+ disconnect( lastCommand, SIGNAL( completed( KMCommand * ) ),
+ this, SLOT( moveMessageFinished( KMCommand * ) ) );
+ lastCommand = 0;
+ mExecutingLock = false;
+ mExecuting = false;
+ finishTimer->start( 0, true );
+ if (mOriginalSerNum) // Try again
+ execFilters( mOriginalSerNum );
+}
+
+void ActionScheduler::fetchTimeOut()
+{
+ // Note: This is a good place for a debug statement
+ assert( lastJob );
+ // sometimes imap jobs seem to just stall so give up and move on
+ disconnect( lastJob, SIGNAL(messageRetrieved( KMMessage* )),
+ this, SLOT(messageFetched( KMMessage* )) );
+ lastJob->kill();
+ lastJob = 0;
+ fetchMessageTimer->start( 0, true );
+}
+
+QString ActionScheduler::debug()
+{
+ QString res;
+ QValueList<ActionScheduler*>::iterator it;
+ int i = 1;
+ for ( it = schedulerList->begin(); it != schedulerList->end(); ++it ) {
+ res.append( QString( "ActionScheduler #%1.\n" ).arg( i ) );
+ if ((*it)->mAccount && kmkernel->find( (*it)->mAccountId )) {
+ res.append( QString( "Account %1, Name %2.\n" )
+ .arg( (*it)->mAccountId )
+ .arg( kmkernel->acctMgr()->find( (*it)->mAccountId )->name() ) );
+ }
+ res.append( QString( "mExecuting %1, " ).arg( (*it)->mExecuting ? "true" : "false" ) );
+ res.append( QString( "mExecutingLock %1, " ).arg( (*it)->mExecutingLock ? "true" : "false" ) );
+ res.append( QString( "mFetchExecuting %1.\n" ).arg( (*it)->mFetchExecuting ? "true" : "false" ) );
+ res.append( QString( "mOriginalSerNum %1.\n" ).arg( (*it)->mOriginalSerNum ) );
+ res.append( QString( "mMessageIt %1.\n" ).arg( ((*it)->mMessageIt != 0) ? *(*it)->mMessageIt : 0 ) );
+ res.append( QString( "mSerNums count %1, " ).arg( (*it)->mSerNums.count() ) );
+ res.append( QString( "mFetchSerNums count %1.\n" ).arg( (*it)->mFetchSerNums.count() ) );
+ res.append( QString( "mResult " ) );
+ if ((*it)->mResult == ResultOk)
+ res.append( QString( "ResultOk.\n" ) );
+ else if ((*it)->mResult == ResultError)
+ res.append( QString( "ResultError.\n" ) );
+ else if ((*it)->mResult == ResultCriticalError)
+ res.append( QString( "ResultCriticalError.\n" ) );
+ else
+ res.append( QString( "Unknown.\n" ) );
+
+ ++i;
+ }
+ return res;
+}
+
+bool ActionScheduler::isEnabled()
+{
+ if (sEnabledChecked)
+ return sEnabled;
+
+ sEnabledChecked = true;
+ KConfig* config = KMKernel::config();
+ KConfigGroupSaver saver(config, "General");
+ sEnabled = config->readBoolEntry("action-scheduler", false);
+ return sEnabled;
+}
+
+bool ActionScheduler::ignoreChanges( bool ignore )
+{
+ bool oldValue = mIgnore;
+ mIgnore = ignore;
+ return oldValue;
+}
+
+#include "actionscheduler.moc"
diff --git a/kmail/actionscheduler.h b/kmail/actionscheduler.h
new file mode 100644
index 00000000..027bce21
--- /dev/null
+++ b/kmail/actionscheduler.h
@@ -0,0 +1,173 @@
+/* -*- mode: C++ -*-
+ Action Scheduler
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) Don Sanders <sanders@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef actionscheduler_h
+#define actionscheduler_h
+
+#include "kmfilteraction.h" // for KMFilterAction::ReturnCode
+#include "kmfilter.h"
+#include "kmfiltermgr.h" // KMFilterMgr::FilterSet
+#include "kmcommands.h"
+
+#include <qobject.h>
+#include <qguardedptr.h>
+#include <qtimer.h>
+
+class KMHeaders;
+
+namespace KMail {
+
+/* A class for asynchronous filtering of messages */
+class ActionScheduler : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum ReturnCode { ResultOk, ResultError, ResultCriticalError };
+
+ ActionScheduler(KMFilterMgr::FilterSet set,
+ QValueList<KMFilter*> filters,
+ KMHeaders *headers = 0,
+ KMFolder *srcFolder = 0);
+ ~ActionScheduler();
+
+ /** The action scheduler will be deleted after the finish signal is emitted
+ if this property is set to true */
+ void setAutoDestruct( bool );
+
+ /** Apply all filters even if they don't match */
+ void setAlwaysMatch( bool );
+
+ /** Set a default folder to move messages into */
+ void setDefaultDestinationFolder( KMFolder* );
+
+ /** Set a folder to monitor for new messages to filter */
+ void setSourceFolder( KMFolder* );
+
+ /** Set a list of filters to work with
+ The current list will not be updated until the queue
+ of messages left to process is empty */
+ void setFilterList( QValueList<KMFilter*> filters );
+
+ /** Set the id of the account associated with this scheduler */
+ void setAccountId( uint id ) { mAccountId = id; mAccount = true; }
+
+ /** Clear the id of the account associated with this scheduler */
+ void clearAccountId() { mAccountId = 0; mAccount = false; }
+
+ /** Queue a message for filtering */
+ void execFilters(const QValueList<Q_UINT32> serNums);
+ void execFilters(const QPtrList<KMMsgBase> msgList);
+ void execFilters(KMMsgBase* msgBase);
+ void execFilters(Q_UINT32 serNum);
+
+ static QString debug();
+ static bool isEnabled();
+
+ /** Allow or deny manipulations on the message to be filtered.
+ This is needed when using pipe-through filters, because the
+ changes made by the filter have to be written back.
+ The old value before applying the new value is returned. */
+ bool ignoreChanges( bool ignore );
+
+signals:
+ /** Emitted when filtering is completed */
+ void result(ReturnCode);
+ void filtered(Q_UINT32);
+
+public slots:
+ /** Called back by asynchronous actions when they have completed */
+ void actionMessage(KMFilterAction::ReturnCode = KMFilterAction::GoOn);
+
+ /** Called back by asynchronous copy actions when they have completed */
+ void copyMessageFinished( KMCommand *command );
+
+private slots:
+ KMMsgBase* messageBase(Q_UINT32 serNum);
+ KMMessage* message(Q_UINT32 serNum);
+ void finish();
+
+ void folderClosedOrExpunged();
+
+ int tempOpenFolder(KMFolder* aFolder);
+ void tempCloseFolders();
+
+ //Fetching slots
+ void fetchMessage();
+ void messageFetched( KMMessage *msg );
+ void msgAdded( KMFolder*, Q_UINT32 );
+ void enqueue(Q_UINT32 serNum);
+
+ //Filtering slots
+ void processMessage();
+ void messageRetrieved(KMMessage*);
+ void filterMessage();
+ void moveMessage();
+ void moveMessageFinished( KMCommand *command );
+ void timeOut();
+ void fetchTimeOut();
+
+private:
+ static QValueList<ActionScheduler*> *schedulerList; // for debugging
+ static KMFolderMgr *tempFolderMgr;
+ static int refCount, count;
+ static bool sEnabled, sEnabledChecked;
+ QValueListIterator<Q_UINT32> mMessageIt;
+ QValueListIterator<KMFilter> mFilterIt;
+ QValueList<Q_UINT32> mSerNums, mFetchSerNums;
+ QValueList<QGuardedPtr<KMFolder> > mOpenFolders;
+ QValueList<KMFilter> mFilters, mQueuedFilters;
+ KMFilterAction* mFilterAction;
+ KMFilterMgr::FilterSet mSet;
+ KMHeaders *mHeaders;
+ QGuardedPtr<KMFolder> mSrcFolder, mDestFolder;
+ bool mExecuting, mExecutingLock, mFetchExecuting;
+ bool mUnget, mFetchUnget;
+ bool mIgnore;
+ bool mFiltersAreQueued;
+ bool mAutoDestruct;
+ bool mAlwaysMatch;
+ bool mAccount;
+ uint mAccountId;
+ Q_UINT32 mOriginalSerNum;
+ bool mDeleteSrcFolder;
+ ReturnCode mResult;
+ QTimer *finishTimer, *fetchMessageTimer, *tempCloseFoldersTimer;
+ QTimer *processMessageTimer, *filterMessageTimer;
+ QTimer *timeOutTimer, *fetchTimeOutTimer;
+ QTime timeOutTime, fetchTimeOutTime;
+ KMCommand *lastCommand;
+ FolderJob *lastJob;
+};
+
+}
+
+#endif /*actionscheduler_h*/
diff --git a/kmail/annotationjobs.cpp b/kmail/annotationjobs.cpp
new file mode 100644
index 00000000..314f01fa
--- /dev/null
+++ b/kmail/annotationjobs.cpp
@@ -0,0 +1,253 @@
+/**
+ * annotationjobs.cpp
+ *
+ * Copyright (c) 2004 David Faure <faure@kde.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+#include "annotationjobs.h"
+#include <kio/scheduler.h>
+#include <kdebug.h>
+
+using namespace KMail;
+
+KIO::SimpleJob* AnnotationJobs::setAnnotation(
+ KIO::Slave* slave, const KURL& url, const QString& entry,
+ const QMap<QString,QString>& attributes )
+{
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)'M' << (int)'S' << url << entry << attributes;
+
+ KIO::SimpleJob* job = KIO::special( url, packedArgs, false );
+ KIO::Scheduler::assignJobToSlave( slave, job );
+ return job;
+}
+
+AnnotationJobs::GetAnnotationJob* AnnotationJobs::getAnnotation(
+ KIO::Slave* slave, const KURL& url, const QString& entry,
+ const QStringList& attributes )
+{
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)'M' << (int)'G' << url << entry << attributes;
+
+ GetAnnotationJob* job = new GetAnnotationJob( url, entry, packedArgs, false );
+ KIO::Scheduler::assignJobToSlave( slave, job );
+ return job;
+}
+
+AnnotationJobs::GetAnnotationJob::GetAnnotationJob( const KURL& url, const QString& entry,
+ const QByteArray &packedArgs,
+ bool showProgressInfo )
+ : KIO::SimpleJob( url, KIO::CMD_SPECIAL, packedArgs, showProgressInfo ),
+ mEntry( entry )
+{
+ connect( this, SIGNAL(infoMessage(KIO::Job*,const QString&)),
+ SLOT(slotInfoMessage(KIO::Job*,const QString&)) );
+}
+
+void AnnotationJobs::GetAnnotationJob::slotInfoMessage( KIO::Job*, const QString& str )
+{
+ // Parse the result
+ QStringList lst = QStringList::split( "\r", str );
+ while ( lst.count() >= 2 ) // we take items 2 by 2
+ {
+ QString name = lst.front(); lst.pop_front();
+ QString value = lst.front(); lst.pop_front();
+ mAnnotations.append( AnnotationAttribute( mEntry, name, value ) );
+ }
+}
+
+AnnotationJobs::MultiGetAnnotationJob::MultiGetAnnotationJob(
+ KIO::Slave* slave, const KURL& url, const QStringList& entries, bool showProgressInfo )
+ : KIO::Job( showProgressInfo ),
+ mSlave( slave ),
+ mUrl( url ), mEntryList( entries ), mEntryListIterator( mEntryList.begin() )
+{
+ QTimer::singleShot(0, this, SLOT(slotStart()));
+}
+
+
+void AnnotationJobs::MultiGetAnnotationJob::slotStart()
+{
+ if ( mEntryListIterator != mEntryList.end() ) {
+ QStringList attributes;
+ attributes << "value";
+ KIO::Job* job = getAnnotation( mSlave, mUrl, *mEntryListIterator, attributes );
+ addSubjob( job );
+ } else { // done!
+ emitResult();
+ }
+}
+
+void AnnotationJobs::MultiGetAnnotationJob::slotResult( KIO::Job *job )
+{
+ if ( job->error() ) {
+ KIO::Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ subjobs.remove( job );
+ const QString& entry = *mEntryListIterator;
+ QString value;
+ bool found = false;
+ GetAnnotationJob* getJob = static_cast<GetAnnotationJob *>( job );
+ const AnnotationList& lst = getJob->annotations();
+ for ( unsigned int i = 0 ; i < lst.size() ; ++ i ) {
+ kdDebug(5006) << "found annotation " << lst[i].name << " = " << lst[i].value << endl;
+ if ( lst[i].name.startsWith( "value." ) ) { // value.priv or value.shared
+ found = true;
+ value = lst[i].value;
+ break;
+ }
+ }
+ emit annotationResult( entry, value, found );
+ // Move on to next one
+ ++mEntryListIterator;
+ slotStart();
+}
+
+AnnotationJobs::MultiGetAnnotationJob* AnnotationJobs::multiGetAnnotation( KIO::Slave* slave, const KURL& url, const QStringList& entries )
+{
+ return new MultiGetAnnotationJob( slave, url, entries, false /*showProgressInfo*/ );
+}
+
+////
+
+AnnotationJobs::MultiSetAnnotationJob::MultiSetAnnotationJob(
+ KIO::Slave* slave, const KURL& url, const AnnotationList& annotations, bool showProgressInfo )
+ : KIO::Job( showProgressInfo ),
+ mSlave( slave ),
+ mUrl( url ), mAnnotationList( annotations ), mAnnotationListIterator( mAnnotationList.begin() )
+{
+ QTimer::singleShot(0, this, SLOT(slotStart()));
+}
+
+
+void AnnotationJobs::MultiSetAnnotationJob::slotStart()
+{
+ if ( mAnnotationListIterator != mAnnotationList.end() ) {
+ const AnnotationAttribute& attr = *mAnnotationListIterator;
+ // setAnnotation can set multiple attributes for a given entry.
+ // So in theory we could group entries coming from our list. Bah.
+ QMap<QString, QString> attributes;
+ attributes.insert( attr.name, attr.value );
+ kdDebug() << k_funcinfo << " setting annotation " << attr.entry << " " << attr.name << " " << attr.value << endl;
+ KIO::Job* job = setAnnotation( mSlave, mUrl, attr.entry, attributes );
+ addSubjob( job );
+ } else { // done!
+ emitResult();
+ }
+}
+
+void AnnotationJobs::MultiSetAnnotationJob::slotResult( KIO::Job *job )
+{
+ if ( job->error() ) {
+ KIO::Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ subjobs.remove( job );
+ const AnnotationAttribute& attr = *mAnnotationListIterator;
+ emit annotationChanged( attr.entry, attr.name, attr.value );
+
+ // Move on to next one
+ ++mAnnotationListIterator;
+ slotStart();
+}
+
+AnnotationJobs::MultiSetAnnotationJob* AnnotationJobs::multiSetAnnotation(
+ KIO::Slave* slave, const KURL& url, const AnnotationList& annotations )
+{
+ return new MultiSetAnnotationJob( slave, url, annotations, false /*showProgressInfo*/ );
+}
+
+
+AnnotationJobs::MultiUrlGetAnnotationJob::MultiUrlGetAnnotationJob( KIO::Slave* slave,
+ const KURL& baseUrl,
+ const QStringList& paths,
+ const QString& annotation )
+ : KIO::Job( false ),
+ mSlave( slave ),
+ mUrl( baseUrl ),
+ mPathList( paths ),
+ mPathListIterator( mPathList.begin() ),
+ mAnnotation( annotation )
+{
+ QTimer::singleShot(0, this, SLOT(slotStart()));
+}
+
+
+void AnnotationJobs::MultiUrlGetAnnotationJob::slotStart()
+{
+ if ( mPathListIterator != mPathList.end() ) {
+ QStringList attributes;
+ attributes << "value";
+ KURL url(mUrl);
+ url.setPath( *mPathListIterator );
+ KIO::Job* job = getAnnotation( mSlave, url, mAnnotation, attributes );
+ addSubjob( job );
+ } else { // done!
+ emitResult();
+ }
+}
+
+void AnnotationJobs::MultiUrlGetAnnotationJob::slotResult( KIO::Job *job )
+{
+ if ( job->error() ) {
+ KIO::Job::slotResult( job ); // will set the error and emit result(this)
+ return;
+ }
+ subjobs.remove( job );
+ const QString& path = *mPathListIterator;
+ GetAnnotationJob* getJob = static_cast<GetAnnotationJob *>( job );
+ const AnnotationList& lst = getJob->annotations();
+ for ( unsigned int i = 0 ; i < lst.size() ; ++ i ) {
+ kdDebug(5006) << "MultiURL: found annotation " << lst[i].name << " = " << lst[i].value << " for path: " << path << endl;
+ if ( lst[i].name.startsWith( "value." ) ) { // value.priv or value.shared
+ mAnnotations.insert( path, lst[i].value );
+ break;
+ }
+ }
+ // Move on to next one
+ ++mPathListIterator;
+ slotStart();
+}
+
+QMap<QString, QString> AnnotationJobs::MultiUrlGetAnnotationJob::annotations() const
+{
+ return mAnnotations;
+}
+
+AnnotationJobs::MultiUrlGetAnnotationJob* AnnotationJobs::multiUrlGetAnnotation( KIO::Slave* slave,
+ const KURL& baseUrl,
+ const QStringList& paths,
+ const QString& annotation )
+{
+ return new MultiUrlGetAnnotationJob( slave, baseUrl, paths, annotation );
+}
+
+
+#include "annotationjobs.moc"
diff --git a/kmail/annotationjobs.h b/kmail/annotationjobs.h
new file mode 100644
index 00000000..5375eeed
--- /dev/null
+++ b/kmail/annotationjobs.h
@@ -0,0 +1,199 @@
+/*
+ * annotationjobs.h
+ *
+ * Copyright (c) 2004 David Faure <faure@kde.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+
+#ifndef ANNOTATIONJOBS_H
+#define ANNOTATIONJOBS_H
+
+#include <kio/job.h>
+#include <qvaluevector.h>
+
+namespace KMail {
+
+/// One entry in the annotation list: attribute name and attribute value
+struct AnnotationAttribute {
+ AnnotationAttribute() {} // for QValueVector
+ AnnotationAttribute( const QString& e, const QString& n, const QString& v )
+ : entry( e ), name( n ), value( v ) {}
+ QString entry; // e.g. /comment
+ QString name; // e.g. value.shared
+ QString value;
+};
+
+typedef QValueVector<AnnotationAttribute> AnnotationList;
+
+/**
+ * This namespace contains functions that return jobs for annotation operations.
+ *
+ * The current implementation is tied to IMAP.
+ * If someone wants to extend this to other protocols, turn the namespace into a class
+ * and use virtual methods.
+ */
+namespace AnnotationJobs {
+
+/**
+ * Set an annotation entry (note that it can have multiple attributes)
+ * @param slave Slave object the job should be assigned to
+ * @param url URL for the annotation
+ * @param entry the name of the annotation entry
+ * @param attributes attribute name+value pairs
+ */
+KIO::SimpleJob* setAnnotation( KIO::Slave* slave, const KURL& url, const QString& entry,
+ const QMap<QString,QString>& attributes );
+
+class MultiSetAnnotationJob;
+/**
+ * Set multiple annotation entries
+ */
+MultiSetAnnotationJob* multiSetAnnotation( KIO::Slave* slave, const KURL& url, const AnnotationList& annotations );
+
+class GetAnnotationJob;
+/**
+ * Get an annotation entry
+ * @param slave Slave object the job should be assigned to
+ * @param url URL for the annotation
+ * @param entry the name of the annotation entry
+ * @param attributes attribute names
+ */
+GetAnnotationJob* getAnnotation( KIO::Slave* slave, const KURL& url, const QString& entry,
+ const QStringList& attributes );
+
+class MultiGetAnnotationJob;
+/**
+ * Get multiple annotation entries
+ * Currently we assume we want to get the "value" for each, to simplify the data structure.
+ */
+MultiGetAnnotationJob* multiGetAnnotation( KIO::Slave* slave, const KURL& url, const QStringList& entries );
+
+class MultiUrlGetAnnotationJob;
+/**
+ * Get annotation entries for multiple folders.
+ * @param paths The paths to get the annotation for
+ * @param annotation The annotation to get
+ */
+MultiUrlGetAnnotationJob* multiUrlGetAnnotation( KIO::Slave* slave,
+ const KURL& baseUrl,
+ const QStringList& paths,
+ const QString& annotation );
+
+
+/// for getAnnotation()
+class GetAnnotationJob : public KIO::SimpleJob
+{
+ Q_OBJECT
+public:
+ GetAnnotationJob( const KURL& url, const QString& entry, const QByteArray &packedArgs,
+ bool showProgressInfo );
+
+ const AnnotationList& annotations() const { return mAnnotations; }
+
+protected slots:
+ void slotInfoMessage( KIO::Job*, const QString& );
+private:
+ AnnotationList mAnnotations;
+ QString mEntry;
+};
+
+/// for multiGetAnnotation
+class MultiGetAnnotationJob : public KIO::Job
+{
+ Q_OBJECT
+
+public:
+ MultiGetAnnotationJob( KIO::Slave* slave, const KURL& url, const QStringList& entries, bool showProgressInfo );
+
+signals:
+ // Emitted when a given annotation was found - or not found
+ void annotationResult( const QString& entry, const QString& value, bool found );
+
+protected slots:
+ virtual void slotStart();
+ virtual void slotResult( KIO::Job *job );
+
+private:
+ KIO::Slave* mSlave;
+ const KURL mUrl;
+ const QStringList mEntryList;
+ QStringList::const_iterator mEntryListIterator;
+};
+
+/// for multiUrlGetAnnotation
+class MultiUrlGetAnnotationJob : public KIO::Job
+{
+ Q_OBJECT
+
+public:
+ MultiUrlGetAnnotationJob( KIO::Slave* slave, const KURL& baseUrl,
+ const QStringList& paths, const QString& annotation );
+
+ QMap<QString, QString> annotations() const;
+
+protected slots:
+ virtual void slotStart();
+ virtual void slotResult( KIO::Job *job );
+
+private:
+ KIO::Slave* mSlave;
+ const KURL mUrl;
+ const QStringList mPathList;
+ QStringList::const_iterator mPathListIterator;
+ QString mAnnotation;
+ QMap<QString, QString> mAnnotations;
+};
+
+/// for multiSetAnnotation
+class MultiSetAnnotationJob : public KIO::Job
+{
+ Q_OBJECT
+
+public:
+ MultiSetAnnotationJob( KIO::Slave* slave, const KURL& url, const AnnotationList& annotations, bool showProgressInfo );
+
+signals:
+ // Emitted when a given annotation was successfully changed
+ void annotationChanged( const QString& entry, const QString& attribute, const QString& value );
+
+protected slots:
+ virtual void slotStart();
+ virtual void slotResult( KIO::Job *job );
+
+private:
+ KIO::Slave* mSlave;
+ const KURL mUrl;
+ const AnnotationList mAnnotationList;
+ AnnotationList::const_iterator mAnnotationListIterator;
+};
+
+} // AnnotationJobs namespace
+
+} // KMail namespace
+
+#endif /* ANNOTATIONJOBS_H */
+
diff --git a/kmail/antispamconfig.cpp b/kmail/antispamconfig.cpp
new file mode 100644
index 00000000..448bd9ac
--- /dev/null
+++ b/kmail/antispamconfig.cpp
@@ -0,0 +1,98 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ antispamconfig.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Patrick Audley <paudley@blackcat.ca>
+ Copyright (c) 2004 Ingo Kloecker <kloecker@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "antispamconfig.h"
+
+#include <kasciistricmp.h>
+
+#include <kstaticdeleter.h>
+#include <kconfig.h>
+
+using namespace KMail;
+
+AntiSpamConfig * AntiSpamConfig::sSelf = 0;
+static KStaticDeleter<AntiSpamConfig> antispamconfig_sd;
+
+AntiSpamConfig * AntiSpamConfig::instance() {
+ if ( !sSelf ) {
+ antispamconfig_sd.setObject( sSelf, new AntiSpamConfig() );
+ sSelf->readConfig();
+ }
+ return sSelf;
+}
+
+void AntiSpamConfig::readConfig()
+{
+ mAgents.clear();
+ KConfig config( "kmail.antispamrc", true );
+ config.setReadDefaults( true );
+ KConfigGroup general( &config, "General" );
+ unsigned int totalTools = general.readUnsignedNumEntry( "tools", 0 );
+ for ( unsigned int i = 1; i <= totalTools; ++i ) {
+ KConfigGroup tool( &config, QString("Spamtool #%1").arg( i ) );
+ if ( tool.hasKey( "ScoreHeader" ) ) {
+ QString name = tool.readEntry( "ScoreName" );
+ QCString header = tool.readEntry( "ScoreHeader" ).latin1();
+ QCString type = tool.readEntry( "ScoreType" ).latin1();
+ QString score = tool.readEntryUntranslated( "ScoreValueRegexp" );
+ QString threshold = tool.readEntryUntranslated( "ScoreThresholdRegexp" );
+ SpamAgentTypes typeE = SpamAgentNone;
+ if ( kasciistricmp( type.data(), "bool" ) == 0 )
+ typeE = SpamAgentBool;
+ else if ( kasciistricmp( type.data(), "decimal" ) == 0 )
+ typeE = SpamAgentFloat;
+ else if ( kasciistricmp( type.data(), "percentage" ) == 0 )
+ typeE = SpamAgentFloatLarge;
+ else if ( kasciistricmp( type.data(), "adjusted" ) == 0 )
+ typeE = SpamAgentAdjustedFloat;
+ mAgents.append( SpamAgent( name, typeE, header, QRegExp( score ),
+ QRegExp( threshold ) ) );
+ }
+ }
+}
+
+const SpamAgents AntiSpamConfig::uniqueAgents() const
+{
+ QStringList seenAgents;
+ SpamAgents agents;
+ SpamAgents::ConstIterator it( mAgents.begin() );
+ SpamAgents::ConstIterator end( mAgents.end() );
+ for ( ; it != end ; ++it ) {
+ const QString agent( ( *it ).name() );
+ if ( seenAgents.find( agent ) == seenAgents.end() ) {
+ agents.append( *it );
+ seenAgents.append( agent );
+ }
+ }
+ return agents;
+}
diff --git a/kmail/antispamconfig.h b/kmail/antispamconfig.h
new file mode 100644
index 00000000..64394fe9
--- /dev/null
+++ b/kmail/antispamconfig.h
@@ -0,0 +1,120 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ antispamconfig.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Patrick Audley <paudley@blackcat.ca>
+ Copyright (c) 2004 Ingo Kloecker <kloecker@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KMAIL_ANTISPAMCONFIG_H__
+#define __KMAIL_ANTISPAMCONFIG_H__
+
+#include <qvaluelist.h>
+#include <qregexp.h>
+
+class QString;
+class QCString;
+
+namespace KMail {
+
+ /// Valid types of SpamAgent
+ typedef enum {
+ SpamAgentNone, //!< Invalid SpamAgent, skip this agent
+ SpamAgentBool, //!< Simple Yes or No (Razor)
+ SpamAgentFloat, //!< For straight percentages between 0.0 and 1.0 (BogoFilter)
+ SpamAgentFloatLarge, //!< For straight percentages between 0.0 and 100.0
+ SpamAgentAdjustedFloat //!< Use this when we need to compare against a threshold (SpamAssasssin)
+ } SpamAgentTypes;
+
+ class SpamAgent {
+ public:
+ SpamAgent() : mType( SpamAgentNone ) {}
+ SpamAgent( const QString & name, SpamAgentTypes type, const QCString & field,
+ const QRegExp & score, const QRegExp & threshold )
+ : mName( name ), mType( type ), mField( field ),
+ mScore( score ), mThreshold( threshold ) {}
+
+ QString name() const { return mName; }
+ SpamAgentTypes scoreType() const { return mType; }
+ QCString header() const { return mField; }
+ QRegExp scorePattern() const { return mScore; }
+ QRegExp thresholdPattern() const { return mThreshold; }
+
+ private:
+ QString mName;
+ SpamAgentTypes mType;
+ QCString mField;
+ QRegExp mScore;
+ QRegExp mThreshold;
+ };
+ typedef QValueList<SpamAgent> SpamAgents;
+ typedef QValueListIterator<SpamAgent> SpamAgentsIterator;
+
+ /**
+ @short Singleton to manage loading the kmail.antispamrc file.
+ @author Patrick Audley <paudley@blackcat.ca>
+
+ Use of this config-manager class is straight forward. Since it
+ is a singleton object, all you have to do is obtain an instance
+ by calling @p SpamConfig::instance() and use any of the
+ public member functions.
+ */
+ class AntiSpamConfig {
+ private:
+ static AntiSpamConfig * sSelf;
+
+ AntiSpamConfig() {}
+
+ public:
+ ~AntiSpamConfig() {}
+
+ static AntiSpamConfig * instance();
+
+ /**
+ * Returns a list of all agents found on the system. This
+ * might list SA twice, if both the C and the Perl version are present.
+ */
+ const SpamAgents agents() const { return mAgents; }
+ SpamAgents agents() { return mAgents; }
+
+ /**
+ * Returns a list of unique agents, found on the system. SpamAssassin will
+ * only be listed once, even if both the C and the Perl version are
+ * installed.
+ */
+ const SpamAgents uniqueAgents() const;
+
+ private:
+ SpamAgents mAgents;
+
+ void readConfig();
+ };
+
+} // namespace KMail
+
+#endif // __KMAIL_ANTISPAMCONFIG_H__
diff --git a/kmail/antispamwizard.cpp b/kmail/antispamwizard.cpp
new file mode 100644
index 00000000..bb8d74bb
--- /dev/null
+++ b/kmail/antispamwizard.cpp
@@ -0,0 +1,1151 @@
+/*
+ This file is part of KMail.
+ Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "antispamwizard.h"
+#include "kcursorsaver.h"
+#include "accountmanager.h"
+#include "kmfilter.h"
+#include "kmfilteraction.h"
+#include "kmfiltermgr.h"
+#include "kmkernel.h"
+#include "kmfolderseldlg.h"
+#include "kmfoldertree.h"
+#include "kmmainwin.h"
+#include "networkaccount.h"
+#include "folderrequester.h"
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+
+#include <qdom.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+using namespace KMail;
+
+AntiSpamWizard::AntiSpamWizard( WizardMode mode,
+ QWidget* parent, KMFolderTree * mainFolderTree )
+ : KWizard( parent ),
+ mInfoPage( 0 ),
+ mSpamRulesPage( 0 ),
+ mVirusRulesPage( 0 ),
+ mSummaryPage( 0 ),
+ mMode( mode )
+{
+ // read the configuration for the anti-spam tools
+ ConfigReader reader( mMode, mToolList );
+ reader.readAndMergeConfig();
+ mToolList = reader.getToolList();
+
+#ifndef NDEBUG
+ if ( mMode == AntiSpam )
+ kdDebug(5006) << endl << "Considered anti-spam tools: " << endl;
+ else
+ kdDebug(5006) << endl << "Considered anti-virus tools: " << endl;
+#endif
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+#ifndef NDEBUG
+ kdDebug(5006) << "Predefined tool: " << (*it).getId() << endl;
+ kdDebug(5006) << "Config version: " << (*it).getVersion() << endl;
+ kdDebug(5006) << "Selection priority: " << (*it).getPrio() << endl;
+ kdDebug(5006) << "Displayed name: " << (*it).getVisibleName() << endl;
+ kdDebug(5006) << "Executable: " << (*it).getExecutable() << endl;
+ kdDebug(5006) << "WhatsThis URL: " << (*it).getWhatsThisText() << endl;
+ kdDebug(5006) << "Filter name: " << (*it).getFilterName() << endl;
+ kdDebug(5006) << "Detection command: " << (*it).getDetectCmd() << endl;
+ kdDebug(5006) << "Learn spam command: " << (*it).getSpamCmd() << endl;
+ kdDebug(5006) << "Learn ham command: " << (*it).getHamCmd() << endl;
+ kdDebug(5006) << "Detection header: " << (*it).getDetectionHeader() << endl;
+ kdDebug(5006) << "Detection pattern: " << (*it).getDetectionPattern() << endl;
+ kdDebug(5006) << "Use as RegExp: " << (*it).isUseRegExp() << endl;
+ kdDebug(5006) << "Supports Bayes Filter: " << (*it).useBayesFilter() << endl;
+ kdDebug(5006) << "Type: " << (*it).getType() << endl << endl;
+#endif
+ }
+
+ setCaption( ( mMode == AntiSpam ) ? i18n( "Anti-Spam Wizard" )
+ : i18n( "Anti-Virus Wizard" ) );
+ mInfoPage = new ASWizInfoPage( mMode, 0, "" );
+ addPage( mInfoPage,
+ ( mMode == AntiSpam )
+ ? i18n( "Welcome to the KMail Anti-Spam Wizard" )
+ : i18n( "Welcome to the KMail Anti-Virus Wizard" ) );
+ connect( mInfoPage, SIGNAL( selectionChanged( void ) ),
+ this, SLOT( checkProgramsSelections( void ) ) );
+
+ if ( mMode == AntiSpam ) {
+ mSpamRulesPage = new ASWizSpamRulesPage( 0, "", mainFolderTree );
+ addPage( mSpamRulesPage, i18n( "Options to fine-tune the handling of spam messages" ));
+ connect( mSpamRulesPage, SIGNAL( selectionChanged( void ) ),
+ this, SLOT( slotBuildSummary( void ) ) );
+ }
+ else {
+ mVirusRulesPage = new ASWizVirusRulesPage( 0, "", mainFolderTree );
+ addPage( mVirusRulesPage, i18n( "Options to fine-tune the handling of virus messages" ));
+ connect( mVirusRulesPage, SIGNAL( selectionChanged( void ) ),
+ this, SLOT( checkVirusRulesSelections( void ) ) );
+ }
+
+ connect( this, SIGNAL( helpClicked( void) ),
+ this, SLOT( slotHelpClicked( void ) ) );
+
+ setNextEnabled( mInfoPage, false );
+
+ if ( mMode == AntiSpam ) {
+ mSummaryPage = new ASWizSummaryPage( 0, "" );
+ addPage( mSummaryPage, i18n( "Summary of changes to be made by this wizard" ) );
+ setNextEnabled( mSpamRulesPage, true );
+ setFinishEnabled( mSummaryPage, true );
+ }
+
+ QTimer::singleShot( 0, this, SLOT( checkToolAvailability( void ) ) );
+}
+
+
+void AntiSpamWizard::accept()
+{
+ if ( mSpamRulesPage ) {
+ kdDebug( 5006 ) << "Folder name for messages classified as spam is "
+ << mSpamRulesPage->selectedSpamFolderName() << endl;
+ kdDebug( 5006 ) << "Folder name for messages classified as unsure is "
+ << mSpamRulesPage->selectedUnsureFolderName() << endl;
+ }
+ if ( mVirusRulesPage )
+ kdDebug( 5006 ) << "Folder name for viruses is "
+ << mVirusRulesPage->selectedFolderName() << endl;
+
+ KMFilterActionDict dict;
+ QValueList<KMFilter*> filterList;
+ bool replaceExistingFilters = false;
+
+ // Let's start with virus detection and handling,
+ // so we can avoid spam checks for viral messages
+ if ( mMode == AntiVirus ) {
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) &&
+ ( mVirusRulesPage->pipeRulesSelected() && (*it).isVirusTool() ) )
+ {
+ // pipe messages through the anti-virus tools,
+ // one single filter for each tool
+ // (could get combined but so it's easier to understand for the user)
+ KMFilter* pipeFilter = new KMFilter();
+ QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions();
+ KMFilterAction* pipeFilterAction = dict["filter app"]->create();
+ pipeFilterAction->argsFromString( (*it).getDetectCmd() );
+ pipeFilterActions->append( pipeFilterAction );
+ KMSearchPattern* pipeFilterPattern = pipeFilter->pattern();
+ pipeFilterPattern->setName( uniqueNameFor( (*it).getFilterName() ) );
+ pipeFilterPattern->append( KMSearchRule::createInstance( "<size>",
+ KMSearchRule::FuncIsGreaterOrEqual, "0" ) );
+ pipeFilter->setApplyOnOutbound( false);
+ pipeFilter->setApplyOnInbound();
+ pipeFilter->setApplyOnExplicit();
+ pipeFilter->setStopProcessingHere( false );
+ pipeFilter->setConfigureShortcut( false );
+
+ filterList.append( pipeFilter );
+ }
+ }
+
+ if ( mVirusRulesPage->moveRulesSelected() )
+ {
+ // Sort out viruses depending on header fields set by the tools
+ KMFilter* virusFilter = new KMFilter();
+ QPtrList<KMFilterAction>* virusFilterActions = virusFilter->actions();
+ KMFilterAction* virusFilterAction1 = dict["transfer"]->create();
+ virusFilterAction1->argsFromString( mVirusRulesPage->selectedFolderName() );
+ virusFilterActions->append( virusFilterAction1 );
+ if ( mVirusRulesPage->markReadRulesSelected() ) {
+ KMFilterAction* virusFilterAction2 = dict["set status"]->create();
+ virusFilterAction2->argsFromString( "R" ); // Read
+ virusFilterActions->append( virusFilterAction2 );
+ }
+ KMSearchPattern* virusFilterPattern = virusFilter->pattern();
+ virusFilterPattern->setName( uniqueNameFor( i18n( "Virus handling" ) ) );
+ virusFilterPattern->setOp( KMSearchPattern::OpOr );
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ))
+ {
+ if ( (*it).isVirusTool() )
+ {
+ const QCString header = (*it).getDetectionHeader().ascii();
+ const QString & pattern = (*it).getDetectionPattern();
+ if ( (*it).isUseRegExp() )
+ virusFilterPattern->append(
+ KMSearchRule::createInstance( header,
+ KMSearchRule::FuncRegExp, pattern ) );
+ else
+ virusFilterPattern->append(
+ KMSearchRule::createInstance( header,
+ KMSearchRule::FuncContains, pattern ) );
+ }
+ }
+ }
+ virusFilter->setApplyOnOutbound( false);
+ virusFilter->setApplyOnInbound();
+ virusFilter->setApplyOnExplicit();
+ virusFilter->setStopProcessingHere( true );
+ virusFilter->setConfigureShortcut( false );
+
+ filterList.append( virusFilter );
+ }
+ }
+ else { // AntiSpam mode
+ // TODO Existing filters with same name are replaced. This is hardcoded
+ // ATM and needs to be replaced with a value from a (still missing)
+ // checkbox in the GUI. At least, the replacement is announced in the GUI.
+ replaceExistingFilters = true;
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) &&
+ (*it).isSpamTool() && !(*it).isDetectionOnly() )
+ {
+ // pipe messages through the anti-spam tools,
+ // one single filter for each tool
+ // (could get combined but so it's easier to understand for the user)
+ KMFilter* pipeFilter = new KMFilter();
+ QPtrList<KMFilterAction>* pipeFilterActions = pipeFilter->actions();
+ KMFilterAction* pipeFilterAction = dict["filter app"]->create();
+ pipeFilterAction->argsFromString( (*it).getDetectCmd() );
+ pipeFilterActions->append( pipeFilterAction );
+ KMSearchPattern* pipeFilterPattern = pipeFilter->pattern();
+ if ( replaceExistingFilters )
+ pipeFilterPattern->setName( (*it).getFilterName() );
+ else
+ pipeFilterPattern->setName( uniqueNameFor( (*it).getFilterName() ) );
+ pipeFilterPattern->append( KMSearchRule::createInstance( "<size>",
+ KMSearchRule::FuncIsLessOrEqual, "256000" ) );
+ pipeFilter->setApplyOnOutbound( false);
+ pipeFilter->setApplyOnInbound();
+ pipeFilter->setApplyOnExplicit();
+ pipeFilter->setStopProcessingHere( false );
+ pipeFilter->setConfigureShortcut( false );
+
+ filterList.append( pipeFilter );
+ }
+ }
+
+ // Sort out spam depending on header fields set by the tools
+ KMFilter* spamFilter = new KMFilter();
+ QPtrList<KMFilterAction>* spamFilterActions = spamFilter->actions();
+ if ( mSpamRulesPage->moveSpamSelected() )
+ {
+ KMFilterAction* spamFilterAction1 = dict["transfer"]->create();
+ spamFilterAction1->argsFromString( mSpamRulesPage->selectedSpamFolderName() );
+ spamFilterActions->append( spamFilterAction1 );
+ }
+ KMFilterAction* spamFilterAction2 = dict["set status"]->create();
+ spamFilterAction2->argsFromString( "P" ); // Spam
+ spamFilterActions->append( spamFilterAction2 );
+ if ( mSpamRulesPage->markAsReadSelected() ) {
+ KMFilterAction* spamFilterAction3 = dict["set status"]->create();
+ spamFilterAction3->argsFromString( "R" ); // Read
+ spamFilterActions->append( spamFilterAction3 );
+ }
+ KMSearchPattern* spamFilterPattern = spamFilter->pattern();
+ if ( replaceExistingFilters )
+ spamFilterPattern->setName( i18n( "Spam handling" ) );
+ else
+ spamFilterPattern->setName( uniqueNameFor( i18n( "Spam handling" ) ) );
+ spamFilterPattern->setOp( KMSearchPattern::OpOr );
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) )
+ {
+ if ( (*it).isSpamTool() )
+ {
+ const QCString header = (*it).getDetectionHeader().ascii();
+ const QString & pattern = (*it).getDetectionPattern();
+ if ( (*it).isUseRegExp() )
+ spamFilterPattern->append(
+ KMSearchRule::createInstance( header,
+ KMSearchRule::FuncRegExp, pattern ) );
+ else
+ spamFilterPattern->append(
+ KMSearchRule::createInstance( header,
+ KMSearchRule::FuncContains, pattern ) );
+ }
+ }
+ }
+ spamFilter->setApplyOnOutbound( false);
+ spamFilter->setApplyOnInbound();
+ spamFilter->setApplyOnExplicit();
+ spamFilter->setStopProcessingHere( true );
+ spamFilter->setConfigureShortcut( false );
+ filterList.append( spamFilter );
+
+ if ( mSpamRulesPage->moveUnsureSelected() )
+ {
+ // Sort out messages classified as unsure
+ bool atLeastOneUnsurePattern = false;
+ KMFilter* unsureFilter = new KMFilter();
+ QPtrList<KMFilterAction>* unsureFilterActions = unsureFilter->actions();
+ KMFilterAction* unsureFilterAction1 = dict["transfer"]->create();
+ unsureFilterAction1->argsFromString( mSpamRulesPage->selectedUnsureFolderName() );
+ unsureFilterActions->append( unsureFilterAction1 );
+ KMSearchPattern* unsureFilterPattern = unsureFilter->pattern();
+ if ( replaceExistingFilters )
+ unsureFilterPattern->setName( i18n( "Semi spam (unsure) handling" ) );
+ else
+ unsureFilterPattern->setName( uniqueNameFor( i18n( "Semi spam (unsure) handling" ) ) );
+ unsureFilterPattern->setOp( KMSearchPattern::OpOr );
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) )
+ {
+ if ( (*it).isSpamTool() && (*it).hasTristateDetection())
+ {
+ atLeastOneUnsurePattern = true;
+ const QCString header = (*it).getDetectionHeader().ascii();
+ const QString & pattern = (*it).getDetectionPattern2();
+ if ( (*it).isUseRegExp() )
+ unsureFilterPattern->append(
+ KMSearchRule::createInstance( header,
+ KMSearchRule::FuncRegExp, pattern ) );
+ else
+ unsureFilterPattern->append(
+ KMSearchRule::createInstance( header,
+ KMSearchRule::FuncContains, pattern ) );
+ }
+ }
+ }
+ unsureFilter->setApplyOnOutbound( false);
+ unsureFilter->setApplyOnInbound();
+ unsureFilter->setApplyOnExplicit();
+ unsureFilter->setStopProcessingHere( true );
+ unsureFilter->setConfigureShortcut( false );
+
+ if ( atLeastOneUnsurePattern )
+ filterList.append( unsureFilter );
+ else
+ delete unsureFilter;
+ }
+
+ // Classify messages manually as Spam
+ KMFilter* classSpamFilter = new KMFilter();
+ classSpamFilter->setIcon( "mail_spam" );
+ QPtrList<KMFilterAction>* classSpamFilterActions = classSpamFilter->actions();
+ KMFilterAction* classSpamFilterActionFirst = dict["set status"]->create();
+ classSpamFilterActionFirst->argsFromString( "P" );
+ classSpamFilterActions->append( classSpamFilterActionFirst );
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() )
+ && (*it).useBayesFilter() && !(*it).isDetectionOnly() )
+ {
+ KMFilterAction* classSpamFilterAction = dict["execute"]->create();
+ classSpamFilterAction->argsFromString( (*it).getSpamCmd() );
+ classSpamFilterActions->append( classSpamFilterAction );
+ }
+ }
+ if ( mSpamRulesPage->moveSpamSelected() )
+ {
+ KMFilterAction* classSpamFilterActionLast = dict["transfer"]->create();
+ classSpamFilterActionLast->argsFromString( mSpamRulesPage->selectedSpamFolderName() );
+ classSpamFilterActions->append( classSpamFilterActionLast );
+ }
+
+ KMSearchPattern* classSpamFilterPattern = classSpamFilter->pattern();
+ if ( replaceExistingFilters )
+ classSpamFilterPattern->setName( i18n( "Classify as spam" ) );
+ else
+ classSpamFilterPattern->setName( uniqueNameFor( i18n( "Classify as spam" ) ) );
+ classSpamFilterPattern->append( KMSearchRule::createInstance( "<size>",
+ KMSearchRule::FuncIsGreaterOrEqual, "0" ) );
+ classSpamFilter->setApplyOnOutbound( false);
+ classSpamFilter->setApplyOnInbound( false );
+ classSpamFilter->setApplyOnExplicit( false );
+ classSpamFilter->setStopProcessingHere( true );
+ classSpamFilter->setConfigureShortcut( true );
+ classSpamFilter->setConfigureToolbar( true );
+ filterList.append( classSpamFilter );
+
+ // Classify messages manually as not Spam / as Ham
+ KMFilter* classHamFilter = new KMFilter();
+ classHamFilter->setIcon( "mail_ham" );
+ QPtrList<KMFilterAction>* classHamFilterActions = classHamFilter->actions();
+ KMFilterAction* classHamFilterActionFirst = dict["set status"]->create();
+ classHamFilterActionFirst->argsFromString( "H" );
+ classHamFilterActions->append( classHamFilterActionFirst );
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() )
+ && (*it).useBayesFilter() && !(*it).isDetectionOnly() )
+ {
+ KMFilterAction* classHamFilterAction = dict["execute"]->create();
+ classHamFilterAction->argsFromString( (*it).getHamCmd() );
+ classHamFilterActions->append( classHamFilterAction );
+ }
+ }
+ KMSearchPattern* classHamFilterPattern = classHamFilter->pattern();
+ if ( replaceExistingFilters )
+ classHamFilterPattern->setName( i18n( "Classify as NOT spam" ) );
+ else
+ classHamFilterPattern->setName( uniqueNameFor( i18n( "Classify as NOT spam" ) ) );
+ classHamFilterPattern->append( KMSearchRule::createInstance( "<size>",
+ KMSearchRule::FuncIsGreaterOrEqual, "0" ) );
+ classHamFilter->setApplyOnOutbound( false);
+ classHamFilter->setApplyOnInbound( false );
+ classHamFilter->setApplyOnExplicit( false );
+ classHamFilter->setStopProcessingHere( true );
+ classHamFilter->setConfigureShortcut( true );
+ classHamFilter->setConfigureToolbar( true );
+ filterList.append( classHamFilter );
+ }
+
+ /* Now that all the filters have been added to the list, tell
+ * the filter manager about it. That will emit filterListUpdate
+ * which will result in the filter list in kmmainwidget being
+ * initialized. This should happend only once. */
+ if ( !filterList.isEmpty() )
+ KMKernel::self()->filterMgr()->appendFilters(
+ filterList, replaceExistingFilters );
+
+ QDialog::accept();
+}
+
+
+void AntiSpamWizard::checkProgramsSelections()
+{
+ bool status = false;
+ bool supportUnsure = false;
+
+ mSpamToolsUsed = false;
+ mVirusToolsUsed = false;
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) )
+ {
+ status = true;
+ if ( (*it).isSpamTool() ) {
+ mSpamToolsUsed = true;
+ if ( (*it).hasTristateDetection() )
+ supportUnsure = true;
+ }
+ if ( (*it).isVirusTool() )
+ mVirusToolsUsed = true;
+ }
+ }
+
+ if ( mMode == AntiSpam ) {
+ mSpamRulesPage->allowUnsureFolderSelection( supportUnsure );
+ slotBuildSummary();
+ }
+
+ if ( ( mMode == AntiVirus ) && mVirusToolsUsed )
+ checkVirusRulesSelections();
+
+ setNextEnabled( mInfoPage, status );
+}
+
+
+void AntiSpamWizard::checkVirusRulesSelections()
+{
+ setFinishEnabled( mVirusRulesPage, anyVirusOptionChecked() );
+}
+
+
+void AntiSpamWizard::checkToolAvailability()
+{
+ // this can take some time to find the tools
+ KCursorSaver busy( KBusyPtr::busy() );
+
+ bool found = false;
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ QString text( i18n("Scanning for %1...").arg( (*it).getId() ) );
+ mInfoPage->setScanProgressText( text );
+ if ( (*it).isSpamTool() && (*it).isServerBased() ) {
+ // check the configured account for pattern in <server>
+ QString pattern = (*it).getServerPattern();
+ kdDebug(5006) << "Testing for server pattern:" << pattern << endl;
+
+ AccountManager* mgr = kmkernel->acctMgr();
+ KMAccount* account = mgr->first();
+ while ( account ) {
+ if ( account->type() == "pop" || account->type().contains( "imap" ) ) {
+ const NetworkAccount * n = dynamic_cast<const NetworkAccount*>( account );
+ if ( n && n->host().lower().contains( pattern.lower() ) ) {
+ mInfoPage->addAvailableTool( (*it).getVisibleName() );
+ found = true;
+ }
+ }
+ account = mgr->next();
+ }
+ }
+ else {
+ // check the availability of the application
+ KApplication::kApplication()->processEvents( 200 );
+ if ( !checkForProgram( (*it).getExecutable() ) ) {
+ mInfoPage->addAvailableTool( (*it).getVisibleName() );
+ found = true;
+ }
+ }
+ }
+ if ( found )
+ mInfoPage->setScanProgressText( ( mMode == AntiSpam )
+ ? i18n("Scanning for anti-spam tools finished.")
+ : i18n("Scanning for anti-virus tools finished.") );
+ else
+ mInfoPage->setScanProgressText( ( mMode == AntiSpam )
+ ? i18n("<p>No spam detection tools have been found. "
+ "Install your spam detection software and "
+ "re-run this wizard.</p>")
+ : i18n("Scanning complete. No anti-virus tools found.") );
+}
+
+
+void AntiSpamWizard::slotHelpClicked()
+{
+ if ( mMode == AntiSpam )
+ kapp->invokeHelp( "the-anti-spam-wizard", "kmail" );
+ else
+ kapp->invokeHelp( "the-anti-virus-wizard", "kmail" );
+}
+
+
+void AntiSpamWizard::slotBuildSummary()
+{
+ QString text;
+ QString newFilters;
+ QString replaceFilters;
+
+ if ( mMode == AntiVirus ) {
+ text = ""; // TODO add summary for the virus part
+ }
+ else { // AntiSpam mode
+ if ( mSpamRulesPage->markAsReadSelected() )
+ text = i18n( "<p>Messages classified as spam are marked as read." );
+ else
+ text = i18n( "<p>Messages classified as spam are not marked as read." );
+
+ if ( mSpamRulesPage->moveSpamSelected() )
+ text += i18n( "<br>Spam messages are moved into the folder named <i>" )
+ + mSpamRulesPage->selectedSpamFolderName() + "</i>.</p>";
+ else
+ text += i18n( "<br>Spam messages are not moved into a certain folder.</p>" );
+
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) &&
+ (*it).isSpamTool() && !(*it).isDetectionOnly() ) {
+ sortFilterOnExistance( (*it).getFilterName(), newFilters, replaceFilters );
+ }
+ }
+ sortFilterOnExistance( i18n( "Spam handling" ), newFilters, replaceFilters );
+
+ // The need for a andling of status "probably spam" depends on the tools chosen
+ if ( mSpamRulesPage->moveUnsureSelected() ) {
+ bool atLeastOneUnsurePattern = false;
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( mInfoPage->isProgramSelected( (*it).getVisibleName() ) ) {
+ if ( (*it).isSpamTool() && (*it).hasTristateDetection())
+ atLeastOneUnsurePattern = true;
+ }
+ }
+ if ( atLeastOneUnsurePattern ) {
+ sortFilterOnExistance( i18n( "Semi spam (unsure) handling" ),
+ newFilters, replaceFilters );
+ text += i18n( "<p>The folder for messages classified as unsure (probably spam) is <i>" )
+ + mSpamRulesPage->selectedUnsureFolderName() + "</i>.</p>";
+ }
+ }
+
+ // Manual classification via toolbar icon / manually applied filter action
+ sortFilterOnExistance( i18n( "Classify as spam" ),
+ newFilters, replaceFilters );
+ sortFilterOnExistance( i18n( "Classify as NOT spam" ),
+ newFilters, replaceFilters );
+
+ // Show the filters in the summary
+ if ( !newFilters.isEmpty() )
+ text += i18n( "<p>The wizard will create the following filters:<ul>" )
+ + newFilters + "</ul></p>";
+ if ( !replaceFilters.isEmpty() )
+ text += i18n( "<p>The wizard will replace the following filters:<ul>" )
+ + replaceFilters + "</ul></p>";
+ }
+
+ mSummaryPage->setSummaryText( text );
+}
+
+
+int AntiSpamWizard::checkForProgram( const QString &executable )
+{
+ kdDebug(5006) << "Testing for executable:" << executable << endl;
+ KProcess process;
+ process << executable;
+ process.setUseShell( true );
+ process.start( KProcess::Block );
+ return process.exitStatus();
+}
+
+
+bool AntiSpamWizard::anyVirusOptionChecked()
+{
+ return ( mVirusRulesPage->moveRulesSelected()
+ || mVirusRulesPage->pipeRulesSelected() );
+}
+
+
+const QString AntiSpamWizard::uniqueNameFor( const QString & name )
+{
+ return KMKernel::self()->filterMgr()->createUniqueName( name );
+}
+
+
+void AntiSpamWizard::sortFilterOnExistance(
+ const QString & intendedFilterName,
+ QString & newFilters, QString & replaceFilters )
+{
+ if ( uniqueNameFor( intendedFilterName ) == intendedFilterName )
+ newFilters += "<li>" + intendedFilterName + "</li>";
+ else
+ replaceFilters += "<li>" + intendedFilterName + "</li>";
+}
+
+
+//---------------------------------------------------------------------------
+AntiSpamWizard::SpamToolConfig::SpamToolConfig( QString toolId,
+ int configVersion, int prio, QString name, QString exec,
+ QString url, QString filter, QString detection, QString spam, QString ham,
+ QString header, QString pattern, QString pattern2, QString serverPattern,
+ bool detectionOnly, bool regExp, bool bayesFilter, bool tristateDetection,
+ WizardMode type )
+ : mId( toolId ), mVersion( configVersion ), mPrio( prio ),
+ mVisibleName( name ), mExecutable( exec ), mWhatsThisText( url ),
+ mFilterName( filter ), mDetectCmd( detection ), mSpamCmd( spam ),
+ mHamCmd( ham ), mDetectionHeader( header ), mDetectionPattern( pattern ),
+ mDetectionPattern2( pattern2 ), mServerPattern( serverPattern ),
+ mDetectionOnly( detectionOnly ),
+ mUseRegExp( regExp ), mSupportsBayesFilter( bayesFilter ),
+ mSupportsUnsure( tristateDetection ), mType( type )
+{
+}
+
+
+bool AntiSpamWizard::SpamToolConfig::isServerBased() const
+{
+ return !mServerPattern.isEmpty();
+}
+
+
+//---------------------------------------------------------------------------
+AntiSpamWizard::ConfigReader::ConfigReader( WizardMode mode,
+ QValueList<SpamToolConfig> & configList )
+ : mToolList( configList ),
+ mMode( mode )
+{
+ if ( mMode == AntiSpam )
+ mConfig = new KConfig( "kmail.antispamrc", true );
+ else
+ mConfig = new KConfig( "kmail.antivirusrc", true );
+}
+
+AntiSpamWizard::ConfigReader::~ConfigReader( )
+{
+ delete mConfig;
+}
+
+
+void AntiSpamWizard::ConfigReader::readAndMergeConfig()
+{
+ QString groupName = ( mMode == AntiSpam )
+ ? QString("Spamtool #%1")
+ : QString("Virustool #%1");
+ // read the configuration from the global config file
+ mConfig->setReadDefaults( true );
+ KConfigGroup general( mConfig, "General" );
+ int registeredTools = general.readNumEntry( "tools", 0 );
+ for (int i = 1; i <= registeredTools; i++)
+ {
+ KConfigGroup toolConfig( mConfig, groupName.arg( i ) );
+ if( !toolConfig.readBoolEntry( "HeadersOnly", false ) )
+ mToolList.append( readToolConfig( toolConfig ) );
+ }
+
+ // read the configuration from the user config file
+ // and merge newer config data
+ mConfig->setReadDefaults( false );
+ KConfigGroup user_general( mConfig, "General" );
+ int user_registeredTools = user_general.readNumEntry( "tools", 0 );
+ for (int i = 1; i <= user_registeredTools; i++)
+ {
+ KConfigGroup toolConfig( mConfig, groupName.arg( i ) );
+ if( !toolConfig.readBoolEntry( "HeadersOnly", false ) )
+ mergeToolConfig( readToolConfig( toolConfig ) );
+ }
+ // Make sure to have add least one tool listed even when the
+ // config file was not found or whatever went wrong
+ // Currently only works for spam tools
+ if ( mMode == AntiSpam ) {
+ if ( registeredTools < 1 && user_registeredTools < 1 )
+ mToolList.append( createDummyConfig() );
+ sortToolList();
+ }
+}
+
+
+AntiSpamWizard::SpamToolConfig
+ AntiSpamWizard::ConfigReader::readToolConfig( KConfigGroup & configGroup )
+{
+ QString id = configGroup.readEntry( "Ident" );
+ int version = configGroup.readNumEntry( "Version" );
+#ifndef NDEBUG
+ kdDebug(5006) << "Found predefined tool: " << id << endl;
+ kdDebug(5006) << "With config version : " << version << endl;
+#endif
+ int prio = configGroup.readNumEntry( "Priority", 1 );
+ QString name = configGroup.readEntry( "VisibleName" );
+ QString executable = configGroup.readEntry( "Executable" );
+ QString url = configGroup.readEntry( "URL" );
+ QString filterName = configGroup.readEntry( "PipeFilterName" );
+ QString detectCmd = configGroup.readEntry( "PipeCmdDetect" );
+ QString spamCmd = configGroup.readEntry( "ExecCmdSpam" );
+ QString hamCmd = configGroup.readEntry( "ExecCmdHam" );
+ QString header = configGroup.readEntry( "DetectionHeader" );
+ QString pattern = configGroup.readEntry( "DetectionPattern" );
+ QString pattern2 = configGroup.readEntry( "DetectionPattern2" );
+ QString serverPattern = configGroup.readEntry( "ServerPattern" );
+ bool detectionOnly = configGroup.readBoolEntry( "DetectionOnly", false );
+ bool useRegExp = configGroup.readBoolEntry( "UseRegExp" );
+ bool supportsBayes = configGroup.readBoolEntry( "SupportsBayes", false );
+ bool supportsUnsure = configGroup.readBoolEntry( "SupportsUnsure", false );
+ return SpamToolConfig( id, version, prio, name, executable, url,
+ filterName, detectCmd, spamCmd, hamCmd,
+ header, pattern, pattern2, serverPattern,
+ detectionOnly, useRegExp,
+ supportsBayes, supportsUnsure, mMode );
+}
+
+
+AntiSpamWizard::SpamToolConfig AntiSpamWizard::ConfigReader::createDummyConfig()
+{
+ return SpamToolConfig( "spamassassin", 0, 1,
+ "SpamAssassin", "spamassassin -V",
+ "http://spamassassin.org", "SpamAssassin Check",
+ "spamassassin -L",
+ "sa-learn -L --spam --no-rebuild --single",
+ "sa-learn -L --ham --no-rebuild --single",
+ "X-Spam-Flag", "yes", "", "",
+ false, false, true, false, AntiSpam );
+}
+
+
+void AntiSpamWizard::ConfigReader::mergeToolConfig( AntiSpamWizard::SpamToolConfig config )
+{
+ bool found = false;
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+#ifndef NDEBUG
+ kdDebug(5006) << "Check against tool: " << (*it).getId() << endl;
+ kdDebug(5006) << "Against version : " << (*it).getVersion() << endl;
+#endif
+ if ( (*it).getId() == config.getId() )
+ {
+ found = true;
+ if ( (*it).getVersion() < config.getVersion() )
+ {
+#ifndef NDEBUG
+ kdDebug(5006) << "Replacing config ..." << endl;
+#endif
+ mToolList.remove( it );
+ mToolList.append( config );
+ }
+ break;
+ }
+ }
+ if ( !found )
+ mToolList.append( config );
+}
+
+
+void AntiSpamWizard::ConfigReader::sortToolList()
+{
+ QValueList<SpamToolConfig> tmpList;
+ SpamToolConfig config;
+
+ while ( !mToolList.isEmpty() ) {
+ QValueListIterator<SpamToolConfig> highest;
+ int priority = 0; // ascending
+ for ( QValueListIterator<SpamToolConfig> it = mToolList.begin();
+ it != mToolList.end(); ++it ) {
+ if ( (*it).getPrio() > priority ) {
+ priority = (*it).getPrio();
+ highest = it;
+ }
+ }
+ config = (*highest);
+ tmpList.append( config );
+ mToolList.remove( highest );
+ }
+ for ( QValueListIterator<SpamToolConfig> it = tmpList.begin();
+ it != tmpList.end(); ++it ) {
+ mToolList.append( (*it) );
+ }
+}
+
+
+//---------------------------------------------------------------------------
+ASWizPage::ASWizPage( QWidget * parent, const char * name,
+ const QString *bannerName )
+ : QWidget( parent, name )
+{
+ QString banner = "kmwizard.png";
+ if ( bannerName && !bannerName->isEmpty() )
+ banner = *bannerName;
+
+ mLayout = new QHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
+ mPixmap = new QPixmap( UserIcon(banner) );
+ mBannerLabel = new QLabel( this );
+ mBannerLabel->setPixmap( *mPixmap );
+ mBannerLabel->setScaledContents( false );
+ mBannerLabel->setFrameShape( QFrame::StyledPanel );
+ mBannerLabel->setFrameShadow( QFrame::Sunken );
+
+ mLayout->addWidget( mBannerLabel );
+ mLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
+}
+
+
+//---------------------------------------------------------------------------
+ASWizInfoPage::ASWizInfoPage( AntiSpamWizard::WizardMode mode,
+ QWidget * parent, const char * name )
+ : ASWizPage( parent, name )
+{
+ QBoxLayout * layout = new QVBoxLayout( mLayout );
+
+ mIntroText = new QLabel( this );
+ mIntroText->setText(
+ ( mode == AntiSpamWizard::AntiSpam )
+ ? i18n(
+ "The wizard will search for any tools to do spam detection\n"
+ "and setup KMail to work with them."
+ )
+ : i18n(
+ "<p>Here you can get some assistance in setting up KMail's filter "
+ "rules to use some commonly-known anti-virus tools.</p>"
+ "<p>The wizard can detect those tools on your computer as "
+ "well as create filter rules to classify messages using these "
+ "tools and to separate messages containing viruses. "
+ "The wizard will not take any existing filter "
+ "rules into consideration: it will always append the new rules.</p>"
+ "<p><b>Warning:</b> As KMail appears to be frozen during the scan of the "
+ "messages for viruses, you may encounter problems with "
+ "the responsiveness of KMail because anti-virus tool "
+ "operations are usually time consuming; please consider "
+ "deleting the filter rules created by the wizard to get "
+ "back to the former behavior."
+ ) );
+ layout->addWidget( mIntroText );
+
+ mScanProgressText = new QLabel( this );
+ mScanProgressText->setText( "" ) ;
+ layout->addWidget( mScanProgressText );
+
+ mToolsList = new KListBox( this );
+ mToolsList->hide();
+ mToolsList->setSelectionMode( QListBox::Multi );
+ mToolsList->setRowMode( QListBox::FixedNumber );
+ mToolsList->setRowMode( 10 );
+ layout->addWidget( mToolsList );
+ connect( mToolsList, SIGNAL(selectionChanged()),
+ this, SLOT(processSelectionChange(void)) );
+
+ mSelectionHint = new QLabel( this );
+ mSelectionHint->setText( "" );
+ layout->addWidget( mSelectionHint );
+
+ layout->addStretch();
+}
+
+
+void ASWizInfoPage::setScanProgressText( const QString &toolName )
+{
+ mScanProgressText->setText( toolName );
+}
+
+
+void ASWizInfoPage::addAvailableTool( const QString &visibleName )
+{
+ QString listName = visibleName;
+ mToolsList->insertItem( listName );
+ if ( !mToolsList->isVisible() )
+ {
+ mToolsList->show();
+ mToolsList->setSelected( 0, true );
+ mSelectionHint->setText( i18n("<p>Please select the tools to be used "
+ "for the detection and go "
+ "to the next page.</p>") );
+ }
+}
+
+bool ASWizInfoPage::isProgramSelected( const QString &visibleName )
+{
+ QString listName = visibleName;
+ return mToolsList->isSelected( mToolsList->findItem( listName ) );
+}
+
+
+void ASWizInfoPage::processSelectionChange()
+{
+ emit selectionChanged();
+}
+
+
+//---------------------------------------------------------------------------
+ASWizSpamRulesPage::ASWizSpamRulesPage( QWidget * parent, const char * name,
+ KMFolderTree * mainFolderTree )
+ : ASWizPage( parent, name )
+{
+ QVBoxLayout *layout = new QVBoxLayout( mLayout );
+
+ mMarkRules = new QCheckBox( i18n("&Mark detected spam messages as read"), this );
+ QWhatsThis::add( mMarkRules,
+ i18n( "Mark messages which have been classified as spam as read.") );
+ layout->addWidget( mMarkRules);
+
+ mMoveSpamRules = new QCheckBox( i18n("Move &known spam to:"), this );
+ QWhatsThis::add( mMoveSpamRules,
+ i18n( "The default folder for spam messages is the trash folder, "
+ "but you may change that in the folder view below.") );
+ layout->addWidget( mMoveSpamRules );
+
+ mFolderReqForSpamFolder = new FolderRequester( this, mainFolderTree );
+ mFolderReqForSpamFolder->setFolder( "trash" );
+ mFolderReqForSpamFolder->setMustBeReadWrite( true );
+ mFolderReqForSpamFolder->setShowOutbox( false );
+ mFolderReqForSpamFolder->setShowImapFolders( false );
+
+ QHBoxLayout *hLayout1 = new QHBoxLayout( layout );
+ hLayout1->addSpacing( KDialog::spacingHint() * 3 );
+ hLayout1->addWidget( mFolderReqForSpamFolder );
+
+ mMoveUnsureRules = new QCheckBox( i18n("Move &probable spam to:"), this );
+ QWhatsThis::add( mMoveUnsureRules,
+ i18n( "The default folder is the inbox folder, but you may change that "
+ "in the folder view below.<p>"
+ "Not all tools support a classification as unsure. If you haven't "
+ "selected a capable tool, you can't select a folder as well.") );
+ layout->addWidget( mMoveUnsureRules );
+
+ mFolderReqForUnsureFolder = new FolderRequester( this, mainFolderTree );
+ mFolderReqForUnsureFolder->setFolder( "inbox" );
+ mFolderReqForUnsureFolder->setMustBeReadWrite( true );
+ mFolderReqForUnsureFolder->setShowOutbox( false );
+ mFolderReqForUnsureFolder->setShowImapFolders( false );
+
+ QHBoxLayout *hLayout2 = new QHBoxLayout( layout );
+ hLayout2->addSpacing( KDialog::spacingHint() * 3 );
+ hLayout2->addWidget( mFolderReqForUnsureFolder );
+
+ layout->addStretch();
+
+ connect( mMarkRules, SIGNAL(clicked()),
+ this, SLOT(processSelectionChange(void)) );
+ connect( mMoveSpamRules, SIGNAL(clicked()),
+ this, SLOT(processSelectionChange(void)) );
+ connect( mMoveUnsureRules, SIGNAL(clicked()),
+ this, SLOT(processSelectionChange(void)) );
+ connect( mFolderReqForSpamFolder, SIGNAL(folderChanged(KMFolder*)),
+ this, SLOT(processSelectionChange(KMFolder*)) );
+ connect( mFolderReqForUnsureFolder, SIGNAL(folderChanged(KMFolder*)),
+ this, SLOT(processSelectionChange(KMFolder*)) );
+
+ mMarkRules->setChecked( true );
+ mMoveSpamRules->setChecked( true );
+}
+
+
+bool ASWizSpamRulesPage::markAsReadSelected() const
+{
+ return mMarkRules->isChecked();
+}
+
+
+bool ASWizSpamRulesPage::moveSpamSelected() const
+{
+ return mMoveSpamRules->isChecked();
+}
+
+
+bool ASWizSpamRulesPage::moveUnsureSelected() const
+{
+ return mMoveUnsureRules->isChecked();
+}
+
+
+QString ASWizSpamRulesPage::selectedSpamFolderName() const
+{
+ QString name = "trash";
+ if ( mFolderReqForSpamFolder->folder() )
+ name = mFolderReqForSpamFolder->folder()->idString();
+ return name;
+}
+
+
+QString ASWizSpamRulesPage::selectedUnsureFolderName() const
+{
+ QString name = "inbox";
+ if ( mFolderReqForUnsureFolder->folder() )
+ name = mFolderReqForUnsureFolder->folder()->idString();
+ return name;
+}
+
+
+void ASWizSpamRulesPage::processSelectionChange()
+{
+ mFolderReqForSpamFolder->setEnabled( mMoveSpamRules->isChecked() );
+ mFolderReqForUnsureFolder->setEnabled( mMoveUnsureRules->isChecked() );
+ emit selectionChanged();
+}
+
+
+void ASWizSpamRulesPage::processSelectionChange( KMFolder* )
+{
+ processSelectionChange();
+}
+
+
+void ASWizSpamRulesPage::allowUnsureFolderSelection( bool enabled )
+{
+ mMoveUnsureRules->setEnabled( enabled );
+ mMoveUnsureRules->setShown( enabled );
+ mFolderReqForUnsureFolder->setEnabled( enabled );
+ mFolderReqForUnsureFolder->setShown( enabled );
+}
+
+
+//---------------------------------------------------------------------------
+ASWizVirusRulesPage::ASWizVirusRulesPage( QWidget * parent, const char * name,
+ KMFolderTree * mainFolderTree )
+ : ASWizPage( parent, name )
+{
+ QGridLayout *grid = new QGridLayout( mLayout, 5, 1, KDialog::spacingHint() );
+
+ mPipeRules = new QCheckBox( i18n("Check messages using the anti-virus tools"), this );
+ QWhatsThis::add( mPipeRules,
+ i18n( "Let the anti-virus tools check your messages. The wizard "
+ "will create appropriate filters. The messages are usually "
+ "marked by the tools so that following filters can react "
+ "on this and, for example, move virus messages to a special folder.") );
+ grid->addWidget( mPipeRules, 0, 0 );
+
+ mMoveRules = new QCheckBox( i18n("Move detected viral messages to the selected folder"), this );
+ QWhatsThis::add( mMoveRules,
+ i18n( "A filter to detect messages classified as virus-infected and to move "
+ "those messages into a predefined folder is created. The "
+ "default folder is the trash folder, but you may change that "
+ "in the folder view.") );
+ grid->addWidget( mMoveRules, 1, 0 );
+
+ mMarkRules = new QCheckBox( i18n("Additionally, mark detected viral messages as read"), this );
+ mMarkRules->setEnabled( false );
+ QWhatsThis::add( mMarkRules,
+ i18n( "Mark messages which have been classified as "
+ "virus-infected as read, as well as moving them "
+ "to the selected folder.") );
+ grid->addWidget( mMarkRules, 2, 0 );
+
+ QString s = "trash";
+ mFolderTree = new SimpleFolderTree( this, mainFolderTree, s, true );
+ grid->addWidget( mFolderTree, 3, 0 );
+
+ connect( mPipeRules, SIGNAL(clicked()),
+ this, SLOT(processSelectionChange(void)) );
+ connect( mMoveRules, SIGNAL(clicked()),
+ this, SLOT(processSelectionChange(void)) );
+ connect( mMarkRules, SIGNAL(clicked()),
+ this, SLOT(processSelectionChange(void)) );
+ connect( mMoveRules, SIGNAL( toggled( bool ) ),
+ mMarkRules, SLOT( setEnabled( bool ) ) );
+}
+
+bool ASWizVirusRulesPage::pipeRulesSelected() const
+{
+ return mPipeRules->isChecked();
+}
+
+
+bool ASWizVirusRulesPage::moveRulesSelected() const
+{
+ return mMoveRules->isChecked();
+}
+
+bool ASWizVirusRulesPage::markReadRulesSelected() const
+{
+ return mMarkRules->isChecked();
+}
+
+
+QString ASWizVirusRulesPage::selectedFolderName() const
+{
+ QString name = "trash";
+ if ( mFolderTree->folder() )
+ name = mFolderTree->folder()->idString();
+ return name;
+}
+
+void ASWizVirusRulesPage::processSelectionChange()
+{
+ emit selectionChanged();
+}
+
+
+//---------------------------------------------------------------------------
+ASWizSummaryPage::ASWizSummaryPage( QWidget * parent, const char * name )
+ : ASWizPage( parent, name )
+{
+ QBoxLayout * layout = new QVBoxLayout( mLayout );
+
+ mSummaryText = new QLabel( this );
+ layout->addWidget( mSummaryText );
+ layout->addStretch();
+}
+
+
+void ASWizSummaryPage::setSummaryText( const QString & text )
+{
+ mSummaryText->setText( text );
+}
+
+
+#include "antispamwizard.moc"
diff --git a/kmail/antispamwizard.h b/kmail/antispamwizard.h
new file mode 100644
index 00000000..745edae6
--- /dev/null
+++ b/kmail/antispamwizard.h
@@ -0,0 +1,398 @@
+/* -*- mode: C++ -*-
+ This file is part of KMail.
+ Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef KMAIL_ANTISPAMWIZARD_H
+#define KMAIL_ANTISPAMWIZARD_H
+
+#include <kconfig.h>
+#include <klistbox.h>
+#include <kwizard.h>
+
+#include <qcheckbox.h>
+#include <qdict.h>
+#include <qlayout.h>
+
+class KActionCollection;
+class KMFolder;
+class KMFolderTree;
+class QLabel;
+
+namespace KMail {
+
+ class SimpleFolderTree;
+ class FolderRequester;
+
+ class ASWizInfoPage;
+ class ASWizSpamRulesPage;
+ class ASWizVirusRulesPage;
+ class ASWizSummaryPage;
+
+ //---------------------------------------------------------------------------
+ /**
+ @short KMail anti-spam wizard.
+ @author Andreas Gungl <a.gungl@gmx.de>
+
+ The wizard helps to create filter rules to let KMail operate
+ with external anti-spam tools. The wizard tries to detect the
+ tools, but the user can overide the preselections.
+ Then the user can decide what funtionality shall be supported
+ by the created filter rules.
+ The wizard will append the created filter rules after the
+ last existing rule to keep possible conflicts with existing
+ filter configurations minimal.
+
+ Anti-virus support was added by Fred Emmott <fred87@users.sf.net>
+
+ The configuration for the tools to get checked and set up
+ is read from a config file. The structure of the file is as
+ following:
+ <pre>
+ [General]
+ tools=1
+
+ [Spamtool #1]
+ Ident=spamassassin
+ Version=0
+ Priority=1
+ VisibleName=&Spamassassin
+ Executable=spamassassin -V
+ URL=http://spamassassin.org
+ PipeFilterName=SpamAssassin Check
+ PipeCmdDetect=spamassassin -L
+ ExecCmdSpam=sa-learn --spam --no-rebuild --single
+ ExecCmdHam=sa-learn --ham --no-rebuild --single
+ DetectionHeader=X-Spam-Flag
+ DetectionPattern=yes
+ DetectionPattern2=
+ DetectionOnly=0
+ UseRegExp=0
+ SupportsBayes=1
+ SupportsUnsure=0
+ ServerSided=0
+ type=spam
+ </pre>
+ The name of the config file is kmail.antispamrc
+ and it's expected in the config dir of KDE.
+
+ */
+ class AntiSpamWizard : public KWizard
+ {
+ Q_OBJECT
+
+ public:
+ /** The wizard can be used for setting up anti-spam tools and for
+ setting up anti-virus tools.
+ */
+ enum WizardMode { AntiSpam, AntiVirus };
+
+ /** Constructor that needs to initialize from the main folder tree
+ of KMail.
+ @param mode The mode the wizard should run in.
+ @param parent The parent widget for the wizard.
+ @param mainFolderTree The main folder tree from which the folders
+ are copied to allow the selection of a spam folder in a tree
+ within one of the wizard pages.
+ */
+ AntiSpamWizard( WizardMode mode,
+ QWidget * parent, KMFolderTree * mainFolderTree );
+
+ protected:
+ /**
+ Instances of this class store the settings for one tool as read from
+ the config file. Visible name and What's this text can not get
+ translated!
+ */
+ class SpamToolConfig
+ {
+ public:
+ SpamToolConfig() {}
+ SpamToolConfig( QString toolId, int configVersion, int prio,
+ QString name, QString exec, QString url, QString filter,
+ QString detection, QString spam, QString ham,
+ QString header, QString pattern, QString pattern2,
+ QString serverPattern,
+ bool detectionOnly, bool regExp, bool bayesFilter,
+ bool tristateDetection, WizardMode type );
+
+ int getVersion() const { return mVersion; }
+ int getPrio() const { return mPrio; }
+ QString getId() const { return mId; }
+ QString getVisibleName() const { return mVisibleName; }
+ QString getExecutable() const { return mExecutable; }
+ QString getWhatsThisText() const { return mWhatsThisText; }
+ QString getFilterName() const { return mFilterName; }
+ QString getDetectCmd() const { return mDetectCmd; }
+ QString getSpamCmd() const { return mSpamCmd; }
+ QString getHamCmd() const { return mHamCmd; }
+ QString getDetectionHeader() const { return mDetectionHeader; }
+ QString getDetectionPattern() const { return mDetectionPattern; }
+ QString getDetectionPattern2() const { return mDetectionPattern2; }
+ QString getServerPattern() const { return mServerPattern; }
+ bool isServerBased() const;
+ bool isDetectionOnly() const { return mDetectionOnly; }
+ bool isUseRegExp() const { return mUseRegExp; }
+ bool useBayesFilter() const { return mSupportsBayesFilter; }
+ bool hasTristateDetection() const { return mSupportsUnsure; }
+ WizardMode getType() const { return mType; }
+ // convinience methods for types
+ bool isSpamTool() const { return ( mType == AntiSpam ); }
+ bool isVirusTool() const { return ( mType == AntiVirus ); }
+
+ private:
+ // used to identifiy configs for the same tool
+ QString mId;
+ // The version of the config data, used for merging and
+ // detecting newer configs
+ int mVersion;
+ // the priority of the tool in the list presented to the user
+ int mPrio;
+ // the name as shown by the checkbox in the dialog page
+ QString mVisibleName;
+ // the command to check the existance of the tool
+ QString mExecutable;
+ // the What's This help text (e.g. url for the tool)
+ QString mWhatsThisText;
+ // name for the created filter in the filter list
+ QString mFilterName;
+ // pipe through cmd used to detect spam messages
+ QString mDetectCmd;
+ // pipe through cmd to let the tool learn a spam message
+ QString mSpamCmd;
+ // pipe through cmd to let the tool learn a ham message
+ QString mHamCmd;
+ // by which header are messages marked as spam
+ QString mDetectionHeader;
+ // what header pattern is used to mark spam messages
+ QString mDetectionPattern;
+ // what header pattern is used to mark unsure messages
+ QString mDetectionPattern2;
+ // what header pattern is used in the account to check for a certain server
+ QString mServerPattern;
+ // filter cannot search actively but relies on pattern by regExp or contain rule
+ bool mDetectionOnly;
+ // filter searches for the pattern by regExp or contain rule
+ bool mUseRegExp;
+ // can the tool learn spam and ham, has it a bayesian algorithm
+ bool mSupportsBayesFilter;
+ // differentiate between ham, spam and a third "unsure" state
+ bool mSupportsUnsure;
+ // Is the tool AntiSpam or AntiVirus
+ WizardMode mType;
+ };
+
+ /**
+ Instances of this class control reading the configuration of the
+ anti-spam tools from global and user config files as well as the
+ merging of different config versions.
+ */
+ class ConfigReader
+ {
+ public:
+ ConfigReader( WizardMode mode,
+ QValueList<SpamToolConfig> & configList );
+ ~ConfigReader( );
+
+ QValueList<SpamToolConfig> & getToolList() { return mToolList; }
+
+ void readAndMergeConfig();
+
+ private:
+ QValueList<SpamToolConfig> & mToolList;
+ KConfig *mConfig;
+ WizardMode mMode;
+
+ SpamToolConfig readToolConfig( KConfigGroup & configGroup );
+ SpamToolConfig createDummyConfig();
+
+ void mergeToolConfig( SpamToolConfig config );
+ void sortToolList();
+ };
+
+ /** Evaluate the settings made and create the appropriate filter rules. */
+ void accept();
+
+ protected slots:
+ /** Modify the status of the wizard to reflect the selection of spam tools. */
+ void checkProgramsSelections();
+ /** Modify the status of the wizard to reflect the selected functionality. */
+ void checkVirusRulesSelections();
+ /** Check if the spam tools are available via the PATH */
+ void checkToolAvailability();
+ /** Show a help topic */
+ void slotHelpClicked();
+ /** Create the summary text based on the current settings */
+ void slotBuildSummary();
+
+ private:
+ /* Check for the availability of an executible along the PATH */
+ int checkForProgram( const QString &executable );
+ /* generic checks if any option in a page is checked */
+ bool anyVirusOptionChecked();
+ /* convenience method calling the appropriate filter manager method */
+ const QString uniqueNameFor( const QString & name );
+ /* convenience method to sort out new and existing filters */
+ void sortFilterOnExistance( const QString & intendedFilterName,
+ QString & newFilters,
+ QString & replaceFilters );
+
+ /* The pages in the wizard */
+ ASWizInfoPage * mInfoPage;
+ ASWizSpamRulesPage * mSpamRulesPage;
+ ASWizVirusRulesPage * mVirusRulesPage;
+ ASWizSummaryPage * mSummaryPage;
+
+ /* The configured tools and it's settings to be used in the wizard. */
+ QValueList<SpamToolConfig> mToolList;
+
+ /* Are any spam tools selected? */
+ bool mSpamToolsUsed;
+ /* Are any virus tools selected? */
+ bool mVirusToolsUsed;
+
+ WizardMode mMode;
+ };
+
+
+ //---------------------------------------------------------------------------
+ class ASWizPage : public QWidget
+ {
+ public:
+ ASWizPage( QWidget *parent, const char *name,
+ const QString *bannerName = 0);
+
+ protected:
+ QBoxLayout *mLayout;
+
+ private:
+ QPixmap *mPixmap;
+ QLabel *mBannerLabel;
+ };
+
+
+ //---------------------------------------------------------------------------
+ class ASWizInfoPage : public ASWizPage
+ {
+ Q_OBJECT
+
+ public:
+ ASWizInfoPage( AntiSpamWizard::WizardMode mode,
+ QWidget *parent, const char *name );
+
+ void setScanProgressText( const QString &toolName );
+ void addAvailableTool( const QString &visibleName );
+ bool isProgramSelected( const QString &visibleName );
+
+ private slots:
+ void processSelectionChange();
+
+ signals:
+ void selectionChanged();
+
+ private:
+ QLabel *mIntroText;
+ QLabel *mScanProgressText;
+ QLabel *mSelectionHint;
+ KListBox *mToolsList;
+ };
+
+ //---------------------------------------------------------------------------
+ class ASWizSpamRulesPage : public ASWizPage
+ {
+ Q_OBJECT
+
+ public:
+ ASWizSpamRulesPage( QWidget * parent, const char * name, KMFolderTree * mainFolderTree );
+
+ bool markAsReadSelected() const;
+ bool moveSpamSelected() const;
+ bool moveUnsureSelected() const;
+
+ QString selectedSpamFolderName() const;
+ QString selectedUnsureFolderName() const;
+
+ void allowUnsureFolderSelection( bool enabled );
+
+ private slots:
+ void processSelectionChange();
+ void processSelectionChange( KMFolder* );
+
+ signals:
+ void selectionChanged();
+
+ private:
+ QCheckBox * mMarkRules;
+ QCheckBox * mMoveSpamRules;
+ QCheckBox * mMoveUnsureRules;
+ FolderRequester *mFolderReqForSpamFolder;
+ FolderRequester *mFolderReqForUnsureFolder;
+ };
+
+ //-------------------------------------------------------------------------
+ class ASWizVirusRulesPage : public ASWizPage
+ {
+ Q_OBJECT
+
+ public:
+ ASWizVirusRulesPage( QWidget * parent, const char * name, KMFolderTree * mainFolderTree );
+
+ bool pipeRulesSelected() const;
+ bool moveRulesSelected() const;
+ bool markReadRulesSelected() const;
+
+ QString selectedFolderName() const;
+
+ private slots:
+ void processSelectionChange();
+ signals:
+ void selectionChanged();
+
+ private:
+ QCheckBox * mPipeRules;
+ QCheckBox * mMoveRules;
+ SimpleFolderTree *mFolderTree;
+ QCheckBox * mMarkRules;
+ };
+
+ //---------------------------------------------------------------------------
+ class ASWizSummaryPage : public ASWizPage
+ {
+ Q_OBJECT
+
+ public:
+ ASWizSummaryPage( QWidget * parent, const char * name );
+
+ void setSummaryText( const QString & text );
+
+ private:
+ QLabel * mSummaryText;
+ };
+
+
+} // namespace KMail
+
+#endif // KMAIL_ANTISPAMWIZARD_H
diff --git a/kmail/app_octetstream.cpp b/kmail/app_octetstream.cpp
new file mode 100644
index 00000000..73594645
--- /dev/null
+++ b/kmail/app_octetstream.cpp
@@ -0,0 +1,66 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ app_octetstream.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "interfaces/bodypartformatter.h"
+
+#include <kdepimmacros.h>
+
+namespace {
+
+ class Formatter : public KMail::Interface::BodyPartFormatter {
+ public:
+ Result format( KMail::Interface::BodyPart *, KMail::HtmlWriter * ) const { return AsIcon; }
+ };
+
+ class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
+ public:
+ const KMail::Interface::BodyPartFormatter * bodyPartFormatter( int idx ) const {
+ return idx == 0 ? new Formatter() : 0 ;
+ }
+ const char * type( int idx ) const {
+ return idx == 0 ? "application" : 0 ;
+ }
+ const char * subtype( int idx ) const {
+ return idx == 0 ? "octet-stream" : 0 ;
+ }
+
+ const KMail::Interface::BodyPartURLHandler * urlHandler( int ) const { return 0; }
+ };
+
+}
+
+extern "C"
+KDE_EXPORT KMail::Interface::BodyPartFormatterPlugin *
+libkmail_bodypartformatter_application_octetstream_create_bodypart_formatter_plugin() {
+ return new Plugin();
+}
+
diff --git a/kmail/application_octetstream.desktop b/kmail/application_octetstream.desktop
new file mode 100644
index 00000000..a0272b6b
--- /dev/null
+++ b/kmail/application_octetstream.desktop
@@ -0,0 +1,85 @@
+[Misc]
+Name=Application Octetstream
+Name[af]=Application/Octet-stream
+Name[ca]=Aplicació Octetstream
+Name[cs]=Aplikace octetstream
+Name[da]=Program oktetstrøm
+Name[eo]=Aplikaĵa Bitokfluo
+Name[es]=Aplicación en flujo de octetos
+Name[eu]=Aplikazioa/zortzikote-jarioa
+Name[fa]=Octetstream کاربرد
+Name[fi]=Octetstream-sovellus
+Name[fr]=Application (flux d'octets)
+Name[fy]=Applikaasje octetstream
+Name[gl]=Aplicación Octetstream
+Name[hu]=Alkalmazás-adatfolyam
+Name[ja]=アプリケーション オクテット ストリーム
+Name[ka]=რვადინებიანი პროგრამა
+Name[kk]=Қолданбаның бинарлы ағымы
+Name[km]=Octetstream កម្មវិធី
+Name[ms]=Aliran Oktet Aplikasi
+Name[nb]=Program Octetstrøm
+Name[ne]=अक्टेस्ट्रिम अनुप्रयोग
+Name[nl]=Applicatie octetstroom
+Name[nn]=Oktettstraum frå program
+Name[pl]=Dane binarne
+Name[pt]=Aplicação Sequência Binária
+Name[pt_BR]=Aplicativo Octetstream
+Name[ru]=Бинарный поток приложения
+Name[sl]=Programski Octetstream
+Name[sr]=Апликација Octetstream
+Name[sr@Latn]=Aplikacija Octetstream
+Name[sv]=Program-oktettström
+Name[ta]=பயன்பாட்டு எண்மம்
+Name[tg]=Миқдори зиёди бинарии барномот
+Name[tr]=Uygulama Sekizli Akışı
+Name[zh_CN]=应用程序 Octetstream
+Comment=A bodypart formatter plugin for application/octet-stream
+Comment[af]='n Inprop module wat die lyf gedeelte vir 'application/octet-stream' formateer
+Comment[bg]=Приставка за форматиране на двоични данни
+Comment[bs]=Dodatak za formatiranje tijela poruke za application/octet-stream
+Comment[ca]=Un endollable formatador del cos per application/octet-stream
+Comment[cs]=Modul formátovače těla pro application/octet-stream
+Comment[da]=Et bodypart formateringsplugin for application/octet-stream
+Comment[de]=Ein Bodypart-Formatierungsmodul für application/octet-stream
+Comment[el]=Ένας μορφοποιητής για application/octet-stream
+Comment[es]=Un accesorio de formato para el cuerpo de application/octet-stream
+Comment[et]=Põhiosa vormindamisplugin (MIME tüübile application/octet-stream)
+Comment[eu]=Gorputz-zati formateatzaile plugin bat aplikazio/zortikote-jarioentzat
+Comment[fa]=وصلۀ قالب‌دهندۀ بخش بدنه برای کاربرد/octet-stream
+Comment[fi]=Muokkainliitännäinen application/octet-stream-muodolle
+Comment[fr]=Un module formateur de corps pour application (flux d'octets)
+Comment[fy]=In opmaakplugin foar application/octet-stream
+Comment[gl]=Unha extensión formateadora do corpo para aplicacións/octet-stream
+Comment[hu]=Formázómodul application/octet-stream típusú adatfolyamokhoz
+Comment[is]=Sniðmátstól fyrir application/octet-stream
+Comment[it]=Un plugin per formattare application/octet-stream
+Comment[ja]=application/octet-stream の Bodypart フォーマッタプラグイン
+Comment[ka]=ნაწილიბრივი დამფორმატებელი მოდული პროგრამისთვის/octet-stream
+Comment[kk]=Application/octet-stream үшін пішімдегіш модулі
+Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​កម្មវិធី/octet-stream
+Comment[lt]=application/octet-stream formatavimo priedas
+Comment[ms]=Plugin pemformat bahagian isi untuk alpikasi/aliran oktet
+Comment[nb]=Et programtillegg for meldingstekst-formatering for application/octet-stream
+Comment[nds]=En Hööftdeel-Formateermoduul för application/octet-stream
+Comment[ne]=अनुप्रयोग/अक्टेट-स्ट्रिमका लागि एउटा मूख्यभाग ढाँचाकार
+Comment[nl]=Een opmaakplugin voor application/octet-stream
+Comment[nn]=Eit programtillegg for formatering av meldingstekst i application/octet-stream
+Comment[pl]=Wtyczka formatowania danych typu application/octet-stream
+Comment[pt]=Um 'plugin' de formatação para application/octet-stream
+Comment[pt_BR]=Um plug-in formatador de componente para application/octet-stream
+Comment[ru]=Форматирование application/octet-stream
+Comment[sk]=Formátovač tela pre MIME typ application/octet-stream
+Comment[sl]=Oblikovni vstavek za application/octet-stream
+Comment[sr]=Прукључак форматера тела за application/octet-stream
+Comment[sr@Latn]=Pruključak formatera tela za application/octet-stream
+Comment[sv]=Ett insticksprogram för brevtextformatering av application/octet-stream
+Comment[ta]=பயன்பாடு அல்லது எண்மத்திற்கான அங்க அமைப்பு சொருகி
+Comment[tg]=Модули ба андозадарории application/octet-stream
+Comment[tr]=application/octet-stream için bir gövde biçimleyici eklentisi
+Comment[uk]=Втулок для форматування application/octet-stream
+Comment[zh_CN]=application/octet-stream 的格式化插件
+
+[Plugin]
+Type=application/octet-stream
+X-KDE-Library=libkmail_bodypartformatter_application_octetstream
diff --git a/kmail/attachmentcollector.cpp b/kmail/attachmentcollector.cpp
new file mode 100644
index 00000000..7114242c
--- /dev/null
+++ b/kmail/attachmentcollector.cpp
@@ -0,0 +1,85 @@
+/* -*- c++ -*-
+ attachmentcollector.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "attachmentcollector.h"
+
+#include "partNode.h"
+
+static bool isInSkipList( partNode * ) {
+ return false;
+}
+
+static bool isInExclusionList( const partNode * node ) {
+ if ( !node )
+ return true;
+
+ switch ( node->type() ) {
+ case DwMime::kTypeApplication:
+ switch ( node->subType() ) {
+ case DwMime::kSubtypePkcs7Mime:
+ case DwMime::kSubtypePkcs7Signature:
+ case DwMime::kSubtypePgpSignature:
+ case DwMime::kSubtypePgpEncrypted:
+ return true;
+ }
+ break;
+ case DwMime::kTypeMultipart:
+ return true;
+ }
+ return false;
+}
+
+
+void KMail::AttachmentCollector::collectAttachmentsFrom( partNode * node ) {
+ while ( node ) {
+ if ( node->isFirstTextPart() ) {
+ node = node->next();
+ continue;
+ }
+ if ( isInSkipList( node ) ) {
+ node = node->next( false ); // skip even the children
+ continue;
+ }
+ if ( isInExclusionList( node ) ) {
+ node = node->next();
+ continue;
+ }
+
+ if ( node->isHeuristicalAttachment() ) {
+ mAttachments.push_back( node );
+ node = node->next( false ); // just make double sure
+ continue;
+ }
+
+ node = node->next();
+ }
+}
+
diff --git a/kmail/attachmentcollector.h b/kmail/attachmentcollector.h
new file mode 100644
index 00000000..52454e8d
--- /dev/null
+++ b/kmail/attachmentcollector.h
@@ -0,0 +1,75 @@
+/* -*- c++ -*-
+ attachmentcollector.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KMAIL_ATTACHMENTCOLLECTOR_H__
+#define __KMAIL_ATTACHMENTCOLLECTOR_H__
+
+#include <vector>
+
+class partNode;
+
+namespace KMail {
+
+ class AttachmentCollector {
+ public:
+ AttachmentCollector()
+ : mDiveIntoEncryptions( true ),
+ mDiveIntoSignatures( true ),
+ mDiveIntoMessages( false ) {}
+
+ void setDiveIntoEncryptions( bool dive ) {
+ mDiveIntoEncryptions = dive;
+ }
+ void setDiveIntoSignatures( bool dive ) {
+ mDiveIntoSignatures = dive;
+ }
+ void setDiveIntoMessages( bool dive ) {
+ mDiveIntoMessages = dive;
+ }
+
+ void collectAttachmentsFrom( partNode * node );
+
+ const std::vector<partNode*> & attachments() const { return mAttachments; }
+
+ private:
+ std::vector<partNode*> mAttachments;
+ bool mDiveIntoEncryptions : 1;
+ bool mDiveIntoSignatures : 1;
+ bool mDiveIntoMessages : 1;
+
+ private: // disabled
+ AttachmentCollector( const AttachmentCollector & );
+ void operator=( const AttachmentCollector & );
+ };
+
+} // namespace KMail
+
+#endif // __KMAIL_BODYPARTFORMATTER_H__
diff --git a/kmail/attachmentlistview.cpp b/kmail/attachmentlistview.cpp
new file mode 100644
index 00000000..b7c8bdd2
--- /dev/null
+++ b/kmail/attachmentlistview.cpp
@@ -0,0 +1,146 @@
+/* -*- c++ -*-
+ attachmentlistview.cpp
+
+ KMail, the KDE mail client.
+ Copyright (c) 2003 Ingo Kloecker <kloecker@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License,
+ version 2.0, as published by the Free Software Foundation.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// my header file
+#include "attachmentlistview.h"
+
+// other KMail headers
+#include "kmmsgbase.h"
+#include "kmfolder.h"
+#include "kmcommands.h"
+#include "kmmsgdict.h"
+#include "composer.h"
+
+// other module headers
+#include <maillistdrag.h>
+using KPIM::MailListDrag;
+
+// other KDE headers
+#include <kurldrag.h>
+
+// other Qt headers
+#include <qevent.h>
+#include <qcstring.h>
+#include <qbuffer.h>
+#include <qptrlist.h>
+#include <qdatastream.h>
+#include <qstring.h>
+
+// other headers (none)
+
+
+namespace KMail {
+
+AttachmentListView::AttachmentListView( KMail::Composer * composer,
+ QWidget* parent,
+ const char* name )
+ : KListView( parent, name ),
+ mComposer( composer )
+{
+ setAcceptDrops( true );
+ setDragEnabled( true );
+}
+
+//-----------------------------------------------------------------------------
+
+AttachmentListView::~AttachmentListView()
+{
+}
+
+//-----------------------------------------------------------------------------
+
+void AttachmentListView::contentsDragEnterEvent( QDragEnterEvent* e )
+{
+ if( e->provides( MailListDrag::format() ) || KURLDrag::canDecode( e ) )
+ e->accept( true );
+ else
+ KListView::dragEnterEvent( e );
+}
+
+//-----------------------------------------------------------------------------
+
+void AttachmentListView::contentsDragMoveEvent( QDragMoveEvent* e )
+{
+ if( e->provides( MailListDrag::format() ) || KURLDrag::canDecode( e ) )
+ e->accept( true );
+ else
+ KListView::dragMoveEvent( e );
+}
+
+//-----------------------------------------------------------------------------
+
+void AttachmentListView::contentsDropEvent( QDropEvent* e )
+{
+ if( e->provides( MailListDrag::format() ) ) {
+ // Decode the list of serial numbers stored as the drag data
+ QByteArray serNums;
+ MailListDrag::decode( e, serNums );
+ QBuffer serNumBuffer( serNums );
+ serNumBuffer.open( IO_ReadOnly );
+ QDataStream serNumStream( &serNumBuffer );
+ Q_UINT32 serNum;
+ KMFolder *folder = 0;
+ int idx;
+ QPtrList<KMMsgBase> messageList;
+ while( !serNumStream.atEnd() ) {
+ KMMsgBase *msgBase = 0;
+ serNumStream >> serNum;
+ KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
+ if( folder )
+ msgBase = folder->getMsgBase( idx );
+ if( msgBase )
+ messageList.append( msgBase );
+ }
+ serNumBuffer.close();
+ uint identity = folder ? folder->identity() : 0;
+ KMCommand *command = new KMForwardAttachedCommand( mComposer, messageList,
+ identity, mComposer );
+ command->start();
+ }
+ else if( KURLDrag::canDecode( e ) ) {
+ KURL::List urlList;
+ if( KURLDrag::decode( e, urlList ) ) {
+ for( KURL::List::Iterator it = urlList.begin();
+ it != urlList.end(); ++it ) {
+ mComposer->addAttach( *it );
+ }
+ }
+ }
+ else {
+ KListView::dropEvent( e );
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void AttachmentListView::keyPressEvent( QKeyEvent * e )
+{
+ if ( e->key() == Key_Delete ) {
+ emit attachmentDeleted();
+ }
+}
+
+/*virtual*/
+void AttachmentListView::startDrag()
+{
+ emit dragStarted();
+}
+
+} // namespace KMail
+
+#include "attachmentlistview.moc"
diff --git a/kmail/attachmentlistview.h b/kmail/attachmentlistview.h
new file mode 100644
index 00000000..23ee6713
--- /dev/null
+++ b/kmail/attachmentlistview.h
@@ -0,0 +1,59 @@
+/* -*- c++ -*-
+ attachmentlistview.h
+
+ KMail, the KDE mail client.
+ Copyright (c) 2003 Ingo Kloecker <kloecker@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License,
+ version 2.0, as published by the Free Software Foundation.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
+*/
+
+
+#ifndef _KMAIL_ATTACHMENTLISTVIEW_H_
+#define _KMAIL_ATTACHMENTLISTVIEW_H_
+
+#include <klistview.h>
+
+class QDragEnterEvent;
+class QDragMoveEvent;
+class QDropEvent;
+class KMComposeWin;
+
+namespace KMail {
+
+class Composer;
+
+class AttachmentListView : public KListView
+{
+ Q_OBJECT
+public:
+ AttachmentListView( KMail::Composer * composer = 0, QWidget* parent = 0,
+ const char* name = 0 );
+ virtual ~AttachmentListView();
+
+ /** Drag and drop methods */
+ void contentsDragEnterEvent( QDragEnterEvent* );
+ void contentsDragMoveEvent( QDragMoveEvent* );
+ void contentsDropEvent( QDropEvent* );
+
+protected:
+ virtual void keyPressEvent( QKeyEvent * e );
+ virtual void startDrag();
+
+private:
+ KMail::Composer * mComposer;
+
+signals:
+ void attachmentDeleted();
+ void dragStarted();
+
+};
+
+} // namespace KMail
+
+#endif // _KMAIL_ATTACHMENTLISTVIEW_H_
+
diff --git a/kmail/attachmentstrategy.cpp b/kmail/attachmentstrategy.cpp
new file mode 100644
index 00000000..37584d84
--- /dev/null
+++ b/kmail/attachmentstrategy.cpp
@@ -0,0 +1,209 @@
+/* -*- c++ -*-
+ attachmentstrategy.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2003 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "attachmentstrategy.h"
+
+#include "partNode.h"
+#include "kmmsgpart.h"
+
+#include <qstring.h>
+
+#include <kdebug.h>
+
+
+namespace KMail {
+
+
+ //
+ // IconicAttachmentStrategy:
+ // show everything but the first text/plain body as icons
+ //
+
+ class IconicAttachmentStrategy : public AttachmentStrategy {
+ friend class ::KMail::AttachmentStrategy;
+ protected:
+ IconicAttachmentStrategy() : AttachmentStrategy() {}
+ virtual ~IconicAttachmentStrategy() {}
+
+ public:
+ const char * name() const { return "iconic"; }
+ const AttachmentStrategy * next() const { return smart(); }
+ const AttachmentStrategy * prev() const { return hidden(); }
+
+ bool inlineNestedMessages() const { return false; }
+ Display defaultDisplay( const partNode * ) const { return AsIcon; }
+ };
+
+ //
+ // SmartAttachmentStrategy:
+ // in addition to Iconic, show all body parts
+ // with content-disposition == "inline" and
+ // all text parts without a filename or name parameter inline
+ //
+
+ class SmartAttachmentStrategy : public AttachmentStrategy {
+ friend class ::KMail::AttachmentStrategy;
+ protected:
+ SmartAttachmentStrategy() : AttachmentStrategy() {}
+ virtual ~SmartAttachmentStrategy() {}
+
+ public:
+ const char * name() const { return "smart"; }
+ const AttachmentStrategy * next() const { return inlined(); }
+ const AttachmentStrategy * prev() const { return iconic(); }
+
+ bool inlineNestedMessages() const { return true; }
+ Display defaultDisplay( const partNode * node ) const {
+ if ( node->hasContentDispositionInline() )
+ // explict "inline" disposition:
+ return Inline;
+ if ( node->isAttachment() )
+ // explicit "attachment" disposition:
+ return AsIcon;
+ if ( node->type() == DwMime::kTypeText &&
+ node->msgPart().fileName().stripWhiteSpace().isEmpty() &&
+ node->msgPart().name().stripWhiteSpace().isEmpty() )
+ // text/* w/o filename parameter:
+ return Inline;
+ return AsIcon;
+ }
+ };
+
+ //
+ // InlinedAttachmentStrategy:
+ // show everything possible inline
+ //
+
+ class InlinedAttachmentStrategy : public AttachmentStrategy {
+ friend class ::KMail::AttachmentStrategy;
+ protected:
+ InlinedAttachmentStrategy() : AttachmentStrategy() {}
+ virtual ~InlinedAttachmentStrategy() {}
+
+ public:
+ const char * name() const { return "inlined"; }
+ const AttachmentStrategy * next() const { return hidden(); }
+ const AttachmentStrategy * prev() const { return smart(); }
+
+ bool inlineNestedMessages() const { return true; }
+ Display defaultDisplay( const partNode * ) const { return Inline; }
+ };
+
+ //
+ // HiddenAttachmentStrategy
+ // show nothing except the first text/plain body part _at all_
+ //
+
+ class HiddenAttachmentStrategy : public AttachmentStrategy {
+ friend class ::KMail::AttachmentStrategy;
+ protected:
+ HiddenAttachmentStrategy() : AttachmentStrategy() {}
+ virtual ~HiddenAttachmentStrategy() {}
+
+ public:
+ const char * name() const { return "hidden"; }
+ const AttachmentStrategy * next() const { return iconic(); }
+ const AttachmentStrategy * prev() const { return inlined(); }
+
+ bool inlineNestedMessages() const { return false; }
+ Display defaultDisplay( const partNode * ) const { return None; }
+ };
+
+
+ //
+ // AttachmentStrategy abstract base:
+ //
+
+ AttachmentStrategy::AttachmentStrategy() {
+
+ }
+
+ AttachmentStrategy::~AttachmentStrategy() {
+
+ }
+
+ const AttachmentStrategy * AttachmentStrategy::create( Type type ) {
+ switch ( type ) {
+ case Iconic: return iconic();
+ case Smart: return smart();
+ case Inlined: return inlined();
+ case Hidden: return hidden();
+ }
+ kdFatal( 5006 ) << "AttachmentStrategy::create(): Unknown attachment startegy ( type == "
+ << (int)type << " ) requested!" << endl;
+ return 0; // make compiler happy
+ }
+
+ const AttachmentStrategy * AttachmentStrategy::create( const QString & type ) {
+ QString lowerType = type.lower();
+ if ( lowerType == "iconic" ) return iconic();
+ //if ( lowerType == "smart" ) return smart(); // not needed, see below
+ if ( lowerType == "inlined" ) return inlined();
+ if ( lowerType == "hidden" ) return hidden();
+ // don't kdFatal here, b/c the strings are user-provided
+ // (KConfig), so fail gracefully to the default:
+ return smart();
+ }
+
+ static const AttachmentStrategy * iconicStrategy = 0;
+ static const AttachmentStrategy * smartStrategy = 0;
+ static const AttachmentStrategy * inlinedStrategy = 0;
+ static const AttachmentStrategy * hiddenStrategy = 0;
+
+ const AttachmentStrategy * AttachmentStrategy::iconic() {
+ if ( !iconicStrategy )
+ iconicStrategy = new IconicAttachmentStrategy();
+ return iconicStrategy;
+ }
+
+ const AttachmentStrategy * AttachmentStrategy::smart() {
+ if ( !smartStrategy )
+ smartStrategy = new SmartAttachmentStrategy();
+ return smartStrategy;
+ }
+
+ const AttachmentStrategy * AttachmentStrategy::inlined() {
+ if ( !inlinedStrategy )
+ inlinedStrategy = new InlinedAttachmentStrategy();
+ return inlinedStrategy;
+ }
+
+ const AttachmentStrategy * AttachmentStrategy::hidden() {
+ if ( !hiddenStrategy )
+ hiddenStrategy = new HiddenAttachmentStrategy();
+ return hiddenStrategy;
+ }
+
+} // namespace KMail
diff --git a/kmail/attachmentstrategy.h b/kmail/attachmentstrategy.h
new file mode 100644
index 00000000..bcd29cfd
--- /dev/null
+++ b/kmail/attachmentstrategy.h
@@ -0,0 +1,79 @@
+/* -*- c++ -*-
+ attachmentstrategy.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2003 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KMAIL_ATTACHMENTSTRATEGY_H__
+#define __KMAIL_ATTACHMENTSTRATEGY_H__
+
+class QString;
+class partNode;
+
+namespace KMail {
+
+ class AttachmentStrategy {
+ protected:
+ AttachmentStrategy();
+ virtual ~AttachmentStrategy();
+
+ public:
+ //
+ // Factory methods:
+ //
+ enum Type { Iconic, Smart, Inlined, Hidden };
+
+ static const AttachmentStrategy * create( Type type );
+ static const AttachmentStrategy * create( const QString & type );
+
+ static const AttachmentStrategy * iconic();
+ static const AttachmentStrategy * smart();
+ static const AttachmentStrategy * inlined();
+ static const AttachmentStrategy * hidden();
+
+ //
+ // Navigation methods:
+ //
+
+ virtual const char * name() const = 0;
+ virtual const AttachmentStrategy * next() const = 0;
+ virtual const AttachmentStrategy * prev() const = 0;
+
+ //
+ // Bahavioural:
+ //
+
+ enum Display { None, AsIcon, Inline };
+
+ virtual bool inlineNestedMessages() const = 0;
+ virtual Display defaultDisplay( const partNode * node ) const = 0;
+ };
+
+} // namespace KMail
+
+#endif // __KMAIL_ATTACHMENTSTRATEGY_H__
diff --git a/kmail/avscripts/Makefile.am b/kmail/avscripts/Makefile.am
new file mode 100644
index 00000000..1f4bfe02
--- /dev/null
+++ b/kmail/avscripts/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = .
+bin_SCRIPTS = kmail_clamav.sh kmail_sav.sh kmail_fprot.sh kmail_antivir.sh
diff --git a/kmail/avscripts/kmail_antivir.sh b/kmail/avscripts/kmail_antivir.sh
new file mode 100755
index 00000000..183431b5
--- /dev/null
+++ b/kmail/avscripts/kmail_antivir.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# This file is part of KMail.
+# Copyright (c) 2004 Hendrik Muhs <Hendrik.Muhs@web.de>
+#
+# KMail is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation.
+#
+# KMail is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of this program with any edition of
+# the Qt library by Trolltech AS, Norway (or with modified versions
+# of Qt that use the same license as Qt), and distribute linked
+# combinations including the two. You must obey the GNU General
+# Public License in all respects for all of the code used other than
+# Qt. If you modify this file, you may extend this exception to
+# your version of the file, but you are not obligated to do so. If
+# you do not wish to do so, delete this exception statement from
+# your version.
+#
+TEMPFILE=`mktemp`
+if [ $? != 0 ] ; then
+ TEMPFILE=`mktemp /tmp/kmail.XXXXXX`
+fi
+export TEMPFILE
+cat > $TEMPFILE
+if antivir --scan-in-archive --scan-in-mbox $TEMPFILE | grep -q ALERT; then
+echo "X-Virus-Flag: yes"
+else
+echo "X-Virus-Flag: no"
+fi
+cat $TEMPFILE
+rm $TEMPFILE
diff --git a/kmail/avscripts/kmail_clamav.sh b/kmail/avscripts/kmail_clamav.sh
new file mode 100755
index 00000000..b6227b39
--- /dev/null
+++ b/kmail/avscripts/kmail_clamav.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# This file is part of KMail.
+# Copyright (c) 2004 Fred Emmott <fred87@users.sf.net>
+#
+# KMail is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation.
+#
+# KMail is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of this program with any edition of
+# the Qt library by Trolltech AS, Norway (or with modified versions
+# of Qt that use the same license as Qt), and distribute linked
+# combinations including the two. You must obey the GNU General
+# Public License in all respects for all of the code used other than
+# Qt. If you modify this file, you may extend this exception to
+# your version of the file, but you are not obligated to do so. If
+# you do not wish to do so, delete this exception statement from
+# your version.
+#
+TEMPFILE=`mktemp`
+if [ $? != 0 ] ; then
+ TEMPFILE=`mktemp /tmp/kmail.XXXXXX`
+fi
+export TEMPFILE
+cat > $TEMPFILE
+
+# check for a running daemon
+if [ "`ps -eo comm|grep clamd`" = "clamd" ]; then
+ chmod a+r $TEMPFILE
+ CLAMCOMANDO="clamdscan --stdout --no-summary "
+else
+ CLAMCOMANDO="clamscan --stdout --no-summary"
+fi
+
+# analyze the message
+if $CLAMCOMANDO $TEMPFILE | grep -q FOUND; then
+ echo "X-Virus-Flag: yes"
+else
+ echo "X-Virus-Flag: no"
+fi
+
+cat $TEMPFILE
+rm $TEMPFILE
diff --git a/kmail/avscripts/kmail_fprot.sh b/kmail/avscripts/kmail_fprot.sh
new file mode 100755
index 00000000..15698e94
--- /dev/null
+++ b/kmail/avscripts/kmail_fprot.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# This file is part of KMail.
+# Copyright (c) 2004 Fred Emmott <fred87@users.sf.net>
+#
+# KMail is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation.
+#
+# KMail is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of this program with any edition of
+# the Qt library by Trolltech AS, Norway (or with modified versions
+# of Qt that use the same license as Qt), and distribute linked
+# combinations including the two. You must obey the GNU General
+# Public License in all respects for all of the code used other than
+# Qt. If you modify this file, you may extend this exception to
+# your version of the file, but you are not obligated to do so. If
+# you do not wish to do so, delete this exception statement from
+# your version.
+#
+TEMPFILE=`mktemp`
+if [ $? != 0 ] ; then
+ TEMPFILE=`mktemp /tmp/kmail.XXXXXX`
+fi
+export TEMPFILE
+cat > $TEMPFILE
+f-prot -archive 3 $TEMPFILE > /dev/null
+RC=$?
+if [ $RC -eq 0 ] ; then
+ echo "X-Virus-Flag: no"
+else
+ case $RC in
+ 1 ) DESC="no - Unrecoverable error" ;;
+ 2 ) DESC="no - Selftest failed" ;;
+ 3 ) DESC="yes - Virus-infected object found" ;;
+ 4 ) DESC="no - Reserved" ;;
+ 5 ) DESC="no - Abnormal termination" ;;
+ 6 ) DESC="no - Virus was removed" ;;
+ 7 ) DESC="no - Error, out of memory" ;;
+ 8 ) DESC="yes - Something suspicious found" ;;
+ esac
+ echo "X-Virus-Flag: $DESC"
+fi
+
+cat $TEMPFILE
+rm $TEMPFILE
diff --git a/kmail/avscripts/kmail_sav.sh b/kmail/avscripts/kmail_sav.sh
new file mode 100755
index 00000000..dbb794bb
--- /dev/null
+++ b/kmail/avscripts/kmail_sav.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# This file is part of KMail.
+# Copyright (c) 2004 Fred Emmott <fred87@users.sf.net>
+#
+# KMail is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License, version 2, as
+# published by the Free Software Foundation.
+#
+# KMail is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of this program with any edition of
+# the Qt library by Trolltech AS, Norway (or with modified versions
+# of Qt that use the same license as Qt), and distribute linked
+# combinations including the two. You must obey the GNU General
+# Public License in all respects for all of the code used other than
+# Qt. If you modify this file, you may extend this exception to
+# your version of the file, but you are not obligated to do so. If
+# you do not wish to do so, delete this exception statement from
+# your version.
+#
+TEMPFILE=`mktemp`
+if [ $? != 0 ] ; then
+ TEMPFILE=`mktemp /tmp/kmail.XXXXXX`
+fi
+export TEMPFILE
+cat > $TEMPFILE
+if sweep -ss -mime $TEMPFILE | grep -q found; then
+echo "X-Virus-Flag: yes"
+else
+echo "X-Virus-Flag: no"
+fi
+cat $TEMPFILE
+rm $TEMPFILE
diff --git a/kmail/bodypartformatter.cpp b/kmail/bodypartformatter.cpp
new file mode 100644
index 00000000..efe12f67
--- /dev/null
+++ b/kmail/bodypartformatter.cpp
@@ -0,0 +1,334 @@
+/* -*- c++ -*-
+ bodypartformatter.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2003 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "bodypartformatter.h"
+#include "bodypartformatterfactory_p.h"
+#include "interfaces/bodypartformatter.h"
+
+#include "objecttreeparser.h"
+#include "partNode.h"
+
+#include <mimelib/enum.h>
+#include <mimelib/string.h>
+#include <mimelib/utility.h>
+
+#include <kdebug.h>
+#include <kasciistricmp.h>
+
+namespace {
+ class AnyTypeBodyPartFormatter
+ : public KMail::BodyPartFormatter,
+ public KMail::Interface::BodyPartFormatter {
+ static const AnyTypeBodyPartFormatter * self;
+ public:
+ Result format( KMail::Interface::BodyPart *, KMail::HtmlWriter * ) const {
+ kdDebug(5006) << "AnyTypeBodyPartFormatter::format() acting as a KMail::Interface::BodyPartFormatter!" << endl;
+ return AsIcon;
+ }
+
+ bool process( KMail::ObjectTreeParser *, partNode *, KMail::ProcessResult & result ) const {
+ result.setNeverDisplayInline( true );
+ return false;
+ }
+ static const KMail::BodyPartFormatter * create() {
+ if ( !self )
+ self = new AnyTypeBodyPartFormatter();
+ return self;
+ }
+ };
+
+ const AnyTypeBodyPartFormatter * AnyTypeBodyPartFormatter::self = 0;
+
+
+ class ImageTypeBodyPartFormatter : public KMail::BodyPartFormatter {
+ static const ImageTypeBodyPartFormatter * self;
+ public:
+ bool process( KMail::ObjectTreeParser *, partNode *, KMail::ProcessResult & result ) const {
+ result.setIsImage( true );
+ return false;
+ }
+ static const KMail::BodyPartFormatter * create() {
+ if ( !self )
+ self = new ImageTypeBodyPartFormatter();
+ return self;
+ }
+ };
+
+ const ImageTypeBodyPartFormatter * ImageTypeBodyPartFormatter::self = 0;
+
+#define CREATE_BODY_PART_FORMATTER(subtype) \
+ class subtype##BodyPartFormatter : public KMail::BodyPartFormatter { \
+ static const subtype##BodyPartFormatter * self; \
+ public: \
+ bool process( KMail::ObjectTreeParser *, partNode *, KMail::ProcessResult & ) const; \
+ static const KMail::BodyPartFormatter * create() { \
+ if ( !self ) \
+ self = new subtype##BodyPartFormatter(); \
+ return self; \
+ } \
+ }; \
+ \
+ const subtype##BodyPartFormatter * subtype##BodyPartFormatter::self; \
+ \
+ bool subtype##BodyPartFormatter::process( KMail::ObjectTreeParser * otp, partNode * node, KMail::ProcessResult & result ) const { \
+ return otp->process##subtype##Subtype( node, result ); \
+ }
+
+ CREATE_BODY_PART_FORMATTER(TextPlain)
+ CREATE_BODY_PART_FORMATTER(TextHtml)
+ //CREATE_BODY_PART_FORMATTER(TextEnriched)
+
+ CREATE_BODY_PART_FORMATTER(ApplicationOctetStream)
+ CREATE_BODY_PART_FORMATTER(ApplicationPkcs7Mime)
+ CREATE_BODY_PART_FORMATTER(ApplicationChiasmusText)
+ //CREATE_BODY_PART_FORMATTER(ApplicationPgp)
+ CREATE_BODY_PART_FORMATTER(ApplicationMsTnef)
+
+ CREATE_BODY_PART_FORMATTER(MessageRfc822)
+
+ CREATE_BODY_PART_FORMATTER(MultiPartMixed)
+ CREATE_BODY_PART_FORMATTER(MultiPartAlternative)
+ CREATE_BODY_PART_FORMATTER(MultiPartSigned)
+ CREATE_BODY_PART_FORMATTER(MultiPartEncrypted)
+
+ typedef TextPlainBodyPartFormatter ApplicationPgpBodyPartFormatter;
+
+
+#undef CREATE_BODY_PART_FORMATTER
+} // anon namespace
+
+// FIXME: port some more KMail::BodyPartFormatters to KMail::Interface::BodyPartFormatters
+void KMail::BodyPartFormatterFactoryPrivate::kmail_create_builtin_bodypart_formatters( KMail::BodyPartFormatterFactoryPrivate::TypeRegistry * reg ) {
+ if ( !reg ) return;
+ (*reg)["application"]["octet-stream"] = new AnyTypeBodyPartFormatter();
+}
+
+typedef const KMail::BodyPartFormatter * (*BodyPartFormatterCreator)();
+
+struct SubtypeBuiltin {
+ const char * subtype;
+ BodyPartFormatterCreator create;
+};
+
+static const SubtypeBuiltin applicationSubtypeBuiltins[] = {
+ { "octet-stream", &ApplicationOctetStreamBodyPartFormatter::create },
+ { "pkcs7-mime", &ApplicationPkcs7MimeBodyPartFormatter::create },
+ { "x-pkcs7-mime", &ApplicationPkcs7MimeBodyPartFormatter::create },
+ { "vnd.de.bund.bsi.chiasmus-text", &ApplicationChiasmusTextBodyPartFormatter::create },
+ { "pgp", &ApplicationPgpBodyPartFormatter::create },
+ { "ms-tnef", &ApplicationMsTnefBodyPartFormatter::create }
+};
+
+static const SubtypeBuiltin textSubtypeBuiltins[] = {
+ { "html", &TextHtmlBodyPartFormatter::create },
+ //{ "enriched", &TextEnrichedBodyPartFormatter::create },
+ { "x-vcard", &AnyTypeBodyPartFormatter::create },
+ { "vcard", &AnyTypeBodyPartFormatter::create },
+ { "rtf", &AnyTypeBodyPartFormatter::create },
+ { "*", &TextPlainBodyPartFormatter::create },
+};
+
+static const SubtypeBuiltin multipartSubtypeBuiltins[] = {
+ { "mixed", &MultiPartMixedBodyPartFormatter::create },
+ { "alternative", &MultiPartAlternativeBodyPartFormatter::create },
+ //{ "digest", &MultiPartDigestFormatter::create },
+ //{ "parallel", &MultiPartParallelFormatter::create },
+ //{ "related", &MultiPartRelatedFormatter::create },
+ { "signed", &MultiPartSignedBodyPartFormatter::create },
+ { "encrypted", &MultiPartEncryptedBodyPartFormatter::create },
+ //{ "report", &MultiPartReportFormatter::create },
+};
+
+static const SubtypeBuiltin messageSubtypeBuiltins[] = {
+ { "rfc822", &MessageRfc822BodyPartFormatter::create },
+};
+
+static const SubtypeBuiltin imageSubtypeBuiltins[] = {
+ { "*", &ImageTypeBodyPartFormatter::create },
+};
+
+static const SubtypeBuiltin anySubtypeBuiltins[] = {
+ { "*", &AnyTypeBodyPartFormatter::create },
+};
+
+#ifdef DIM
+#undef DIM
+#endif
+#define DIM(x) sizeof(x) / sizeof(*x)
+
+static const struct {
+ const char * type;
+ const SubtypeBuiltin * subtypes;
+ unsigned int num_subtypes;
+} builtins[] = {
+ { "application", applicationSubtypeBuiltins, DIM(applicationSubtypeBuiltins) },
+ { "text", textSubtypeBuiltins, DIM(textSubtypeBuiltins) },
+ { "multipart", multipartSubtypeBuiltins, DIM(multipartSubtypeBuiltins) },
+ { "message", messageSubtypeBuiltins, DIM(messageSubtypeBuiltins) },
+ { "image", imageSubtypeBuiltins, DIM(imageSubtypeBuiltins) },
+ //{ "audio", audioSubtypeBuiltins, DIM(audioSubtypeBuiltins) },
+ //{ "model", modelSubtypeBuiltins, DIM(modelSubtypeBuiltins) },
+ //{ "video", videoSubtypeBuiltins, DIM(videoSubtypeBuiltins) },
+ { "*", anySubtypeBuiltins, DIM(anySubtypeBuiltins) },
+};
+
+#undef DIM
+
+const KMail::BodyPartFormatter * KMail::BodyPartFormatter::createFor( int type, int subtype ) {
+ DwString t, st;
+ DwTypeEnumToStr( type, t );
+ DwSubtypeEnumToStr( subtype, st );
+ return createFor( t.c_str(), st.c_str() );
+}
+
+static const KMail::BodyPartFormatter * createForText( const char * subtype ) {
+ if ( subtype && *subtype )
+ switch ( subtype[0] ) {
+ case 'h':
+ case 'H':
+ if ( kasciistricmp( subtype, "html" ) == 0 )
+ return TextHtmlBodyPartFormatter::create();
+ break;
+ case 'r':
+ case 'R':
+ if ( kasciistricmp( subtype, "rtf" ) == 0 )
+ return AnyTypeBodyPartFormatter::create();
+ break;
+ case 'x':
+ case 'X':
+ case 'v':
+ case 'V':
+ if ( kasciistricmp( subtype, "x-vcard" ) == 0 ||
+ kasciistricmp( subtype, "vcard" ) == 0 )
+ return AnyTypeBodyPartFormatter::create();
+ break;
+ }
+
+ return TextPlainBodyPartFormatter::create();
+}
+
+static const KMail::BodyPartFormatter * createForImage( const char * ) {
+ return ImageTypeBodyPartFormatter::create();
+}
+
+static const KMail::BodyPartFormatter * createForMessage( const char * subtype ) {
+ if ( kasciistricmp( subtype, "rfc822" ) == 0 )
+ return MessageRfc822BodyPartFormatter::create();
+ return AnyTypeBodyPartFormatter::create();
+}
+
+static const KMail::BodyPartFormatter * createForMultiPart( const char * subtype ) {
+ if ( subtype && *subtype )
+ switch ( subtype[0] ) {
+ case 'a':
+ case 'A':
+ if ( kasciistricmp( subtype, "alternative" ) == 0 )
+ return MultiPartAlternativeBodyPartFormatter::create();
+ break;
+ case 'e':
+ case 'E':
+ if ( kasciistricmp( subtype, "encrypted" ) == 0 )
+ return MultiPartEncryptedBodyPartFormatter::create();
+ break;
+ case 's':
+ case 'S':
+ if ( kasciistricmp( subtype, "signed" ) == 0 )
+ return MultiPartSignedBodyPartFormatter::create();
+ break;
+ }
+
+ return MultiPartMixedBodyPartFormatter::create();
+}
+
+static const KMail::BodyPartFormatter * createForApplication( const char * subtype ) {
+ if ( subtype && *subtype )
+ switch ( subtype[0] ) {
+ case 'p':
+ case 'P':
+ if ( kasciistricmp( subtype, "pgp" ) == 0 )
+ return ApplicationPgpBodyPartFormatter::create();
+ // fall through
+ case 'x':
+ case 'X':
+ if ( kasciistricmp( subtype, "pkcs7-mime" ) == 0 ||
+ kasciistricmp( subtype, "x-pkcs7-mime" ) == 0 )
+ return ApplicationPkcs7MimeBodyPartFormatter::create();
+ break;
+ case 'm':
+ case 'M':
+ if ( kasciistricmp( subtype, "ms-tnef" ) == 0 )
+ return ApplicationMsTnefBodyPartFormatter::create();
+ break;
+ case 'v':
+ case 'V':
+ if ( kasciistricmp( subtype, "vnd.de.bund.bsi.chiasmus-text") == 0)
+ return ApplicationChiasmusTextBodyPartFormatter::create();
+ break;
+ }
+
+ return AnyTypeBodyPartFormatter::create();
+}
+
+// OK, replace this with a factory with plugin support later on...
+const KMail::BodyPartFormatter * KMail::BodyPartFormatter::createFor( const char * type, const char * subtype ) {
+ if ( type && *type )
+ switch ( type[0] ) {
+ case 'a': // application
+ case 'A':
+ if ( kasciistricmp( type, "application" ) == 0 )
+ return createForApplication( subtype );
+ break;
+ case 'i': // image
+ case 'I':
+ if ( kasciistricmp( type, "image" ) == 0 )
+ return createForImage( subtype );
+ break;
+ case 'm': // multipart / message
+ case 'M':
+ if ( kasciistricmp( type, "multipart" ) == 0 )
+ return createForMultiPart( subtype );
+ else if ( kasciistricmp( type, "message" ) == 0 )
+ return createForMessage( subtype );
+ break;
+ case 't': // text
+ case 'T':
+ if ( kasciistricmp( type, "text" ) == 0 )
+ return createForText( subtype );
+ break;
+ }
+
+ return AnyTypeBodyPartFormatter::create();
+}
+
diff --git a/kmail/bodypartformatter.h b/kmail/bodypartformatter.h
new file mode 100644
index 00000000..eda28a90
--- /dev/null
+++ b/kmail/bodypartformatter.h
@@ -0,0 +1,58 @@
+/* -*- c++ -*-
+ bodypartformatter.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2003 Marc Mutz <mutz@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KMAIL_BODYPARTFORMATTER_H__
+#define __KMAIL_BODYPARTFORMATTER_H__
+
+class partNode;
+
+namespace KMail {
+
+ class ObjectTreeParser;
+ class ProcessResult;
+
+ class BodyPartFormatter {
+ const BodyPartFormatter & operator=( const BodyPartFormatter & );
+ BodyPartFormatter( const BodyPartFormatter & );
+ protected:
+ BodyPartFormatter() {}
+ public:
+ virtual ~BodyPartFormatter() {}
+
+ virtual bool process( ObjectTreeParser *, partNode *, ProcessResult & ) const = 0;
+
+ static const BodyPartFormatter * createFor( int type, int subtype );
+ static const BodyPartFormatter * createFor( const char * type, const char * subtype );
+ };
+
+} // namespace KMail
+
+#endif // __KMAIL_BODYPARTFORMATTER_H__
diff --git a/kmail/bodypartformatterfactory.cpp b/kmail/bodypartformatterfactory.cpp
new file mode 100644
index 00000000..24ee2fba
--- /dev/null
+++ b/kmail/bodypartformatterfactory.cpp
@@ -0,0 +1,191 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ bodypartformatterfactory.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
+ Ingo Kloecker <kloecker@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "bodypartformatterfactory.h"
+#include "bodypartformatterfactory_p.h"
+using namespace KMail::BodyPartFormatterFactoryPrivate;
+
+#include "interfaces/bodypartformatter.h"
+#include "urlhandlermanager.h"
+
+// libkdepim
+#include <libkdepim/pluginloader.h>
+
+// KDE
+#include <kdebug.h>
+
+// Qt
+#include <qstring.h>
+#include <qcstring.h>
+#include <qstringlist.h>
+
+#include <assert.h>
+
+namespace {
+
+ KPIM_DEFINE_PLUGIN_LOADER( BodyPartFormatterPluginLoader,
+ KMail::Interface::BodyPartFormatterPlugin,
+ "create_bodypart_formatter_plugin",
+ "kmail/plugins/bodypartformatter/*.desktop" )
+
+}
+
+KMail::BodyPartFormatterFactory * KMail::BodyPartFormatterFactory::mSelf = 0;
+
+const KMail::BodyPartFormatterFactory * KMail::BodyPartFormatterFactory::instance() {
+ if ( !mSelf )
+ mSelf = new BodyPartFormatterFactory();
+ return mSelf;
+}
+
+KMail::BodyPartFormatterFactory::BodyPartFormatterFactory() {
+ mSelf = this;
+}
+
+KMail::BodyPartFormatterFactory::~BodyPartFormatterFactory() {
+ mSelf = 0;
+}
+
+static TypeRegistry * all = 0;
+
+static void insertBodyPartFormatter( const char * type, const char * subtype,
+ const KMail::Interface::BodyPartFormatter * formatter ) {
+ if ( !type || !*type || !subtype || !*subtype || !formatter || !all )
+ return;
+
+ TypeRegistry::iterator type_it = all->find( type );
+ if ( type_it == all->end() ) {
+ kdDebug( 5006 ) << "BodyPartFormatterFactory: instantiating new Subtype Registry for \""
+ << type << "\"" << endl;
+ type_it = all->insert( std::make_pair( type, SubtypeRegistry() ) ).first;
+ assert( type_it != all->end() );
+ }
+
+ SubtypeRegistry & subtype_reg = type_it->second;
+ SubtypeRegistry::iterator subtype_it = subtype_reg.find( subtype );
+ if ( subtype_it != subtype_reg.end() ) {
+ kdDebug( 5006 ) << "BodyPartFormatterFactory: overwriting previously registered formatter for \""
+ << type << "/" << subtype << "\"" << endl;
+ subtype_reg.erase( subtype_it ); subtype_it = subtype_reg.end();
+ }
+
+ subtype_reg.insert( std::make_pair( subtype, formatter ) );
+}
+
+static void loadPlugins() {
+ const BodyPartFormatterPluginLoader * pl = BodyPartFormatterPluginLoader::instance();
+ if ( !pl ) {
+ kdWarning( 5006 ) << "BodyPartFormatterFactory: cannot instantiate plugin loader!" << endl;
+ return;
+ }
+ const QStringList types = pl->types();
+ kdDebug( 5006 ) << "BodyPartFormatterFactory: found " << types.size() << " plugins." << endl;
+ for ( QStringList::const_iterator it = types.begin() ; it != types.end() ; ++it ) {
+ const KMail::Interface::BodyPartFormatterPlugin * plugin = pl->createForName( *it );
+ if ( !plugin ) {
+ kdWarning( 5006 ) << "BodyPartFormatterFactory: plugin \"" << *it << "\" is not valid!" << endl;
+ continue;
+ }
+ for ( int i = 0 ; const KMail::Interface::BodyPartFormatter * bfp = plugin->bodyPartFormatter( i ) ; ++i ) {
+ const char * type = plugin->type( i );
+ if ( !type || !*type ) {
+ kdWarning( 5006 ) << "BodyPartFormatterFactory: plugin \"" << *it
+ << "\" returned empty type specification for index "
+ << i << endl;
+ break;
+ }
+ const char * subtype = plugin->subtype( i );
+ if ( !subtype || !*subtype ) {
+ kdWarning( 5006 ) << "BodyPartFormatterFactory: plugin \"" << *it
+ << "\" returned empty subtype specification for index "
+ << i << endl;
+ break;
+ }
+ insertBodyPartFormatter( type, subtype, bfp );
+ }
+ for ( int i = 0 ; const KMail::Interface::BodyPartURLHandler * handler = plugin->urlHandler( i ) ; ++i )
+ KMail::URLHandlerManager::instance()->registerHandler( handler );
+ }
+}
+
+static void setup() {
+ if ( !all ) {
+ all = new TypeRegistry();
+ kmail_create_builtin_bodypart_formatters( all );
+ loadPlugins();
+ }
+}
+
+
+const KMail::Interface::BodyPartFormatter * KMail::BodyPartFormatterFactory::createFor( const char * type, const char * subtype ) const {
+ if ( !type || !*type )
+ type = "*";
+ if ( !subtype || !*subtype )
+ subtype = "*";
+
+ setup();
+ assert( all );
+
+ if ( all->empty() )
+ return 0;
+
+ TypeRegistry::const_iterator type_it = all->find( type );
+ if ( type_it == all->end() )
+ type_it = all->find( "*" );
+ if ( type_it == all->end() )
+ return 0;
+
+ const SubtypeRegistry & subtype_reg = type_it->second;
+ if ( subtype_reg.empty() )
+ return 0;
+
+ SubtypeRegistry::const_iterator subtype_it = subtype_reg.find( subtype );
+ if ( subtype_it == subtype_reg.end() )
+ subtype_it = subtype_reg.find( "*" );
+ if ( subtype_it == subtype_reg.end() )
+ return 0;
+
+ kdWarning( !(*subtype_it).second, 5006 )
+ << "BodyPartFormatterFactory: a null bodypart formatter sneaked in for \""
+ << type << "/" << subtype << "\"!" << endl;
+
+ return (*subtype_it).second;
+}
+
+const KMail::Interface::BodyPartFormatter * KMail::BodyPartFormatterFactory::createFor( const QString & type, const QString & subtype ) const {
+ return createFor( type.latin1(), subtype.latin1() );
+}
+
+const KMail::Interface::BodyPartFormatter * KMail::BodyPartFormatterFactory::createFor( const QCString & type, const QCString & subtype ) const {
+ return createFor( type.data(), subtype.data() );
+}
diff --git a/kmail/bodypartformatterfactory.h b/kmail/bodypartformatterfactory.h
new file mode 100644
index 00000000..63f43bd7
--- /dev/null
+++ b/kmail/bodypartformatterfactory.h
@@ -0,0 +1,72 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ bodypartformatterfactory.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
+ Ingo Kloecker <kloecker@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KMAIL_BODYPARTFORMATTERFACTORY_H__
+#define __KMAIL_BODYPARTFORMATTERFACTORY_H__
+
+class QString;
+class QCString;
+
+namespace KMail {
+
+ namespace Interface {
+ class BodyPartFormatter;
+ }
+
+ class BodyPartFormatterFactory {
+ class gcc_shut_up;
+ friend class ::KMail::BodyPartFormatterFactory::gcc_shut_up;
+ public:
+ ~BodyPartFormatterFactory();
+
+ static const BodyPartFormatterFactory * instance();
+
+ const Interface::BodyPartFormatter * createFor( const char * type, const char * subtype ) const;
+ const Interface::BodyPartFormatter * createFor( const QString & type, const QString & subtype ) const;
+ const Interface::BodyPartFormatter * createFor( const QCString & type, const QCString & subtype ) const;
+
+ //
+ // Only boring stuff below:
+ //
+ private:
+ BodyPartFormatterFactory();
+ static BodyPartFormatterFactory * mSelf;
+ private:
+ // disabled
+ const BodyPartFormatterFactory & operator=( const BodyPartFormatterFactory & );
+ BodyPartFormatterFactory( const BodyPartFormatterFactory & );
+ };
+
+} // namespace KMail
+
+#endif // __KMAIL_BODYPARTFORMATTERFACTORY_H__
diff --git a/kmail/bodypartformatterfactory_p.h b/kmail/bodypartformatterfactory_p.h
new file mode 100644
index 00000000..7171ba29
--- /dev/null
+++ b/kmail/bodypartformatterfactory_p.h
@@ -0,0 +1,62 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ bodypartformatterfactory.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2004 Marc Mutz <mutz@kde.org>,
+ Ingo Kloecker <kloecker@kde.org>
+
+ KMail is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KMAIL_BODYPARTFORMATTERFACTORY_P_H__
+#define __KMAIL_BODYPARTFORMATTERFACTORY_P_H__
+
+#include <qcstring.h>
+
+#include <map>
+
+namespace KMail {
+
+ namespace Interface {
+ class BodyPartFormatter;
+ }
+
+ namespace BodyPartFormatterFactoryPrivate {
+ struct ltstr {
+ bool operator()( const char * s1, const char * s2 ) const {
+ return qstricmp( s1, s2 ) < 0;
+ }
+ };
+
+ typedef std::map<const char*, const KMail::Interface::BodyPartFormatter*, ltstr> SubtypeRegistry;
+ typedef std::map<const char*, SubtypeRegistry, ltstr> TypeRegistry;
+
+ // defined in bodypartformatters.cpp
+ extern void kmail_create_builtin_bodypart_formatters( TypeRegistry * );
+ }
+} // namespace KMail
+
+#endif // __KMAIL_BODYPARTFORMATTERFACTORY_P_H__
diff --git a/kmail/bodyvisitor.cpp b/kmail/bodyvisitor.cpp
new file mode 100644
index 00000000..99af6619
--- /dev/null
+++ b/kmail/bodyvisitor.cpp
@@ -0,0 +1,211 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "bodyvisitor.h"
+#include "kmmsgpart.h"
+#include "attachmentstrategy.h"
+#include <kdebug.h>
+
+namespace KMail {
+
+ BodyVisitor* BodyVisitorFactory::getVisitor( const AttachmentStrategy* strategy )
+ {
+ if (strategy == AttachmentStrategy::smart())
+ {
+ return new BodyVisitorSmart();
+ } else if (strategy == AttachmentStrategy::iconic())
+ {
+ return new BodyVisitorHidden();
+ } else if (strategy == AttachmentStrategy::inlined())
+ {
+ return new BodyVisitorInline();
+ } else if (strategy == AttachmentStrategy::hidden())
+ {
+ return new BodyVisitorHidden();
+ }
+ // default
+ return new BodyVisitorSmart();
+ }
+
+ //=============================================================================
+
+ BodyVisitor::BodyVisitor()
+ {
+ // parts that are probably always ok to load
+ mBasicList.clear();
+ // body text
+ mBasicList += "TEXT/PLAIN";
+ mBasicList += "TEXT/HTML";
+ mBasicList += "MESSAGE/DELIVERY-STATUS";
+ // pgp stuff
+ mBasicList += "APPLICATION/PGP-SIGNATURE";
+ mBasicList += "APPLICATION/PGP";
+ mBasicList += "APPLICATION/PGP-ENCRYPTED";
+ mBasicList += "APPLICATION/PKCS7-SIGNATURE";
+ // groupware
+ mBasicList += "APPLICATION/MS-TNEF";
+ mBasicList += "TEXT/CALENDAR";
+ mBasicList += "TEXT/X-VCARD";
+ }
+
+ //-----------------------------------------------------------------------------
+ BodyVisitor::~BodyVisitor()
+ {
+ }
+
+ //-----------------------------------------------------------------------------
+ void BodyVisitor::visit( KMMessagePart * part )
+ {
+ mParts.append( part );
+ }
+
+ //-----------------------------------------------------------------------------
+ void BodyVisitor::visit( QPtrList<KMMessagePart> & list )
+ {
+ mParts = list;
+ }
+
+ //-----------------------------------------------------------------------------
+ QPtrList<KMMessagePart> BodyVisitor::partsToLoad()
+ {
+ QPtrListIterator<KMMessagePart> it( mParts );
+ QPtrList<KMMessagePart> selected;
+ KMMessagePart *part = 0;
+ bool headerCheck = false;
+ while ( (part = it.current()) != 0 )
+ {
+ ++it;
+ // skip this part if the parent part is already loading
+ if ( part->parent() &&
+ selected.contains( part->parent() ) &&
+ part->loadPart() )
+ continue;
+
+ if ( part->originalContentTypeStr().contains("SIGNED") )
+ {
+ // signed messages have to be loaded completely
+ // so construct a new dummy part that loads the body
+ KMMessagePart *fake = new KMMessagePart();
+ fake->setPartSpecifier( "TEXT" );
+ fake->setOriginalContentTypeStr("");
+ fake->setLoadPart( true );
+ selected.append( fake );
+ break;
+ }
+
+ if ( headerCheck && !part->partSpecifier().endsWith(".HEADER") )
+ {
+ // this is an embedded simple message (not multipart) so we get no header part
+ // from imap. As we probably need to load the header (e.g. in smart or inline mode)
+ // we add a fake part that is not included in the message itself
+ KMMessagePart *fake = new KMMessagePart();
+ QString partId = part->partSpecifier().section( '.', 0, -2 )+".HEADER";
+ fake->setPartSpecifier( partId );
+ fake->setOriginalContentTypeStr("");
+ fake->setLoadPart( true );
+ if ( addPartToList( fake ) )
+ selected.append( fake );
+ }
+
+ if ( part->originalContentTypeStr() == "MESSAGE/RFC822" )
+ headerCheck = true;
+ else
+ headerCheck = false;
+
+ // check whether to load this part or not:
+ // look at the basic list, ask the subclass and check the parent
+ if ( mBasicList.contains( part->originalContentTypeStr() ) ||
+ parentNeedsLoading( part ) ||
+ addPartToList( part ) )
+ {
+ if ( part->typeStr() != "MULTIPART" ||
+ part->partSpecifier().endsWith(".HEADER") )
+ {
+ // load the part itself
+ part->setLoadPart( true );
+ }
+ }
+ if ( !part->partSpecifier().endsWith(".HEADER") &&
+ part->typeStr() != "MULTIPART" )
+ part->setLoadHeaders( true ); // load MIME header
+
+ if ( part->loadHeaders() || part->loadPart() )
+ selected.append( part );
+ }
+ return selected;
+ }
+
+ //-----------------------------------------------------------------------------
+ bool BodyVisitor::parentNeedsLoading( KMMessagePart *msgPart )
+ {
+ KMMessagePart *part = msgPart;
+ while ( part )
+ {
+ if ( part->parent() &&
+ ( part->parent()->originalContentTypeStr() == "MULTIPART/SIGNED" ||
+ ( msgPart->originalContentTypeStr() == "APPLICATION/OCTET-STREAM" &&
+ part->parent()->originalContentTypeStr() == "MULTIPART/ENCRYPTED" ) ) )
+ return true;
+
+ part = part->parent();
+ }
+ return false;
+ }
+
+ //=============================================================================
+
+ BodyVisitorSmart::BodyVisitorSmart()
+ : BodyVisitor()
+ {
+ }
+
+ //-----------------------------------------------------------------------------
+ bool BodyVisitorSmart::addPartToList( KMMessagePart * part )
+ {
+ // header of an encapsulated message
+ if ( part->partSpecifier().endsWith(".HEADER") )
+ return true;
+
+ return false;
+ }
+
+ //=============================================================================
+
+ BodyVisitorInline::BodyVisitorInline()
+ : BodyVisitor()
+ {
+ }
+
+ //-----------------------------------------------------------------------------
+ bool BodyVisitorInline::addPartToList( KMMessagePart * part )
+ {
+ // header of an encapsulated message
+ if ( part->partSpecifier().endsWith(".HEADER") )
+ return true;
+ else if ( part->typeStr() == "IMAGE" ) // images
+ return true;
+ else if ( part->typeStr() == "TEXT" ) // text, diff and stuff
+ return true;
+
+ return false;
+ }
+
+ //=============================================================================
+
+ BodyVisitorHidden::BodyVisitorHidden()
+ : BodyVisitor()
+ {
+ }
+
+ //-----------------------------------------------------------------------------
+ bool BodyVisitorHidden::addPartToList( KMMessagePart * part )
+ {
+ // header of an encapsulated message
+ if ( part->partSpecifier().endsWith(".HEADER") )
+ return true;
+
+ return false;
+ }
+
+}
diff --git a/kmail/bodyvisitor.h b/kmail/bodyvisitor.h
new file mode 100644
index 00000000..fa5d2fb5
--- /dev/null
+++ b/kmail/bodyvisitor.h
@@ -0,0 +1,109 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ *
+ * This file is part of KMail, the KDE mail client.
+ * Copyright (c) 2003 Carsten Burghardt <burghardt@kde.org>
+ *
+ * KMail is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * KMail is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+
+#ifndef bodyiterator_h
+#define bodyiterator_h
+
+#include <qptrlist.h>
+#include <qstringlist.h>
+
+class KMMessagePart;
+
+namespace KMail {
+
+ class AttachmentStrategy;
+
+ // Base class
+ class BodyVisitor
+ {
+ public:
+ BodyVisitor();
+ virtual ~BodyVisitor();
+
+ /** Register the parts that should be visited */
+ void visit( KMMessagePart * part );
+ void visit( QPtrList<KMMessagePart> & list );
+
+ /** Returns a list of parts that should be loaded */
+ QPtrList<KMMessagePart> partsToLoad();
+
+ /** Decides whether a part should be loaded.
+ This needs to be implemented by a subclass */
+ virtual bool addPartToList( KMMessagePart * part ) = 0;
+
+ protected:
+ /**
+ * Checks if one of the parents needs loaded children
+ * This is e.g. needed for multipart/signed where all parts have to be loaded
+ */
+ static bool parentNeedsLoading( KMMessagePart * part );
+
+ protected:
+ QPtrList<KMMessagePart> mParts;
+ QStringList mBasicList;
+ };
+
+ // Factory to create a visitor according to the Attachment Strategy
+ class BodyVisitorFactory
+ {
+ public:
+ static BodyVisitor* getVisitor( const AttachmentStrategy* strategy );
+ };
+
+ // Visitor for smart attachment display
+ class BodyVisitorSmart: public BodyVisitor
+ {
+ public:
+ BodyVisitorSmart();
+
+ bool addPartToList( KMMessagePart * part );
+ };
+
+ // Visitor for inline attachment display
+ class BodyVisitorInline: public BodyVisitor
+ {
+ public:
+ BodyVisitorInline();
+
+ bool addPartToList( KMMessagePart * part );
+ };
+
+ // Visitor for hidden attachment display
+ class BodyVisitorHidden: public BodyVisitor
+ {
+ public:
+ BodyVisitorHidden();
+
+ bool addPartToList( KMMessagePart * part );
+ };
+
+}
+
+#endif
diff --git a/kmail/cachedimapjob.cpp b/kmail/cachedimapjob.cpp
new file mode 100644
index 00000000..8c633961
--- /dev/null
+++ b/kmail/cachedimapjob.cpp
@@ -0,0 +1,841 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ *
+ * This file is part of KMail, the KDE mail client.
+ * Copyright (c) 2002-2004 Bo Thorsen <bo@sonofthor.dk>
+ * 2002-2003 Steffen Hansen <hansen@kde.org>
+ * 2002-2003 Zack Rusin <zack@kde.org>
+ *
+ * KMail is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * KMail is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "cachedimapjob.h"
+#include "imapaccountbase.h"
+
+#include "kmfoldermgr.h"
+#include "kmfolder.h"
+#include "kmfoldercachedimap.h"
+#include "kmailicalifaceimpl.h"
+#include "kmacctcachedimap.h"
+#include "kmmsgdict.h"
+#include "maildirjob.h"
+#include "scalix.h"
+#include "util.h"
+
+#include <kio/scheduler.h>
+#include <kio/job.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+
+namespace KMail {
+
+// Get messages
+CachedImapJob::CachedImapJob( const QValueList<MsgForDownload>& msgs,
+ JobType type, KMFolderCachedImap* folder )
+ : FolderJob( type ), mFolder( folder ), mMsgsForDownload( msgs ),
+ mTotalBytes(0), mMsg(0), mParentFolder( 0 )
+{
+ QValueList<MsgForDownload>::ConstIterator it = msgs.begin();
+ for ( ; it != msgs.end() ; ++it )
+ mTotalBytes += (*it).size;
+}
+
+// Put messages
+CachedImapJob::CachedImapJob( const QPtrList<KMMessage>& msgs, JobType type,
+ KMFolderCachedImap* folder )
+ : FolderJob( msgs, QString::null, type, folder?folder->folder():0 ), mFolder( folder ),
+ mTotalBytes( msgs.count() ), // we abuse it as "total number of messages"
+ mMsg( 0 ), mParentFolder( 0 )
+{
+}
+
+CachedImapJob::CachedImapJob( const QValueList<unsigned long>& msgs,
+ JobType type, KMFolderCachedImap* folder )
+ : FolderJob( QPtrList<KMMessage>(), QString::null, type, folder?folder->folder():0 ),
+ mFolder( folder ), mSerNumMsgList( msgs ), mTotalBytes( msgs.count() ), mMsg( 0 ),
+ mParentFolder ( 0 )
+{
+}
+
+// Add sub folders
+CachedImapJob::CachedImapJob( const QValueList<KMFolderCachedImap*>& fList,
+ JobType type, KMFolderCachedImap* folder )
+ : FolderJob( type ), mFolder( folder ), mFolderList( fList ), mMsg( 0 ),
+ mParentFolder ( 0 )
+{
+}
+
+// Rename folder
+CachedImapJob::CachedImapJob( const QString& string1, JobType type,
+ KMFolderCachedImap* folder )
+ : FolderJob( type ), mFolder(folder), mMsg( 0 ), mString( string1 ),
+ mParentFolder ( 0 )
+{
+ assert( folder );
+ assert( type != tDeleteMessage ); // moved to another ctor
+}
+
+// Delete folders or messages
+CachedImapJob::CachedImapJob( const QStringList& foldersOrMsgs, JobType type,
+ KMFolderCachedImap* folder )
+ : FolderJob( type ), mFolder( folder ), mFoldersOrMessages( foldersOrMsgs ),
+ mMsg( 0 ), mParentFolder( 0 )
+{
+ assert( folder );
+}
+
+// Other jobs (list messages,expunge folder, check uid validity)
+CachedImapJob::CachedImapJob( JobType type, KMFolderCachedImap* folder )
+ : FolderJob( type ), mFolder( folder ), mMsg( 0 ), mParentFolder ( 0 )
+{
+ assert( folder );
+}
+
+CachedImapJob::~CachedImapJob()
+{
+ mAccount->mJobList.remove(this);
+}
+
+void CachedImapJob::execute()
+{
+ mSentBytes = 0;
+
+ if( !mFolder ) {
+ if( !mMsgList.isEmpty() ) {
+ mFolder = static_cast<KMFolderCachedImap*>(mMsgList.first()->storage());
+ }
+ }
+ assert( mFolder );
+ mAccount = mFolder->account();
+ assert( mAccount != 0 );
+ if( mAccount->makeConnection() != ImapAccountBase::Connected ) {
+ // No connection to the IMAP server
+ kdDebug(5006) << "mAccount->makeConnection() failed" << endl;
+ mPassiveDestructor = true;
+ delete this;
+ return;
+ } else
+ mPassiveDestructor = false;
+
+ // All necessary conditions have been met. Register this job
+ mAccount->mJobList.append(this);
+
+ /**
+ * The Scalix server requires to send him a custom X-SCALIX-ID command
+ * to switch it into a special mode.
+ *
+ * This should be done once after the login and before the first command.
+ */
+ if ( mAccount->groupwareType() == KMAcctCachedImap::GroupwareScalix ) {
+ if ( !mAccount->sentCustomLoginCommand() ) {
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+
+ const QString command = QString( "X-SCALIX-ID " );
+ const QString argument = QString( "(\"name\" \"Evolution\" \"version\" \"2.10.0\")" );
+
+ stream << (int) 'X' << 'N' << command << argument;
+
+ const KURL url = mAccount->getUrl();
+
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ jd.items << mFolder->label(); // for the err msg
+ KIO::SimpleJob *simpleJob = KIO::special( url.url(), packedArgs, false );
+ KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
+ mAccount->insertJob(simpleJob, jd);
+
+ mAccount->setSentCustomLoginCommand( true );
+ }
+ }
+
+ switch( mType ) {
+ case tGetMessage: slotGetNextMessage(); break;
+ case tPutMessage: slotPutNextMessage(); break;
+ case tDeleteMessage: slotDeleteNextMessages(); break;
+ case tExpungeFolder: expungeFolder(); break;
+ case tAddSubfolders: slotAddNextSubfolder(); break;
+ case tDeleteFolders: slotDeleteNextFolder(); break;
+ case tCheckUidValidity: checkUidValidity(); break;
+ case tRenameFolder: renameFolder(mString); break;
+ case tListMessages: listMessages(); break;
+ default:
+ assert( 0 );
+ }
+}
+
+void CachedImapJob::listMessages()
+{
+ KURL url = mAccount->getUrl();
+ url.setPath( mFolder->imapPath() + ";UID=1:*;SECTION=FLAGS RFC822.SIZE");
+
+ KIO::SimpleJob *job = KIO::get(url, false, false);
+ KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ jd.cancellable = true;
+ mAccount->insertJob( job, jd );
+ connect( job, SIGNAL( result(KIO::Job *) ),
+ this, SLOT( slotListMessagesResult( KIO::Job* ) ) );
+ // send the data directly for KMFolderCachedImap
+ connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
+ mFolder, SLOT( slotGetMessagesData( KIO::Job* , const QByteArray& ) ) );
+}
+
+void CachedImapJob::slotDeleteNextMessages( KIO::Job* job )
+{
+ if (job) {
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ if( job->error() ) {
+ mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
+ delete this;
+ return;
+ }
+ mAccount->removeJob(it);
+ }
+
+ if( mFoldersOrMessages.isEmpty() ) {
+ // No more messages to delete
+ delete this;
+ return;
+ }
+
+ QString uids = mFoldersOrMessages.front(); mFoldersOrMessages.pop_front();
+
+ KURL url = mAccount->getUrl();
+ url.setPath( mFolder->imapPath() +
+ QString::fromLatin1(";UID=%1").arg(uids) );
+
+ KIO::SimpleJob *simpleJob = KIO::file_delete( url, false );
+ KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ mAccount->insertJob( simpleJob, jd );
+ connect( simpleJob, SIGNAL( result(KIO::Job *) ),
+ this, SLOT( slotDeleteNextMessages(KIO::Job *) ) );
+}
+
+void CachedImapJob::expungeFolder()
+{
+ KURL url = mAccount->getUrl();
+ // Special URL that means EXPUNGE
+ url.setPath( mFolder->imapPath() + QString::fromLatin1(";UID=*") );
+
+ KIO::SimpleJob *job = KIO::file_delete( url, false );
+ KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ mAccount->insertJob( job, jd );
+ connect( job, SIGNAL( result(KIO::Job *) ),
+ this, SLOT( slotExpungeResult(KIO::Job *) ) );
+}
+
+void CachedImapJob::slotExpungeResult( KIO::Job * job )
+{
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ if (job->error()) {
+ mErrorCode = job->error();
+ mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
+ }
+ else
+ mAccount->removeJob(it);
+
+ delete this;
+}
+
+void CachedImapJob::slotGetNextMessage(KIO::Job * job)
+{
+ if (job) {
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ if (job->error()) {
+ mErrorCode = job->error();
+ mAccount->handleJobError( job, i18n( "Error while retrieving message on the server: " ) + '\n' );
+ delete this;
+ return;
+ }
+
+ ulong size = 0;
+ if ((*it).data.size() > 0) {
+ ulong uid = mMsg->UID();
+ size = mMsg->msgSizeServer();
+
+ // Convert CR/LF to LF.
+ size_t dataSize = (*it).data.size();
+ dataSize = Util::crlf2lf( (*it).data.data(), dataSize ); // always <=
+ (*it).data.resize( dataSize );
+
+ mMsg->setComplete( true );
+ mMsg->fromByteArray( (*it).data );
+ mMsg->setUID(uid);
+ mMsg->setMsgSizeServer(size);
+ mMsg->setTransferInProgress( false );
+ int index = 0;
+ mFolder->addMsgInternal( mMsg, true, &index );
+
+ if ( kmkernel->iCalIface().isResourceFolder( mFolder->folder() ) ) {
+ mFolder->setStatus( index, KMMsgStatusRead, false );
+ }
+
+ emit messageRetrieved( mMsg );
+ if ( index > 0 ) mFolder->unGetMsg( index );
+ } else {
+ emit messageRetrieved( 0 );
+ }
+ mMsg = 0;
+
+ mSentBytes += size;
+ emit progress( mSentBytes, mTotalBytes );
+ mAccount->removeJob(it);
+ } else
+ mFolder->quiet( true );
+
+ if( mMsgsForDownload.isEmpty() ) {
+ mFolder->quiet( false );
+ delete this;
+ return;
+ }
+
+ MsgForDownload mfd = mMsgsForDownload.front(); mMsgsForDownload.pop_front();
+
+ mMsg = new KMMessage;
+ mMsg->setUID(mfd.uid);
+ mMsg->setMsgSizeServer(mfd.size);
+ if( mfd.flags > 0 )
+ KMFolderImap::flagsToStatus(mMsg, mfd.flags, true, GlobalSettings::allowLocalFlags() ? mFolder->permanentFlags() : INT_MAX);
+ KURL url = mAccount->getUrl();
+ url.setPath(mFolder->imapPath() + QString(";UID=%1;SECTION=BODY.PEEK[]").arg(mfd.uid));
+
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ jd.cancellable = true;
+ mMsg->setTransferInProgress(true);
+ KIO::SimpleJob *simpleJob = KIO::get(url, false, false);
+ KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
+ mAccount->insertJob(simpleJob, jd);
+ connect(simpleJob, SIGNAL(processedSize(KIO::Job *, KIO::filesize_t)),
+ this, SLOT(slotProcessedSize(KIO::Job *, KIO::filesize_t)));
+ connect(simpleJob, SIGNAL(result(KIO::Job *)),
+ this, SLOT(slotGetNextMessage(KIO::Job *)));
+ connect(simpleJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
+ mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
+}
+
+void CachedImapJob::slotProcessedSize(KIO::Job *, KIO::filesize_t processed)
+{
+ emit progress( mSentBytes + processed, mTotalBytes );
+}
+
+void CachedImapJob::slotPutNextMessage()
+{
+ mMsg = 0;
+
+ // First try the message list
+ if( !mMsgList.isEmpty() ) {
+ mMsg = mMsgList.first();
+ mMsgList.removeFirst();
+ }
+
+ // Now try the serial number list
+ while( mMsg == 0 && !mSerNumMsgList.isEmpty() ) {
+ unsigned long serNum = mSerNumMsgList.first();
+ mSerNumMsgList.pop_front();
+
+ // Find the message with this serial number
+ int i = 0;
+ KMFolder* aFolder = 0;
+ KMMsgDict::instance()->getLocation( serNum, &aFolder, &i );
+ if( mFolder->folder() != aFolder )
+ // This message was moved or something
+ continue;
+ mMsg = mFolder->getMsg( i );
+ }
+
+ if( !mMsg ) {
+ // No message found for upload
+ delete this;
+ return;
+ }
+
+ KURL url = mAccount->getUrl();
+ QString flags = KMFolderImap::statusToFlags( mMsg->status(), mFolder->permanentFlags() );
+ url.setPath( mFolder->imapPath() + ";SECTION=" + flags );
+
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+
+ mMsg->setUID( 0 ); // for the index
+ QCString cstr(mMsg->asString());
+ int a = cstr.find("\nX-UID: ");
+ int b = cstr.find('\n', a);
+ if (a != -1 && b != -1 && cstr.find("\n\n") > a) cstr.remove(a, b-a);
+ QCString mData(cstr.length() + cstr.contains('\n'));
+ unsigned int i = 0;
+ for( char *ch = cstr.data(); *ch; ch++ ) {
+ if ( *ch == '\n' ) {
+ mData.at(i) = '\r';
+ i++;
+ }
+ mData.at(i) = *ch; i++;
+ }
+ jd.data = mData;
+ jd.msgList.append( mMsg );
+
+ mMsg->setTransferInProgress(true);
+ KIO::SimpleJob *simpleJob = KIO::put(url, 0, false, false, false);
+ KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
+ mAccount->insertJob(simpleJob, jd);
+ connect( simpleJob, SIGNAL( result(KIO::Job *) ),
+ SLOT( slotPutMessageResult(KIO::Job *) ) );
+ connect( simpleJob, SIGNAL( dataReq(KIO::Job *, QByteArray &) ),
+ SLOT( slotPutMessageDataReq(KIO::Job *, QByteArray &) ) );
+ connect( simpleJob, SIGNAL( data(KIO::Job *, const QByteArray &) ),
+ mFolder, SLOT( slotSimpleData(KIO::Job *, const QByteArray &) ) );
+ connect( simpleJob, SIGNAL(infoMessage(KIO::Job *, const QString &)),
+ SLOT(slotPutMessageInfoData(KIO::Job *, const QString &)) );
+
+}
+
+//-----------------------------------------------------------------------------
+// TODO: port to KIO::StoredTransferJob once it's ok to require kdelibs-3.3
+void CachedImapJob::slotPutMessageDataReq(KIO::Job *job, QByteArray &data)
+{
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+ if ((*it).data.size() - (*it).offset > 0x8000) {
+ data.duplicate((*it).data.data() + (*it).offset, 0x8000);
+ (*it).offset += 0x8000;
+ } else if ((*it).data.size() - (*it).offset > 0) {
+ data.duplicate((*it).data.data() + (*it).offset,
+ (*it).data.size() - (*it).offset);
+ (*it).offset = (*it).data.size();
+ } else
+ data.resize(0);
+}
+
+//----------------------------------------------------------------------------
+void CachedImapJob::slotPutMessageInfoData(KIO::Job *job, const QString &data)
+{
+ KMFolderCachedImap * imapFolder = static_cast<KMFolderCachedImap*>(mDestFolder->storage());
+ KMAcctCachedImap *account = imapFolder->account();
+ ImapAccountBase::JobIterator it = account->findJob( job );
+ if ( it == account->jobsEnd() ) return;
+
+ if ( data.find("UID") != -1 && mMsg )
+ {
+ int uid = (data.right(data.length()-4)).toInt();
+ kdDebug( 5006 ) << k_funcinfo << "Server told us uid is: " << uid << endl;
+ mMsg->setUID( uid );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void CachedImapJob::slotPutMessageResult(KIO::Job *job)
+{
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ if ( job->error() ) {
+ bool cont = mAccount->handlePutError( job, *it, mFolder->folder() );
+ if ( !cont ) {
+ delete this;
+ } else {
+ mMsg = 0;
+ slotPutNextMessage();
+ }
+ return;
+ }
+
+ emit messageStored( mMsg );
+
+ // we abuse those fields, the unit is the number of messages, here
+ ++mSentBytes;
+ emit progress( mSentBytes, mTotalBytes );
+
+ int i;
+ if( ( i = mFolder->find(mMsg) ) != -1 ) {
+ /*
+ * If we have aquired a uid during upload the server supports the uidnext
+ * extension and there is no need to redownload this mail, we already have
+ * it. Otherwise remove it, it will be redownloaded.
+ */
+ if ( mMsg->UID() == 0 ) {
+ mFolder->removeMsg(i);
+ } else {
+ // When removing+readding, no point in telling the imap resources about it
+ bool b = kmkernel->iCalIface().isResourceQuiet();
+ kmkernel->iCalIface().setResourceQuiet( true );
+
+ mFolder->takeTemporarily( i );
+ mFolder->addMsgKeepUID( mMsg );
+ mMsg->setTransferInProgress( false );
+
+ kmkernel->iCalIface().setResourceQuiet( b );
+ }
+ }
+ mMsg = NULL;
+ mAccount->removeJob( it );
+ slotPutNextMessage();
+}
+
+
+void CachedImapJob::slotAddNextSubfolder( KIO::Job * job )
+{
+ if (job) {
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ // make copy of setting, to reset it before potentially destroying 'it'
+ bool silentUpload = static_cast<KMFolderCachedImap*>((*it).parent->storage())->silentUpload();
+ static_cast<KMFolderCachedImap*>((*it).parent->storage())->setSilentUpload( false );
+
+ if ( job->error() && !silentUpload ) {
+ QString myError = "<p><b>" + i18n("Error while uploading folder")
+ + "</b></p><p>" + i18n("Could not make the folder <b>%1</b> on the server.").arg((*it).items[0])
+ + "</p><p>" + i18n("This could be because you do not have permission to do this, or because the folder is already present on the server; the error message from the server communication is here:") + "</p>";
+ mAccount->handleJobError( job, myError );
+ }
+
+ if( job->error() ) {
+ delete this;
+ return;
+ } else {
+ KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( (*it).current->storage() );
+ KMFolderCachedImap* parentStorage = static_cast<KMFolderCachedImap*>( (*it).parent->storage() );
+ Q_ASSERT( storage );
+ Q_ASSERT( parentStorage );
+ if ( storage->imapPath().isEmpty() ) {
+ QString path = mAccount->createImapPath( parentStorage->imapPath(), storage->folder()->name() );
+ if ( !storage->imapPathForCreation().isEmpty() )
+ path = storage->imapPathForCreation();
+ storage->setImapPath( path );
+ storage->writeConfig();
+ }
+ }
+ mAccount->removeJob( it );
+ }
+
+ if (mFolderList.isEmpty()) {
+ // No more folders to add
+ delete this;
+ return;
+ }
+
+ KMFolderCachedImap *folder = mFolderList.front();
+ mFolderList.pop_front();
+ KURL url = mAccount->getUrl();
+ QString path = mAccount->createImapPath( mFolder->imapPath(),
+ folder->folder()->name() );
+ if ( !folder->imapPathForCreation().isEmpty() ) {
+ // the folder knows it's namespace
+ path = folder->imapPathForCreation();
+ }
+ url.setPath( path );
+
+ if ( mAccount->groupwareType() != KMAcctCachedImap::GroupwareScalix ) {
+ // Associate the jobData with the parent folder, not with the child
+ // This is necessary in case of an error while creating the subfolder,
+ // so that folderComplete is called on the parent (and the sync resetted).
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ jd.items << folder->label(); // for the err msg
+ jd.current = folder->folder();
+ KIO::SimpleJob *simpleJob = KIO::mkdir(url);
+ KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
+ mAccount->insertJob(simpleJob, jd);
+ connect( simpleJob, SIGNAL(result(KIO::Job *)),
+ this, SLOT(slotAddNextSubfolder(KIO::Job *)) );
+ } else {
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+
+ const QString command = QString( "X-CREATE-SPECIAL" );
+ const QString argument = QString( "%1 %2" ).arg( Scalix::Utils::contentsTypeToScalixId( folder->contentsType() ) )
+ .arg( path );
+
+ stream << (int) 'X' << 'N' << command << argument;
+
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ jd.items << folder->label(); // for the err msg
+ jd.current = folder->folder();
+ KIO::SimpleJob *simpleJob = KIO::special( url.url(), packedArgs, false );
+ KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
+ mAccount->insertJob(simpleJob, jd);
+ connect( simpleJob, SIGNAL(result(KIO::Job *)),
+ this, SLOT(slotAddNextSubfolder(KIO::Job *)) );
+ }
+}
+
+
+void CachedImapJob::slotDeleteNextFolder( KIO::Job *job )
+{
+ if (job) {
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ mAccount->removeDeletedFolder( (*it).path );
+
+ if( job->error() ) {
+ mAccount->handleJobError( job, i18n( "Error while deleting folder %1 on the server: " ).arg( (*it).path ) + '\n' );
+ delete this;
+ return;
+ }
+ mAccount->removeJob(it);
+ }
+
+ if( mFoldersOrMessages.isEmpty() ) {
+ // No more folders to delete
+ delete this;
+ return;
+ }
+
+ QString folderPath = mFoldersOrMessages.front();
+ mFoldersOrMessages.pop_front();
+ KURL url = mAccount->getUrl();
+ url.setPath(folderPath);
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ jd.path = url.path();
+ KIO::SimpleJob *simpleJob = KIO::file_delete(url, false);
+ KIO::Scheduler::assignJobToSlave(mAccount->slave(), simpleJob);
+ mAccount->insertJob(simpleJob, jd);
+ connect( simpleJob, SIGNAL( result(KIO::Job *) ),
+ SLOT( slotDeleteNextFolder(KIO::Job *) ) );
+}
+
+void CachedImapJob::checkUidValidity()
+{
+ KURL url = mAccount->getUrl();
+ url.setPath( mFolder->imapPath() + ";UID=0:0" );
+
+ ImapAccountBase::jobData jd( url.url(), mFolder->folder() );
+ jd.cancellable = true;
+
+ KIO::SimpleJob *job = KIO::get( url, false, false );
+ KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
+ mAccount->insertJob( job, jd );
+ connect( job, SIGNAL(result(KIO::Job *)),
+ SLOT(slotCheckUidValidityResult(KIO::Job *)) );
+ connect( job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+ mFolder, SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
+}
+
+void CachedImapJob::slotCheckUidValidityResult(KIO::Job * job)
+{
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ if( job->error() ) {
+ mErrorCode = job->error();
+ mAccount->handleJobError( job, i18n( "Error while reading folder %1 on the server: " ).arg( (*it).parent->label() ) + '\n' );
+ delete this;
+ return;
+ }
+
+ // Check the uidValidity
+ QCString cstr((*it).data.data(), (*it).data.size() + 1);
+ int a = cstr.find("X-uidValidity: ");
+ if (a < 0) {
+ // Something is seriously rotten here!
+ // TODO: Tell the user that he has a problem
+ kdDebug(5006) << "No uidvalidity available for folder "
+ << mFolder->name() << endl;
+ }
+ else {
+ int b = cstr.find("\r\n", a);
+ if ( (b - a - 15) >= 0 ) {
+ QString uidv = cstr.mid(a + 15, b - a - 15);
+ // kdDebug(5006) << "New uidv = " << uidv << ", old uidv = "
+ // << mFolder->uidValidity() << endl;
+ if( !mFolder->uidValidity().isEmpty() && mFolder->uidValidity() != uidv ) {
+ // kdDebug(5006) << "Expunging the mailbox " << mFolder->name()
+ // << "!" << endl;
+ mFolder->expunge();
+ mFolder->setLastUid( 0 );
+ mFolder->clearUidMap();
+ }
+ } else
+ kdDebug(5006) << "No uidvalidity available for folder "
+ << mFolder->name() << endl;
+ }
+
+ a = cstr.find( "X-PermanentFlags: " );
+ if ( a < 0 ) {
+ kdDebug(5006) << "no PERMANENTFLAGS response? assumming custom flags are not available" << endl;
+ } else {
+ int b = cstr.find( "\r\n", a );
+ if ( (b - a - 18) >= 0 ) {
+ int flags = cstr.mid( a + 18, b - a - 18 ).toInt();
+ emit permanentFlags( flags );
+ } else {
+ kdDebug(5006) << "PERMANENTFLAGS response broken, assumming custom flags are not available" << endl;
+ }
+ }
+
+ mAccount->removeJob(it);
+ delete this;
+}
+
+
+void CachedImapJob::renameFolder( const QString &newName )
+{
+ // Set the source URL
+ KURL urlSrc = mAccount->getUrl();
+ urlSrc.setPath( mFolder->imapPath() );
+
+ // Set the destination URL - this is a bit trickier
+ KURL urlDst = mAccount->getUrl();
+ QString imapPath( mFolder->imapPath() );
+ // Destination url = old imappath - oldname + new name
+ imapPath.truncate( imapPath.length() - mFolder->folder()->name().length() - 1);
+ imapPath += newName + '/';
+ urlDst.setPath( imapPath );
+
+ ImapAccountBase::jobData jd( newName, mFolder->folder() );
+ jd.path = imapPath;
+
+ KIO::SimpleJob *simpleJob = KIO::rename( urlSrc, urlDst, false );
+ KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
+ mAccount->insertJob( simpleJob, jd );
+ connect( simpleJob, SIGNAL(result(KIO::Job *)),
+ SLOT(slotRenameFolderResult(KIO::Job *)) );
+}
+
+static void renameChildFolders( KMFolderDir* dir, const QString& oldPath,
+ const QString& newPath )
+{
+ if( dir ) {
+ KMFolderNode *node = dir->first();
+ while( node ) {
+ if( !node->isDir() ) {
+ KMFolderCachedImap* imapFolder =
+ static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
+ if ( !imapFolder->imapPath().isEmpty() )
+ // Only rename folders that have been accepted by the server
+ if( imapFolder->imapPath().find( oldPath ) == 0 ) {
+ QString p = imapFolder->imapPath();
+ p = p.mid( oldPath.length() );
+ p.prepend( newPath );
+ imapFolder->setImapPath( p );
+ renameChildFolders( imapFolder->folder()->child(), oldPath, newPath );
+ }
+ }
+ node = dir->next();
+ }
+ }
+}
+
+void CachedImapJob::slotRenameFolderResult( KIO::Job *job )
+{
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+
+ if( job->error() ) {
+ // Error, revert label change
+ QMap<QString, KMAcctCachedImap::RenamedFolder>::ConstIterator renit = mAccount->renamedFolders().find( mFolder->imapPath() );
+ Q_ASSERT( renit != mAccount->renamedFolders().end() );
+ if ( renit != mAccount->renamedFolders().end() ) {
+ mFolder->folder()->setLabel( (*renit).mOldLabel );
+ mAccount->removeRenamedFolder( mFolder->imapPath() );
+ }
+ mAccount->handleJobError( job, i18n( "Error while trying to rename folder %1" ).arg( mFolder->label() ) + '\n' );
+ } else {
+ // Okay, the folder seems to be renamed on the server,
+ // now rename it on disk
+ QString oldName = mFolder->name();
+ QString oldPath = mFolder->imapPath();
+ mAccount->removeRenamedFolder( oldPath );
+ mFolder->setImapPath( (*it).path );
+ mFolder->FolderStorage::rename( (*it).url );
+
+ if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 );
+ QString newPath = mFolder->imapPath();
+ if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 );
+ renameChildFolders( mFolder->folder()->child(), oldPath, newPath );
+ kmkernel->dimapFolderMgr()->contentsChanged();
+
+ mAccount->removeJob(it);
+ }
+ delete this;
+}
+
+void CachedImapJob::slotListMessagesResult( KIO::Job * job )
+{
+ KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
+ if ( it == mAccount->jobsEnd() ) { // Shouldn't happen
+ delete this;
+ return;
+ }
+
+ if (job->error()) {
+ mErrorCode = job->error();
+ mAccount->handleJobError( job, i18n( "Error while deleting messages on the server: " ) + '\n' );
+ }
+ else
+ mAccount->removeJob(it);
+
+ delete this;
+}
+
+//-----------------------------------------------------------------------------
+void CachedImapJob::setParentFolder( const KMFolderCachedImap* parent )
+{
+ mParentFolder = const_cast<KMFolderCachedImap*>( parent );
+}
+
+}
+
+#include "cachedimapjob.moc"
diff --git a/kmail/cachedimapjob.h b/kmail/cachedimapjob.h
new file mode 100644
index 00000000..ad5579a0
--- /dev/null
+++ b/kmail/cachedimapjob.h
@@ -0,0 +1,141 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ *
+ * This file is part of KMail, the KDE mail client.
+ * Copyright (c) 2002-2003 Bo Thorsen <bo@sonofthor.dk>
+ * 2002-2003 Steffen Hansen <hansen@kde.org>
+ * 2002-2003 Zack Rusin <zack@kde.org>
+ *
+ * KMail is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * KMail is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ */
+
+#ifndef CACHEDIMAPJOB_H
+#define CACHEDIMAPJOB_H
+
+#include "folderjob.h"
+#include <kio/job.h>
+#include <kio/global.h>
+
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <qcstring.h>
+
+class KMFolderCachedImap;
+class KMAcctCachedImap;
+class KMMessage;
+
+namespace KMail {
+
+class CachedImapJob : public FolderJob {
+ Q_OBJECT
+public:
+ /** Information about a message to be downloaded (from the 'IMAP envelope') */
+ struct MsgForDownload {
+ MsgForDownload() : uid(0),flags(0),size(0) {} // for QValueList only
+ MsgForDownload( ulong _uid, int _flags, ulong _size )
+ : uid(_uid), flags(_flags), size(_size) {}
+ ulong uid;
+ int flags;
+ ulong size;
+ };
+
+ // Get messages
+ CachedImapJob( const QValueList<MsgForDownload>& msgs,
+ JobType type = tGetMessage, KMFolderCachedImap* folder = 0 );
+ // Put messages
+ CachedImapJob( const QPtrList<KMMessage>& msgs,
+ JobType type, KMFolderCachedImap* folder=0 );
+ CachedImapJob( const QValueList<unsigned long>& msgs,
+ JobType type, KMFolderCachedImap* folder=0 );
+ // Add sub folders
+ CachedImapJob( const QValueList<KMFolderCachedImap*>& folders,
+ JobType type = tAddSubfolders,
+ KMFolderCachedImap* folder = 0 );
+ // Rename folder
+ CachedImapJob( const QString& string1, JobType type,
+ KMFolderCachedImap* folder );
+ // Delete folders or messages
+ CachedImapJob( const QStringList& foldersOrMsgs, JobType type,
+