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&lters..."), 
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

Reply via email to