Revision: 7440
http://mahogany.svn.sourceforge.net/mahogany/?rev=7440&view=rev
Author: vadz
Date: 2008-05-01 16:11:23 -0700 (Thu, 01 May 2008)
Log Message:
-----------
change the spam filters UI to allow using different settings for different
folders; added server-side spam filter
Modified Paths:
--------------
trunk/M/CHANGES
trunk/M/M.vcproj
trunk/M/doc/Manual.htex
trunk/M/include/SpamFilter.h
trunk/M/include/gui/wxMenuDefs.h
trunk/M/res/M.rc
trunk/M/src/gui/wxMFrame.cpp
trunk/M/src/gui/wxMainFrame.cpp
trunk/M/src/gui/wxMenuDefs.cpp
trunk/M/src/mail/Address.cpp
trunk/M/src/mail/SpamFilter.cpp
trunk/M/src/modules/spam/DspamFilter.cpp
trunk/M/src/modules/spam/HeadersFilter.cpp
Added Paths:
-----------
trunk/M/res/serverspam.bmp
trunk/M/src/icons/serverspam.xpm
trunk/M/src/modules/spam/ServerSideFilter.cpp
Modified: trunk/M/CHANGES
===================================================================
--- trunk/M/CHANGES 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/CHANGES 2008-05-01 23:11:23 UTC (rev 7440)
@@ -9,6 +9,7 @@
Release 0.68 '' September xx, 2007
---------------------------------------
+2008-05-02 VZ: Add support for server-side spam filters.
2008-04-25 VZ: Add support for filtering on individual headers to the GUI.
2008-04-23 VZ: Allow using wildcards in the headers selected to be seen.
2008-04-22 VZ: Added support for "Face:" header, similar to "X-Face:"
Modified: trunk/M/M.vcproj
===================================================================
--- trunk/M/M.vcproj 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/M.vcproj 2008-05-01 23:11:23 UTC (rev 7440)
@@ -1813,6 +1813,9 @@
<File
RelativePath=".\src\modules\spam\HeadersFilter.cpp">
</File>
+ <File
+
RelativePath=".\src\modules\spam\ServerSideFilter.cpp">
+ </File>
</Filter>
</Filter>
<Filter
Modified: trunk/M/doc/Manual.htex
===================================================================
--- trunk/M/doc/Manual.htex 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/doc/Manual.htex 2008-05-01 23:11:23 UTC (rev 7440)
@@ -75,6 +75,12 @@
this is useful to avoid sending duplicate replies to the different
addresses of the same person, for example.
\item Allow creation of filters testing individual headers in the GUI.
+ \item Add support for server-side spam filters: this is not especially
+ useful for classifying spam (as you could already check the header
+ added by the server to indicate that a message is spam), although it
+ is much simpler now, but is helpful for training the server-side
+ filters as using the \MenuCmd{Message|Spam} menu commands can now be
+ configured to do the right thing.
\end{itemize}
\subsubsection{0.67 against 0.66}
Modified: trunk/M/include/SpamFilter.h
===================================================================
--- trunk/M/include/SpamFilter.h 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/include/SpamFilter.h 2008-05-01 23:11:23 UTC (rev 7440)
@@ -117,10 +117,12 @@
This function shows the global filter dialog.
+ @param profile the profile to use for storing the options (we don't
+ change its reference count)
@param parent the parent frame for the dialog
@return true if something was changed, false otherwise
*/
- static bool Configure(wxFrame *parent);
+ static bool Configure(Profile *profile, wxFrame *parent);
/**
Allow the user to edit the parameters of a spam rule.
@@ -193,6 +195,9 @@
These methods provide a spam filter API. Client code doesn't have direct
access to them because they're invoked on all spam filters at once via
our static public methods.
+
+ The profile parameter passed to them should be used to read the options
+ use by the filter. This profile is never NULL.
*/
//@{
@@ -201,14 +206,18 @@
This is used by the public Reclassify().
*/
- virtual void DoReclassify(const Message& msg, bool isSpam) = 0;
+ virtual void DoReclassify(const Profile *profile,
+ const Message& msg,
+ bool isSpam) = 0;
/**
Train filter using this message.
This is used by the public Train().
*/
- virtual void DoTrain(const Message& msg, bool isSpam) = 0;
+ virtual void DoTrain(const Profile *profile,
+ const Message& msg,
+ bool isSpam) = 0;
/**
Process a message and return whether it is a spam.
@@ -220,7 +229,8 @@
@return true if this is a spam, false if we don't think it's a spam and
-1 if we're sure this is not a spam
*/
- virtual int DoCheckIfSpam(const Message& msg,
+ virtual int DoCheckIfSpam(const Profile *profile,
+ const Message& msg,
const String& param,
String *result) = 0;
@@ -233,7 +243,7 @@
@return the name of the icon to use or NULL
*/
- virtual const wxChar *GetOptionPageIconName() const { return NULL; }
+ virtual const char *GetOptionPageIconName() const { return NULL; }
/**
Return a pointer to the option page used for editing this spam filter
@@ -276,7 +286,11 @@
// after doing its work
static void DoLoadAll();
+ // helper: get the profile to use for this message, tries hard to return
+ // non-NULL profile (and usually succeeds)
+ static Profile *GetProfile(const Message& msg);
+
// the head of the linked list of spam filters
static SpamFilter *ms_first;
Modified: trunk/M/include/gui/wxMenuDefs.h
===================================================================
--- trunk/M/include/gui/wxMenuDefs.h 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/include/gui/wxMenuDefs.h 2008-05-01 23:11:23 UTC (rev 7440)
@@ -161,6 +161,7 @@
WXMENU_FOLDER_SEP4,
WXMENU_FOLDER_FILTERS,
WXMENU_FOLDER_WHENCE,
+ WXMENU_FOLDER_SPAM_CONFIG,
WXMENU_FOLDER_SEP5,
WXMENU_FOLDER_PROP,
WXMENU_FOLDER_END = WXMENU_FOLDER_PROP,
@@ -179,7 +180,6 @@
WXMENU_EDIT_MODULES,
WXMENU_EDIT_FILTERS,
WXMENU_EDIT_TEMPLATES,
- WXMENU_EDIT_SPAM_CONFIG,
WXMENU_EDIT_SEP3,
WXMENU_EDIT_PREF,
WXMENU_EDIT_CONFIG_SOURCES,
Modified: trunk/M/res/M.rc
===================================================================
--- trunk/M/res/M.rc 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/res/M.rc 2008-05-01 23:11:23 UTC (rev 7440)
@@ -137,9 +137,12 @@
calendar BITMAP "calendar.bmp"
#endif
-// these shouldn't be there but loaded from modules... (TODO)
+// Spam filter icons for the options dialog used for configuring them (32x32)
+//
+// TODO: they shouldn't be there at all but loaded from modules...
spam BITMAP "spam.bmp"
dspam BITMAP "../lib/dspam/dspam.bmp"
+serverspam BITMAP "serverspam.bmp"
// Folder tree bitmaps (16x16)
folder_inbox BITMAP "folder_inbox.bmp"
Added: trunk/M/res/serverspam.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/M/res/serverspam.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: trunk/M/src/gui/wxMFrame.cpp
===================================================================
--- trunk/M/src/gui/wxMFrame.cpp 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/src/gui/wxMFrame.cpp 2008-05-01 23:11:23 UTC (rev 7440)
@@ -46,7 +46,6 @@
#include "Composer.h"
#include "MImport.h"
-#include "SpamFilter.h"
#include "gui/wxFiltersDialog.h" // for ConfigureAllFilters()
#include "gui/wxOptionsDlg.h"
@@ -605,10 +604,6 @@
EditTemplates(this);
break;
- case WXMENU_EDIT_SPAM_CONFIG:
- SpamFilter::Configure(this);
- break;
-
case WXMENU_EDIT_RESTORE_PREF:
(void)ShowRestoreDefaultsDialog(mApplication->GetProfile(), this);
break;
Modified: trunk/M/src/gui/wxMainFrame.cpp
===================================================================
--- trunk/M/src/gui/wxMainFrame.cpp 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/src/gui/wxMainFrame.cpp 2008-05-01 23:11:23 UTC (rev 7440)
@@ -45,6 +45,7 @@
#include "gui/wxFiltersDialog.h" // for ConfigureFiltersForFolder
#include "gui/wxIdentityCombo.h" // for IDC_IDENT_COMBO
#include "MFolderDialogs.h" // for ShowFolderCreateDialog
+#include "SpamFilter.h" // for SpamFilter::Configure()
#include "gui/wxMDialogs.h"
#include "gui/wxMenuDefs.h"
@@ -929,6 +930,17 @@
}
break;
+ case WXMENU_FOLDER_SPAM_CONFIG:
+ {
+ MFolder_obj folder(m_FolderTree->GetSelection());
+ if ( folder )
+ {
+ Profile_obj profile(folder->GetProfile());
+ SpamFilter::Configure(profile, this);
+ }
+ }
+ break;
+
case WXMENU_FOLDER_IMPORTTREE:
// create all MBOX folders under the specified dir
{
Modified: trunk/M/src/gui/wxMenuDefs.cpp
===================================================================
--- trunk/M/src/gui/wxMenuDefs.cpp 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/src/gui/wxMenuDefs.cpp 2008-05-01 23:11:23 UTC (rev 7440)
@@ -273,7 +273,7 @@
{ WXMENU_FILE_EXIT, gettext_noop("E&xit\tCtrl-Q"),
gettext_noop("Quit the application") , wxITEM_NORMAL },
// folder
- // available accels: DGJKQVXYZ
+ // available accels: DJKQVX
{ WXMENU_FOLDER_OPEN, gettext_noop("&Open...\tCtrl-O"),
gettext_noop("Open an existing message folder") ,
wxITEM_NORMAL },
{ WXMENU_FOLDER_OPEN_RO, gettext_noop("Open read-onl&y..."),
gettext_noop("Open a folder in read only mode") ,
wxITEM_NORMAL },
{ WXMENU_FOLDER_CREATE, gettext_noop("&Create..."), gettext_noop("Create
a new folder definition") , wxITEM_NORMAL },
@@ -281,7 +281,7 @@
{ WXMENU_FOLDER_MOVE, gettext_noop("&Move..."), gettext_noop("Move the
selected folder") , wxITEM_NORMAL },
{ WXMENU_FOLDER_REMOVE, gettext_noop("&Remove from tree"),
gettext_noop("Remove the selected folder from the folder tree") ,
wxITEM_NORMAL },
{ WXMENU_FOLDER_DELETE, gettext_noop("&Delete"), gettext_noop("Delete
all messages in the folder and remove it") , wxITEM_NORMAL },
- { WXMENU_FOLDER_CLEAR, gettext_noop("C&lear..."), gettext_noop("Delete
all messages in the folder") , wxITEM_NORMAL },
+ { WXMENU_FOLDER_CLEAR, gettext_noop("&Zap..."), gettext_noop("Delete
all messages in the folder") , wxITEM_NORMAL },
{ WXMENU_FOLDER_CLOSE, gettext_noop("Clos&e"), gettext_noop("Close the
current folder") , wxITEM_NORMAL },
{ WXMENU_FOLDER_CLOSEALL, gettext_noop("Close &all"), gettext_noop("Close
all opened folders") , wxITEM_NORMAL },
{ WXMENU_SEPARATOR, "", ""
, wxITEM_NORMAL },
@@ -302,13 +302,14 @@
{ WXMENU_SEPARATOR, "", ""
, wxITEM_NORMAL },
{ WXMENU_FOLDER_FILTERS, gettext_noop("&Filters..."), gettext_noop("Edit
the filters to use for current folder") , wxITEM_NORMAL },
{ WXMENU_FOLDER_WHENCE, gettext_noop("&Where is filter..."),
gettext_noop("Find the filters which move messages to this folder")
, wxITEM_NORMAL },
+ { WXMENU_FOLDER_SPAM_CONFIG, gettext_noop("Spam fi<ers..."),
gettext_noop("Set the options spam filters options"), wxITEM_NORMAL },
{ WXMENU_SEPARATOR, "", ""
, wxITEM_NORMAL },
{ WXMENU_FOLDER_PROP, gettext_noop("&Properties..."),
gettext_noop("Show the properties of the current folder") ,
wxITEM_NORMAL },
// normal edit
// the available accelerators for this menu:
- // BHJNVWYZ
+ // ABHJNVWYZ
{ WXMENU_EDIT_CUT, gettext_noop("Cu&t\tCtrl-X"), gettext_noop("Cut
selection and copy it to clipboard") , wxITEM_NORMAL },
{ WXMENU_EDIT_COPY, gettext_noop("&Copy\tCtrl-C"), gettext_noop("Copy
selection to clipboard") , wxITEM_NORMAL },
{ WXMENU_EDIT_PASTE,gettext_noop("&Paste\tCtrl-V"), gettext_noop("Paste
from clipboard") , wxITEM_NORMAL },
@@ -322,7 +323,6 @@
{ WXMENU_EDIT_MODULES, gettext_noop("M&odules..."), gettext_noop("Choose
which extension modules to use") , wxITEM_NORMAL },
{ WXMENU_EDIT_FILTERS, gettext_noop("Filter &rules..."),
gettext_noop("Edit rules for message filtering") , wxITEM_NORMAL },
{ WXMENU_EDIT_TEMPLATES,gettext_noop("Te&mplates..."), gettext_noop("Edit
templates used for message composition") , wxITEM_NORMAL },
- { WXMENU_EDIT_SPAM_CONFIG, gettext_noop("Sp&am filters..."),
gettext_noop("Set the options for spam detection"), wxITEM_NORMAL },
{ WXMENU_SEPARATOR, "", "" ,
wxITEM_NORMAL },
{ WXMENU_EDIT_PREF, gettext_noop("Pr&eferences...\tShift-Ctrl-E"),
gettext_noop("Change options") , wxITEM_NORMAL },
{ WXMENU_EDIT_CONFIG_SOURCES, gettext_noop("Configuration so&urces..."),
gettext_noop("Edit configuration sources list"), wxITEM_NORMAL },
Added: trunk/M/src/icons/serverspam.xpm
===================================================================
--- trunk/M/src/icons/serverspam.xpm (rev 0)
+++ trunk/M/src/icons/serverspam.xpm 2008-05-01 23:11:23 UTC (rev 7440)
@@ -0,0 +1,226 @@
+/* XPM */
+static char *serverspam[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 188 2",
+" c #364878",
+". c #6B757F",
+"X c #787A76",
+"o c #9F1918",
+"O c #A10000",
+"+ c #A30000",
+"@ c #A40000",
+"# c #A50000",
+"$ c #A40100",
+"% c #A40101",
+"& c #A60000",
+"* c #A70000",
+"= c #A50202",
+"- c #A10B0B",
+"; c #B23130",
+": c #CC0000",
+"> c #CD0404",
+", c #CD0505",
+"< c #C83232",
+"1 c #C93232",
+"2 c #D63434",
+"3 c #D73636",
+"4 c #D83C3C",
+"5 c #D94040",
+"6 c #DF6464",
+"7 c #E06666",
+"8 c #7F817C",
+"9 c #82847F",
+"0 c #3F5583",
+"q c #445C8A",
+"w c #47608C",
+"e c #47608D",
+"r c #49618D",
+"t c #496390",
+"y c #4A6390",
+"u c #4C6692",
+"i c #4C6693",
+"p c #4C6793",
+"a c #4E6793",
+"s c #4F6995",
+"d c #4E6A95",
+"f c #4E6996",
+"g c #4E6A96",
+"h c #4F6A96",
+"j c #516793",
+"k c #506B95",
+"l c #566B95",
+"z c #5A6E96",
+"x c #516D98",
+"c c #506D99",
+"v c #516D99",
+"b c #516E99",
+"n c #57729B",
+"m c #5F779E",
+"M c #68799E",
+"N c #737F9D",
+"B c #6B7DA1",
+"V c #6C7DA0",
+"C c #6E7EA1",
+"Z c #6C7EA2",
+"A c #6F80A2",
+"S c #6E80A3",
+"D c #6F80A3",
+"F c #6E81A4",
+"G c #7081A3",
+"H c #7181A4",
+"J c #7081A5",
+"K c #7182A4",
+"L c #7082A5",
+"P c #7182A5",
+"I c #7283A4",
+"U c #7082A6",
+"Y c #7283A6",
+"T c #7084A6",
+"R c #7284A6",
+"E c #7285A6",
+"W c #7285A7",
+"Q c #7386A7",
+"! c #7484A5",
+"~ c #7584A6",
+"^ c #7485A7",
+"/ c #7585A7",
+"( c #7685A7",
+") c #7586A7",
+"_ c #7085A8",
+"` c #7285A8",
+"' c #7386A8",
+"] c #7387A9",
+"[ c #7387AA",
+"{ c #7586A8",
+"} c #7487A8",
+"| c #7587A9",
+" . c #7688A9",
+".. c #7588AA",
+"X. c #7488AB",
+"o. c #7589AB",
+"O. c #7688AA",
+"+. c #748AAC",
+"@. c #758AAC",
+"#. c #768BAC",
+"$. c #778BAE",
+"%. c #838580",
+"&. c #868883",
+"*. c #878984",
+"=. c #888A85",
+"-. c #898C86",
+";. c #969695",
+":. c #A2A2A2",
+">. c #A4A4A3",
+",. c #A4A5A3",
+"<. c #A9A9A8",
+"1. c #A9A9A9",
+"2. c #A9AAA9",
+"3. c #AAAAA9",
+"4. c #ACACAB",
+"5. c #ADADAC",
+"6. c #B0B1AF",
+"7. c #B6B7B3",
+"8. c #BABDB7",
+"9. c #BCBDB9",
+"0. c #BCBEB9",
+"q. c #BDBDBB",
+"w. c #E98F8F",
+"e. c #D2BFBD",
+"r. c #C0C0BF",
+"t. c #C2C4BF",
+"y. c #C0C2C2",
+"u. c #C3C4C0",
+"i. c #C6C7C4",
+"p. c #C6C7C5",
+"a. c gray78",
+"s. c #C7C8C6",
+"d. c #C9CCC7",
+"f. c #CBCBCA",
+"g. c #CBCCC8",
+"h. c #CCCCCA",
+"j. c #C8CCCD",
+"k. c #CDCDCC",
+"l. c #D2D3D0",
+"z. c #D2D4D1",
+"x. c #D3D4D1",
+"c. c #D3D6D0",
+"v. c #D4D4D3",
+"b. c #D4D5D3",
+"n. c #D6D6D5",
+"m. c #D6D8D5",
+"M. c #D7D8D6",
+"N. c #D5D7DA",
+"B. c #D9DAD8",
+"V. c #DADBD9",
+"C. c #DBDBD9",
+"Z. c #DADDD8",
+"A. c #DCDDDB",
+"S. c #DCDEDB",
+"D. c #DDDDDC",
+"F. c #DFDFDC",
+"G. c #DEDEDD",
+"H. c #DEDFDD",
+"J. c #DDE0DB",
+"K. c #DFE0DE",
+"L. c #DFE1DE",
+"P. c #DFE0DF",
+"I. c #E0E1DE",
+"U. c #E0E1DF",
+"Y. c #E1E1DF",
+"T. c #E0E3DE",
+"R. c gray88",
+"E. c #E1E1E0",
+"W. c #E1E3E0",
+"Q. c #E1E2E1",
+"!. c #E2E3E1",
+"~. c #E2E3E2",
+"^. c #E3E3E2",
+"/. c #E3E4E1",
+"(. c #E3E5E1",
+"). c #E3E4E2",
+"_. c #E4E4E2",
+"`. c #E4E5E2",
+"'. c #E5E5E2",
+"]. c #E5E6E3",
+"[. c #E5E6E4",
+"{. c #E5E7E4",
+"}. c #E5E7E5",
+"|. c #E6E7E4",
+" X c #E6E8E5",
+".X c #EDEEED",
+"XX c gray100",
+"oX c None",
+/* pixels */
+"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoXoX9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 X oXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoX9 _.l.l.l.l.l.l.l.l.l.l.l.l.l.l.R.9 oXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoX9 D. Z.b.9 oXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoX9 G. ( ~ ! I H G A C V V M t.p.9 oXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoX9 P. ) / ^ Y P K D S Z B z (.n.9 oXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoX9 G. .{ Q E R L J F l r q t.i.9 oXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoX9 H. O.| } ' W T U j e e w (.m.9 oXoXoX",
+"oXoXoXoXoXoXoXoXoXoXoX9 K. o...] ] ` _ a y t y t 0.s.9 oXoXoX",
+"oXoXoX9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 . p u u p i (.B.9 oXoXoX",
+"oXoX9 _.l.l.l.l.l.l.l.l.l.l.l.l.l.l.N.9 g s g f h (.V.9 oXoXoX",
+"oXoX9 D. 0 Z.j.9 x v b x c (.S.9 oXoXoX",
+"oXoX9 G. ( ~ ! I H G A C V V M t.y.9 J.F.9 oXoXoX",
+"oXoX9 P. ) / ^ Y P K D S Z B z (.v.9 8.J.T.T.T.T.c.I.9 oXoXoX",
+"oXoX9 G. .{ Q E R L J F l r q t.i.9 '.`.`.).^.~.~.d.9 oXoXoX",
+"oXoX9 H. O.| } ' W T U j e e w (.z.9 -.-.-.-.-.-.-.%.oXoXoXoX",
+"oXoX9 K. o...] ] ` _ a y t y t 0.s.9 g.u.9.7.8 9 %.&.*.*.oXoX",
+"oXoX9 U. [EMAIL PROTECTED] m k p u u p i (.M.9 =.=.=.=.=.=.=.oXoXoX*.oX",
+"oXoX9 W. $.#.+.n h d g s g f h (.e.o = @ @ @ @ @ @ @ @ $ - oX",
+"oXoX9 !. b v x v v v x v b x c (.; < 6 7 7 7 7 7 7 7 7 6 1 + ",
+"oXoX9 [. N J.= 6 , : : : : : : : : , 6 # ",
+"oXoX9 |.c.(.(.(.T.8.8.8.J.T.T.T.T.c.@ 7 : > 4 : : : : 5 > : 7 @ ",
+"oXoX9 C. X}.{.{.[.[.].'.`.`.).^.~.~.@ 7 : 3 XXw.: : w.XX2 : 7 @ ",
+"oXoXoX9 9 9 9 9 9 9 9 -.-.-.-.-.-.-.@ 7 : : w.XXw.w.XXw.: : 7 @ ",
+"oXoXoXoXoX9 u.x.A.A.x.g.u.9.7.8 9 %.@ 7 : : : w.XXXXw.: : : 7 @ ",
+"oXoXoXoX=.=.=.=.=.=.=.=.=.=.=.=.=.=.@ 7 : : : w.XXXXw.: : : 7 @ ",
+"oXoXoX=.:.6.h.4.4.4.4.4.4.5.:.a.r.;.@ 7 : : w.XXw.w.XXw.: : 7 @ ",
+"oXoX=.>.s.q.1.2.2.3.3.3.3.f.<.<.k.,.@ 7 : 2 XXw.: : w.XX3 : 7 @ ",
+"oX=..XE./.Y.Y.U.Y.Y.Y.Y.Y.~.L.L.Q.[.@ 7 : > 5 : : : : 4 > : 7 @ ",
+"oX&.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.% 6 , : : : : : : : : , 6 # ",
+"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXO 1 6 7 7 7 7 7 7 7 7 6 1 * ",
+"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX& # @ @ @ @ @ @ @ @ # & oX"
+};
Modified: trunk/M/src/mail/Address.cpp
===================================================================
--- trunk/M/src/mail/Address.cpp 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/src/mail/Address.cpp 2008-05-01 23:11:23 UTC (rev 7440)
@@ -388,7 +388,7 @@
}
/* static */
-String Address::GetSenderAddress(Profile *profile)
+String Address::GetSenderAddress(const Profile *profile)
{
String email(READ_CONFIG_TEXT(profile, MP_FROM_ADDRESS));
Modified: trunk/M/src/mail/SpamFilter.cpp
===================================================================
--- trunk/M/src/mail/SpamFilter.cpp 2008-05-01 23:08:16 UTC (rev 7439)
+++ trunk/M/src/mail/SpamFilter.cpp 2008-05-01 23:11:23 UTC (rev 7440)
@@ -36,6 +36,8 @@
#include "gui/wxOptionsPage.h"
#include "gui/wxOptionsDlg.h"
+#include "Message.h"
+
#include "SpamFilter.h"
// ----------------------------------------------------------------------------
@@ -46,9 +48,43 @@
static const wxChar FILTERS_SEPARATOR = _T(';');
// ----------------------------------------------------------------------------
-// local types
+// local functions
// ----------------------------------------------------------------------------
+namespace
+{
+
+/**
+ Return the name in which the status (enabled or disabled) of the given
+ filter is stored in the config.
+ */
+inline String GetSpamFilterKeyName(const char *name)
+{
+ return String::Format("UseSpamFilter_%s", name);
+}
+
+/**
+ Return true if the given filter is enabled in the specified profile.
+ */
+inline bool IsSpamFilterEnabled(const Profile *profile, const char *name)
+{
+ return profile->readEntry(GetSpamFilterKeyName(name), true);
+}
+
+/**
+ Enable or disable the given spam filter.
+ */
+inline void EnableSpamFilter(Profile *profile, const char *name, bool enable)
+{
+ profile->writeEntry(GetSpamFilterKeyName(name), enable);
+}
+
+} // anonymous namespace
+
+// ----------------------------------------------------------------------------
+// local classes
+// ----------------------------------------------------------------------------
+
class SpamOptionsDialog : public wxOptionsEditDialog
{
public:
@@ -62,25 +98,79 @@
{
m_profile = profile;
m_imagelist = imagelist;
+ m_chkEnable = NULL;
CreateAllControls();
Fit();
Layout();
}
+ virtual wxControl *CreateControlsAbove(wxPanel *panel)
+ {
+ wxControl *last = NULL;
+
+ last = CreateMessage(panel,
+ _("This dialog is used to configure the options of the individual "
+ "spam filters and\n"
+ "to select whether they are used for the \"Message|Spam\" menu "
+ "commands.\n"
+ "\n"
+ "Notice that you still need to configure a filter rule with a "
+ "\"Check if spam\" test\n"
+ "to actually use the spam filters configured here.\n"), last);
+
+ m_chkEnable = CreateCheckBox(panel,
+ _("&Use the selected filter"),
+ -1, // no max width as we have just one field
+ last);
+ last = m_chkEnable;
+
+ Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
+ wxCommandEventHandler(SpamOptionsDialog::OnCheckBox));
+
+ return last;
+ }
+
virtual void CreateNotebook(wxPanel *panel)
{
m_notebook = new wxPNotebook(_T("SpamOptions"), panel);
+ Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
+ wxNotebookEventHandler(SpamOptionsDialog::OnPageChanged));
+
if ( m_imagelist )
m_notebook->AssignImageList(m_imagelist);
// now we can put the pages into it
for ( SpamFilter *p = SpamFilter::ms_first; p; p = p->m_next )
{
+ // update internal data first so that our OnPageChanged() handler
+ // could use it when it's called from CreateOptionsPage() below
+ const String name = p->GetName();
+ m_used.push_back(IsSpamFilterEnabled(m_profile, name));
+ m_names.push_back(name);
+
p->CreateOptionPage(m_notebook, m_profile);
}
}
+ virtual bool TransferDataFromWindow()
+ {
+ if ( !wxOptionsEditDialog::TransferDataFromWindow() )
+ return false;
+
+ // update the data in the config
+ const size_t count = m_used.size();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ const String& name = m_names[n];
+ const bool used = m_used[n] != false;
+ if ( IsSpamFilterEnabled(m_profile, name) != used )
+ EnableSpamFilter(m_profile, name, used);
+ }
+
+ return true;
+ }
+
protected:
virtual Profile *GetProfile() const
{
@@ -89,8 +179,39 @@
}
private:
+ // update the internal data from checkbox value
+ void OnCheckBox(wxCommandEvent& event)
+ {
+ if ( event.GetEventObject() != m_chkEnable )
+ return;
+
+ const int sel = m_notebook->GetSelection();
+ CHECK_RET( sel != wxNOT_FOUND, "no active page?" );
+
+ m_used[sel] = m_chkEnable->GetValue();
+
+ SetDirty();
+ }
+
+ // update the checkbox from internal data
+ void OnPageChanged(wxNotebookEvent& event)
+ {
+ const int sel = event.GetSelection();
+ if ( sel != wxNOT_FOUND )
+ m_chkEnable->SetValue(m_used[sel] != false);
+ }
+
+
Profile *m_profile;
wxImageList *m_imagelist;
+ wxCheckBox *m_chkEnable;
+
+ // the names of the spam filters, indexed by their order in the notebook
+ wxArrayString m_names;
+
+ // the boolean value of the checkbox indicating whether the filter should be
+ // used for each of the pages, indexed by their order in the notebook
+ wxArrayInt m_used;
};
// ----------------------------------------------------------------------------
@@ -166,6 +287,18 @@
return NULL;
}
+/* static */
+Profile *SpamFilter::GetProfile(const Message& msg)
+{
+ Profile *profile = msg.GetProfile();
+ if ( !profile )
+ profile = mApplication->GetProfile();
+
+ ASSERT_MSG( profile, "should have some profile to use" );
+
+ return profile;
+}
+
// ----------------------------------------------------------------------------
// forward the real operations to all filters in the spam chain
// ----------------------------------------------------------------------------
@@ -173,22 +306,32 @@
/* static */
void SpamFilter::Reclassify(const Message& msg, bool isSpam)
{
+ Profile * const profile = GetProfile(msg);
+ if ( !profile )
+ return;
+
LoadAll();
for ( SpamFilter *p = ms_first; p; p = p->m_next )
{
- p->DoReclassify(msg, isSpam);
+ if ( IsSpamFilterEnabled(profile, p->GetName()) )
+ p->DoReclassify(profile, msg, isSpam);
}
}
/* static */
void SpamFilter::Train(const Message& msg, bool isSpam)
{
+ Profile * const profile = GetProfile(msg);
+ if ( !profile )
+ return;
+
LoadAll();
for ( SpamFilter *p = ms_first; p; p = p->m_next )
{
- p->DoTrain(msg, isSpam);
+ if ( IsSpamFilterEnabled(profile, p->GetName()) )
+ p->DoTrain(profile, msg, isSpam);
}
}
@@ -198,6 +341,10 @@
const String& paramsAll,
String *result)
{
+ Profile * const profile = GetProfile(msg);
+ if ( !profile )
+ return false;
+
LoadAll();
// break down the parameters (if we have any) into names and values
@@ -236,7 +383,7 @@
// now try all filters in turn until one of them returns true
for ( SpamFilter *p = ms_first; p; p = p->m_next )
{
- const String& name(p->GetName());
+ const String name(p->GetName());
String param;
if ( !paramsAll.empty() )
@@ -250,13 +397,17 @@
param = values[(size_t)n];
}
- //else: use all filters
+ else // use only configured filters
+ {
+ if ( !IsSpamFilterEnabled(profile, p->GetName()) )
+ continue;
+ }
// DoCheckIfSpam() may return -1 in addition to true or false which is
// treated as "definitively false", i.e. not only this spam filter didn't
// recognize this message as spam but it shouldn't be even checked with
// the others (this is mainly used for whitelisting support)
- switch ( p->DoCheckIfSpam(msg, param, result) )
+ switch ( p->DoCheckIfSpam(profile, msg, param, result) )
{
case true:
if ( result )
@@ -292,7 +443,7 @@
// ----------------------------------------------------------------------------
/* static */
-bool SpamFilter::Configure(wxFrame *parent)
+bool SpamFilter::Configure(Profile *profile, wxFrame *parent)
{
LoadAll();
@@ -304,7 +455,7 @@
size_t nPages = 0;
for ( SpamFilter *p = ms_first; p; p = p->m_next )
{
- const wxChar *iconname = p->GetOptionPageIconName();
+ const char * const iconname = p->GetOptionPageIconName();
if ( iconname )
{
nPages++;
@@ -321,17 +472,11 @@
}
- // now we must select a profile from which the filters options will be read
- // from and written to
- Profile_obj profile(Profile::CreateModuleProfile(SPAM_FILTER_INTERFACE));
-
// do create the dialog (this will create all the pages inside its
// CreateNotebook()) and show it
SpamOptionsDialog dlg(parent, profile, imagelist);
- bool ok = dlg.ShowModal() == wxID_OK;
-
- return ok;
+ return dlg.ShowModal() == wxID_OK;
}
/* static */
Modified: trunk/M/src/modules/spam/DspamFilter.cpp
===================================================================
--- trunk/M/src/modules/spam/DspamFilter.cpp 2008-05-01 23:08:16 UTC (rev
7439)
+++ trunk/M/src/modules/spam/DspamFilter.cpp 2008-05-01 23:11:23 UTC (rev
7440)
@@ -176,12 +176,17 @@
void Train(wxWindow *parent);
protected:
- virtual void DoReclassify(const Message& msg, bool isSpam);
- virtual void DoTrain(const Message& msg, bool isSpam);
- virtual int DoCheckIfSpam(const Message& msg,
+ virtual void DoReclassify(const Profile *profile,
+ const Message& msg,
+ bool isSpam);
+ virtual void DoTrain(const Profile *profile,
+ const Message& msg,
+ bool isSpam);
+ virtual int DoCheckIfSpam(const Profile *profile,
+ const Message& msg,
const String& param,
String *result);
- virtual const wxChar *GetOptionPageIconName() const { return _T("dspam"); }
+ virtual const char *GetOptionPageIconName() const { return "dspam"; }
virtual SpamOptionsPage *CreateOptionPage(wxListOrNoteBook *notebook,
Profile *profile) const;
@@ -341,14 +346,18 @@
return true;
}
-void DspamFilter::DoReclassify(const Message& msg, bool isSpam)
+void DspamFilter::DoReclassify(const Profile * /* profile */,
+ const Message& msg,
+ bool isSpam)
{
ClassifyContextHandler handler(ClassifyContextHandler::Reclassify, isSpam);
DoProcess(msg, handler);
}
-void DspamFilter::DoTrain(const Message& msg, bool isSpam)
+void DspamFilter::DoTrain(const Profile * /* profile */,
+ const Message& msg,
+ bool isSpam)
{
ClassifyContextHandler handler(ClassifyContextHandler::Train, isSpam);
@@ -356,7 +365,8 @@
}
int
-DspamFilter::DoCheckIfSpam(const Message& msg,
+DspamFilter::DoCheckIfSpam(const Profile * /* profile */,
+ const Message& msg,
const String& param,
String *result)
{
@@ -526,7 +536,7 @@
Message_obj msg(mf->GetMessage(hi->GetUId()));
if ( msg )
{
- DoTrain(*msg, isSpam);
+ DoTrain(NULL /* unused */, *msg, isSpam);
continue;
}
Modified: trunk/M/src/modules/spam/HeadersFilter.cpp
===================================================================
--- trunk/M/src/modules/spam/HeadersFilter.cpp 2008-05-01 23:08:16 UTC (rev
7439)
+++ trunk/M/src/modules/spam/HeadersFilter.cpp 2008-05-01 23:11:23 UTC (rev
7440)
@@ -206,12 +206,25 @@
HeadersFilter() { }
protected:
- virtual void DoReclassify(const Message& msg, bool isSpam);
- virtual void DoTrain(const Message& msg, bool isSpam);
- virtual int DoCheckIfSpam(const Message& msg,
+ virtual void DoReclassify(const Profile * /* profile */,
+ const Message& /* msg */,
+ bool /* isSpam */)
+ {
+ // this filter can't be trained
+ }
+
+ virtual void DoTrain(const Profile * /* profile */,
+ const Message& /* msg */,
+ bool /* isSpam */)
+ {
+ // this filter can't be trained
+ }
+
+ virtual int DoCheckIfSpam(const Profile *profile,
+ const Message& msg,
const String& param,
String *result);
- virtual const wxChar *GetOptionPageIconName() const { return _T("spam"); }
+ virtual const char *GetOptionPageIconName() const { return "spam"; }
virtual SpamOptionsPage *CreateOptionPage(wxListOrNoteBook *notebook,
Profile *profile) const;
@@ -399,9 +412,6 @@
public:
HeadersOptionsPage(wxListOrNoteBook *notebook, Profile *profile);
- void FromString(const String &source);
- String ToString();
-
private:
ConfigValueDefault *GetConfigValues();
FieldInfo *GetFieldInfo();
@@ -1053,18 +1063,9 @@
// HeadersFilter itself
// ----------------------------------------------------------------------------
-void HeadersFilter::DoReclassify(const Message& /* msg */, bool /* isSpam */)
-{
- // we're too stupid to allow user to correct our erros -- nothing to do
-}
-
-void HeadersFilter::DoTrain(const Message& /* msg */, bool /* isSpam */)
-{
- // we're too stupid to be trained -- nothing to do
-}
-
int
-HeadersFilter::DoCheckIfSpam(const Message& msg,
+HeadersFilter::DoCheckIfSpam(const Profile *profile,
+ const Message& msg,
const String& param,
String *result)
{
@@ -1072,9 +1073,6 @@
size_t n;
if ( tests.empty() )
{
- // use defaults
- Profile_obj profile(Profile::CreateModuleProfile(SPAM_FILTER_INTERFACE));
-
for ( n = 0; n < Spam_Test_Max; n++ )
{
const SpamTestDesc& desc = spamTestDescs[n];
@@ -1328,60 +1326,6 @@
}
}
-void HeadersOptionsPage::FromString(const String &source)
-{
- if ( source.empty() )
- {
- SetDefaults();
- return;
- }
-
- SetFalse();
-
- const wxArrayString tests = strutil_restore_array(source);
-
- const size_t count = tests.GetCount();
- for ( size_t token = 0; token < count; token++ )
- {
- const wxString& actual = tests[token];
-
- HeadersOptionsPage::Iterator option(this);
- while ( !option.IsEnd() )
- {
- if ( actual == option->Token() )
- {
- option->m_active = true;
- break;
- }
-
- ++option;
- }
-
- if ( option.IsEnd() )
- {
- FAIL_MSG(String::Format(_T("Unknown spam test \"%s\""),
actual.c_str()));
- }
- }
-}
-
-String HeadersOptionsPage::ToString()
-{
- String result;
-
- for ( HeadersOptionsPage::Iterator option(this); !option.IsEnd(); ++option )
- {
- if ( option->m_active )
- {
- if ( !result.empty() )
- result += _T(':');
-
- result += option->Token();
- }
- }
-
- return result;
-}
-
ConfigValueDefault *HeadersOptionsPage::GetConfigValues()
{
// ConfigValueDefault doesn't have default ctor, so use this hack knowing
Added: trunk/M/src/modules/spam/ServerSideFilter.cpp
===================================================================
--- trunk/M/src/modules/spam/ServerSideFilter.cpp
(rev 0)
+++ trunk/M/src/modules/spam/ServerSideFilter.cpp 2008-05-01 23:11:23 UTC
(rev 7440)
@@ -0,0 +1,377 @@
+///////////////////////////////////////////////////////////////////////////////
+// Project: M - cross platform e-mail GUI client
+// File name: src/modules/spam/ServerSideFilter.cpp
+// Purpose: SpamFilter implementation using server-side filtering
+// Author: Vadim Zeitlin
+// Created: 2008-04-28
+// CVS-ID: $Id$
+// Copyright: (c) 2008 Vadim Zeitlin <[EMAIL PROTECTED]>
+// Licence: M licence
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "Mpch.h"
+
+#ifndef USE_PCH
+ #include "Mcommon.h"
+
+ #include "MApplication.h"
+#endif //USE_PCH
+
+#include "MFolder.h"
+#include "MailFolder.h"
+#include "Message.h"
+#include "HeaderInfo.h"
+#include "UIdArray.h"
+#include "SendMessage.h"
+
+#include "SpamFilter.h"
+#include "gui/SpamOptionsPage.h"
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// names for the options we use (all are empty strings by default)
+static const char *SRV_SPAM_HEADER_NAME = "ServerSpamHeaderName";
+static const char *SRV_SPAM_HEADER_VALUE = "ServerSpamHeaderValue";
+static const char *SRV_SPAM_FOLDER = "ServerSpamFolder";
+static const char *SRV_SPAM_BOUNCE_HAM = "ServerSpamBounceHam";
+static const char *SRV_SPAM_BOUNCE_SPAM = "ServerSpamBounceSpam";
+
+// ----------------------------------------------------------------------------
+// ServerSideFilter class
+// ----------------------------------------------------------------------------
+
+class ServerSideFilter : public SpamFilter
+{
+public:
+ ServerSideFilter() { }
+
+protected:
+ virtual void DoReclassify(const Profile *profile,
+ const Message& msg,
+ bool isSpam);
+ virtual void DoTrain(const Profile *profile,
+ const Message& msg,
+ bool isSpam);
+ virtual int DoCheckIfSpam(const Profile *profile,
+ const Message& msg,
+ const String& param,
+ String *result);
+ virtual const char *GetOptionPageIconName() const { return "serverspam"; }
+ virtual SpamOptionsPage *CreateOptionPage(wxListOrNoteBook *notebook,
+ Profile *profile) const;
+
+private:
+ DECLARE_SPAM_FILTER("serverside", _("Server Side"), 10);
+};
+
+IMPLEMENT_SPAM_FILTER(ServerSideFilter,
+ gettext_noop("Server-Side Spam Filter"),
+ "(c) 2008 Vadim Zeitlin <[EMAIL PROTECTED]>");
+
+// ----------------------------------------------------------------------------
+// ServerSideOptionsPage
+// ----------------------------------------------------------------------------
+
+class ServerSideOptionsPage : public SpamOptionsPage
+{
+public:
+ ServerSideOptionsPage(const ServerSideFilter *filter,
+ wxNotebook *parent,
+ Profile *profile);
+
+private:
+ ServerSideFilter *m_filter;
+};
+
+// ============================================================================
+// ServerSideFilter implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// ServerSideFilter public API implementation
+// ----------------------------------------------------------------------------
+
+void
+ServerSideFilter::DoReclassify(const Profile *profile,
+ const Message& msg,
+ bool isSpam)
+{
+ const String folder = profile->readEntry(SRV_SPAM_FOLDER);
+ if ( !folder.empty() )
+ {
+ if ( !isSpam )
+ {
+ wxLogMessage(_("Server-side filter using spam folder can only "
+ "reclassify messages as spam by moving them into "
+ "this folder. To classify a message as non-spam it is "
+ "enough to move it out of the junk folder."));
+ return;
+ }
+
+ String reason; // explanation of why error happened (if it did)
+ MailFolder * const mf = msg.GetFolder();
+ if ( !mf )
+ {
+ reason = _("failed to get the folder containing the message");
+ }
+ else
+ {
+ UIdArray uids;
+ uids.push_back(msg.GetUId());
+ if ( !mf->SaveMessages(&uids, folder) )
+ reason = _("failed to copy message to the spam folder ") + folder;
+ }
+
+ if ( !reason.empty() )
+ {
+ wxLogError(_("Error while reclassifying the message: %s."),
+ reason.c_str());
+ }
+ }
+ else // reclassify by bouncing to some address
+ {
+ const String addr = profile->readEntry(isSpam ? SRV_SPAM_BOUNCE_SPAM
+ : SRV_SPAM_BOUNCE_HAM);
+ if ( addr.empty() )
+ {
+ wxLogWarning(_("You need to configure either a server-side folder "
+ "containing spam or the address to bounce messages "
+ "to in order to train the server-side spam filter."));
+ return;
+ }
+
+ SendMessage::Bounce(addr, profile, msg);
+ }
+}
+
+void
+ServerSideFilter::DoTrain(const Profile * /* profile */,
+ const Message& /* msg */,
+ bool /* isSpam */)
+{
+ wxLogError(_("Server-side spam filter can't be trained from the client."));
+}
+
+int
+ServerSideFilter::DoCheckIfSpam(const Profile *profile,
+ const Message& msg,
+ const String& param,
+ String *result)
+{
+ // first get the header to check: if any of the required values are not set,
+ // this filter is not used at all so we simply return false
+ const String headerName = profile->readEntry(SRV_SPAM_HEADER_NAME);
+ if ( headerName.empty() )
+ return false;
+
+ const String headerValue = profile->readEntry(SRV_SPAM_HEADER_VALUE);
+ if ( headerValue.empty() )
+ return false;
+
+
+ // do check the configured header
+ String value;
+ if ( !msg.GetHeaderLine(headerName, value) )
+ return false;
+
+ if ( !value.StartsWith(headerValue) )
+ return false;
+
+ if ( result )
+ result->Printf("%s: %s", headerName.c_str(), headerValue.c_str());
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// ServerSideFilter user-configurable options
+// ----------------------------------------------------------------------------
+
+SpamOptionsPage *
+ServerSideFilter::CreateOptionPage(wxListOrNoteBook *notebook,
+ Profile *profile) const
+{
+ return new ServerSideOptionsPage(this, notebook, profile);
+}
+
+// ============================================================================
+// ServerSideOptionsPage implementation
+// ============================================================================
+
+enum
+{
+ ServerSidePageField_Help,
+ ServerSidePageField_HeaderHelp,
+ ServerSidePageField_Header,
+ ServerSidePageField_ValueHelp,
+ ServerSidePageField_Value,
+ ServerSidePageField_SpamFolderHelp,
+ ServerSidePageField_SpamFolder,
+ ServerSidePageField_BounceHelp,
+ ServerSidePageField_HamBounce,
+ ServerSidePageField_SpamBounce,
+ ServerSidePageField_Max
+};
+
+ServerSideOptionsPage::ServerSideOptionsPage(const ServerSideFilter *filter,
+ wxListOrNoteBook *notebook,
+ Profile *profile)
+ : SpamOptionsPage(notebook, profile)
+{
+ static const wxOptionsPage::FieldInfo s_fields[] =
+ {
+ {
+ gettext_noop
+ (
+ "This page is used for configuring Mahogany integration\n"
+ "with a server-side spam filter. Such filters are operated\n"
+ "by some ISPs and typically insert special headers in the\n"
+ "incoming messages indicating whether an email was recognized\n"
+ "as spam.\n"
+ "\n"
+ "If the filter is of probabilistic nature, there should also\n"
+ "be a way to train it, i.e. correct its mistakes when it wrongly\n"
+ "classifies a non-spam message as ham or, on the contrary,
doesn't\n"
+ "recognize a spam. This is usually done either by resending the\n"
+ "message which was incorrectly classified to some special
address\n"
+ "or moving it to a special \"Spam\" folder and you should choose\n"
+ "the appropriate option below.\n"
+ "\n"
+ "Notice that operation of server-side filter is not under
Mahogany\n"
+ "control. If you prefer to do spam checks locally, please use\n"
+ "the high-quality integrated DSPAM filter instead of this one.\n"
+ ),
+ wxOptionsPage::Field_Message,
+ -1
+ },
+
+ {
+ gettext_noop
+ (
+ "\n"
+ "Enter the name of the header added by the server-side filter.\n"
+ "For example, use \"X-Spam-Flag\" for SpamAssasin or\n"
+ "\"X-DSPAM-Result\" for DSPAM."
+ ),
+ wxOptionsPage::Field_Message,
+ -1
+ },
+ {
+ gettext_noop("&Header to check"),
+ wxOptionsPage::Field_Text,
+ -1
+ },
+
+ {
+ gettext_noop
+ (
+ "\n"
+ "Enter the value of the header selected above indicating that\n"
+ "the message is spam. E.g. use \"YES\" with \"X-Spam-Flag\" or\n"
+ "\"Spam\" with \"X-DSPAM-Result\". This value must match (case-"
+ "sensitively)\n"
+ "in the beginning of the string for the message to be recognized "
+ "as spam."
+ ),
+ wxOptionsPage::Field_Message,
+ ServerSidePageField_Header
+ },
+ {
+ gettext_noop("&Value indicating spam"),
+ wxOptionsPage::Field_Text,
+ ServerSidePageField_Header
+ },
+
+ {
+ gettext_noop
+ (
+ "\n\n"
+ "If the message reclassification is done by moving it in a
special\n"
+ "folder, select it here. Otherwise leave it empty and, if the\n"
+ "filter supports reclassification at all, fill in the addresses
below."
+ ),
+ wxOptionsPage::Field_Message,
+ -1
+ },
+ {
+ gettext_noop("Server &folder for spam"),
+ wxOptionsPage::Field_Folder,
+ -1
+ },
+
+ {
+ gettext_noop
+ (
+ "When the message was mistakenly recognized as spam, the\n"
+ "\"Mark as ham\" menu command will resend it to the first
address\n"
+ "(typically something like [EMAIL PROTECTED]). When a\n"
+ "spam message was not recognized as such, the \"Dispose as
spam\"\n"
+ "command will resend it to the second address."
+ ),
+ wxOptionsPage::Field_Message,
+ -ServerSidePageField_SpamFolder
+ },
+ {
+ gettext_noop("Resend &non-spam to"),
+ wxOptionsPage::Field_Text,
+ -ServerSidePageField_SpamFolder
+ },
+ {
+ gettext_noop("Resend &spam to"),
+ wxOptionsPage::Field_Text,
+ -ServerSidePageField_SpamFolder
+ },
+ };
+
+ wxCOMPILE_TIME_ASSERT2( WXSIZEOF(s_fields) == ServerSidePageField_Max,
+ FieldsNotInSync, ServerSideFields );
+
+
+ #define CONFIG_STR(name) ConfigValueDefault(name, "")
+ #define CONFIG_NONE() ConfigValueNone()
+
+ static const ConfigValueDefault s_values[] =
+ {
+ CONFIG_NONE(),
+ CONFIG_NONE(),
+ CONFIG_STR(SRV_SPAM_HEADER_NAME),
+ CONFIG_NONE(),
+ CONFIG_STR(SRV_SPAM_HEADER_VALUE),
+ CONFIG_NONE(),
+ CONFIG_STR(SRV_SPAM_FOLDER),
+ CONFIG_NONE(),
+ CONFIG_STR(SRV_SPAM_BOUNCE_HAM),
+ CONFIG_STR(SRV_SPAM_BOUNCE_SPAM),
+ };
+
+ #undef CONFIG_NONE
+ #undef CONFIG_STR
+
+ wxCOMPILE_TIME_ASSERT2( WXSIZEOF(s_values) == ServerSidePageField_Max,
+ ValuesNotInSync, ServerSideValues );
+
+
+ Create
+ (
+ notebook,
+ gettext_noop("Server Side"),
+ profile,
+ s_fields,
+ s_values,
+ ServerSidePageField_Max,
+ 0, // offset from the start (none)
+ -1, // help id (none)
+ notebook->GetPageCount() // image id
+ );
+}
+
Property changes on: trunk/M/src/modules/spam/ServerSideFilter.cpp
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference
Don't miss this year's exciting event. There's still time to save $100.
Use priority code J8TL2D2.
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
Mahogany-cvsupdates mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mahogany-cvsupdates