From d24ce995d911624983d0c9afb95e273dbb36da47 Mon Sep 17 00:00:00 2001 From: "beard%netscape.com" Date: Wed, 2 Oct 2002 20:04:09 +0000 Subject: [PATCH] Work in progress changes for bayesian spam filter. sr=sspitzer, r=ducarroz git-svn-id: svn://10.0.0.236/trunk@131019 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/mailnews/base/macbuild/msgCoreIDL.xml | 34 +++++++- .../base/resources/content/mailCommands.js | 85 +++++++------------ .../base/search/public/nsIMsgFilterPlugin.idl | 66 ++++++++++---- 3 files changed, 114 insertions(+), 71 deletions(-) diff --git a/mozilla/mailnews/base/macbuild/msgCoreIDL.xml b/mozilla/mailnews/base/macbuild/msgCoreIDL.xml index 2c78743f4be..8d41b285b89 100644 --- a/mozilla/mailnews/base/macbuild/msgCoreIDL.xml +++ b/mozilla/mailnews/base/macbuild/msgCoreIDL.xml @@ -327,7 +327,7 @@ MWFTP_Post_hostName MWFTP_Post_username - MWFTP_Post_password0 + MWFTP_Post_password0ÿݸ MWFTP_Post_remoteDir MWFTP_Post_ftp_PathVersion1 MWFTP_Post_ftp_PathType0 @@ -1136,6 +1136,13 @@ Text + + Name + nsIMsgFilterPlugin.idl + MacOS + Text + + @@ -1428,6 +1435,11 @@ nsISpamSettings.idl MacOS + + Name + nsIMsgFilterPlugin.idl + MacOS + @@ -1704,7 +1716,7 @@ MWFTP_Post_hostName MWFTP_Post_username - MWFTP_Post_password0 + MWFTP_Post_password0ÿݸ MWFTP_Post_remoteDir MWFTP_Post_ftp_PathVersion1 MWFTP_Post_ftp_PathType0 @@ -2513,6 +2525,13 @@ Text + + Name + nsIMsgFilterPlugin.idl + MacOS + Text + + @@ -2805,6 +2824,11 @@ nsISpamSettings.idl MacOS + + Name + nsIMsgFilterPlugin.idl + MacOS + @@ -3102,6 +3126,12 @@ nsIMsgFilterList.idl MacOS + + headers + Name + nsIMsgFilterPlugin.idl + MacOS + headers Name diff --git a/mozilla/mailnews/base/resources/content/mailCommands.js b/mozilla/mailnews/base/resources/content/mailCommands.js index 4273869b767..b8c031c3b76 100644 --- a/mozilla/mailnews/base/resources/content/mailCommands.js +++ b/mozilla/mailnews/base/resources/content/mailCommands.js @@ -429,44 +429,36 @@ function doHelpButton() // XXX The following junkmail code might be going away or changing +const NS_BAYESIANFILTER_CONTRACTID = "@mozilla.org/messenger/filter-plugin;1?name=bayesianfilter"; +const nsIJunkMailPlugin = Components.interfaces.nsIJunkMailPlugin; + var gJunkmailComponent; function getJunkmailComponent() { if (!gJunkmailComponent) { - gJunkmailComponent = Components.classes['@mozilla.org/messenger/filter-plugin;1?name=junkmail'] - .getService(Components.interfaces.nsISupports).wrappedJSObject; - gJunkmailComponent.initComponent(); + gJunkmailComponent = Components.classes[NS_BAYESIANFILTER_CONTRACTID].getService(nsIJunkMailPlugin); + // gJunkmailComponent.initComponent(); + // who calls init method? } } function analyze(aMessage, aNextFunction) { - function callback(aScore) { - } - - callback.prototype = + var listener = { + onMessageClassified: function(aMsgURL, aClassification) { - onMessageScored: function processNext(aScore) - { - if (aMessage) { - //if (aScore == -1) debugger; - if (aScore == 0) { - aMessage.setStringProperty("score", "0"); - } - else if (aScore == 1) { - aMessage.setStringProperty("score", "100"); - } - } - aNextFunction(); - } - }; - + dump(aMsgURL + ' is ' + (aClassification == nsIJunkMailPlugin.JUNK ? 'JUNK' : 'GOOD') + '\n'); + var score = (aClassification == nsIJunkMailPlugin.JUNK ? "100" : "0"); + aMessage.setStringProperty("score", score); + aNextFunction(); + } + }; // XXX TODO jumping through hoops here. var messageURI = aMessage.folder.generateMessageURI(aMessage.messageKey) + "?fetchCompleteMessage=true"; var messageURL = mailSession.ConvertMsgURIToMsgURL(messageURI, msgWindow); - gJunkmailComponent.calculate(messageURL, new callback); + gJunkmailComponent.classifyMessage(messageURL, listener); } function analyzeFolder() @@ -509,6 +501,7 @@ function analyzeMessages() ++counter; while (!message.isRead) { if (counter == messages.length) { + dump('[bayesian filter message analysis complete.]\n'); gJunkmailComponent.mBatchUpdate = false; return; } @@ -519,6 +512,7 @@ function analyzeMessages() analyze(message, processNext); } else { + dump('[bayesian filter message analysis complete.]\n'); gJunkmailComponent.batchUpdate = false; } } @@ -527,6 +521,7 @@ function analyzeMessages() var messages = GetSelectedMessages(); var counter = 0; gJunkmailComponent.batchUpdate = true; + dump('[bayesian filter message analysis begins.]\n'); processNext(); } @@ -541,38 +536,22 @@ function mark(aMessage, aSpam, aNextFunction) // XXX TODO jumping through hoops here. var score = aMessage.getStringProperty("score"); - var action; - if (aSpam) { - if (score == "100") { - // Marking a spam message as spam does nothing - return; - } - - if (score == "0") { - // Marking a non-spam message as spam - action = Components.interfaces.nsIMsgFilterPlugin.hamToSpam; - } - else - action = Components.interfaces.nsIMsgFilterPlugin.unknownToSpam; - - } - else { - if (score == "0") { - // Marking a non-spam message as non-spam does nothing - return; - } - - if (score == "100") { - // Marking a spam message as non-spam - action = Components.interfaces.nsIMsgFilterPlugin.spamToHam; - } - else - action = Components.interfaces.nsIMsgFilterPlugin.unknownToHam; - } + var oldClassification = ((score == "100") ? nsIJunkMailPlugin.JUNK : + (score == "0") ? nsIJunkMailPlugin.GOOD : nsIJunkMailPlugin.UNCLASSIFIED); + var newClassification = (aSpam ? nsIJunkMailPlugin.JUNK : nsIJunkMailPlugin.GOOD); var messageURI = aMessage.folder.generateMessageURI(aMessage.messageKey) + "?fetchCompleteMessage=true"; var messageURL = mailSession.ConvertMsgURIToMsgURL(messageURI, msgWindow); - gJunkmailComponent.mark(messageURL, action, aNextFunction); + + var listener = (aNextFunction == null ? null : + { + onMessageClassified: function(aMsgURL, aClassification) + { + aNextFunction(); + } + }); + + gJunkmailComponent.setMessageClassification(messageURL, oldClassification, newClassification, listener); } function JunkSelectedMessages(setAsJunk) @@ -620,6 +599,7 @@ function markFolderAsJunk(aSpam) message.setStringProperty("score","0"); } else { + dump('[folder marking complete.]\n'); gJunkmailComponent.batchUpdate = false; } } @@ -628,5 +608,6 @@ function markFolderAsJunk(aSpam) var folder = GetFirstSelectedMsgFolder(); var messages = folder.getMessages(msgWindow); gJunkmailComponent.batchUpdate = true; + dump('[folder marking starting.]\n'); processNext(); } diff --git a/mozilla/mailnews/base/search/public/nsIMsgFilterPlugin.idl b/mozilla/mailnews/base/search/public/nsIMsgFilterPlugin.idl index 5d759b3e21a..1178b766997 100644 --- a/mozilla/mailnews/base/search/public/nsIMsgFilterPlugin.idl +++ b/mozilla/mailnews/base/search/public/nsIMsgFilterPlugin.idl @@ -47,11 +47,6 @@ interface nsIStreamListener; [scriptable, uuid(e2e56690-a676-11d6-80c9-00008646b737)] interface nsIMsgFilterPlugin : nsISupports { - const long unknownToSpam = 0; - const long unknownToHam = 1; - const long hamToSpam = 2; - const long spamToHam = 3; - /** * Initialize the plugin object. * @@ -61,8 +56,9 @@ interface nsIMsgFilterPlugin : nsISupports void init(in ACString aServerPrefsKey); /** - * Filter a message by headers. + * Filter an email message by content or headers, your choice. * + * @param aMsgURL URL to fetch full contents of this message. * @param aMsgHdr Can be used to set properties on the header of the * message (e.g. for attaching a score to it). * @@ -78,17 +74,12 @@ interface nsIMsgFilterPlugin : nsISupports * * @param aMsgWindow Passed back to the listener. */ - void filterMsgByHeaders(in nsIMsgDBHdr aMsgHdr, in unsigned long aCount, - [array, size_is(aCount)] in string aHeaders, - in nsIMsgFilterHitNotify aListener, - in nsIMsgWindow aMsgWindow); - - /** - * XXX |string| -- should really be a UTF8 String - */ - void filterMsg(in string aMessageURL, - in nsIMsgDBHdr aMsgHdr, - in nsIMsgFilterHitNotify aListener); + void filterMessage(in string aMsgURL, + in nsIMsgDBHdr aMsgHdr, + in unsigned long aCount, + [array, size_is(aCount)] in string aHeaders, + in nsIMsgFilterHitNotify aListener, + in nsIMsgWindow aMsgWindow); /** * Do any necessary cleanup: flush and close any open files, etc. @@ -113,3 +104,44 @@ interface nsIMsgFilterPlugin : nsISupports }; +/** + * Rather than passing low level details about scores and such, abstract + * this away by informing a listener of a message's classification, which + * can be one of 3 values: UNCLASSIFIED, GOOD, or JUNK. + */ +[scriptable, uuid(0243f3d6-d583-11d6-898a-00039310a47a)] +interface nsIJunkMailClassificationListener : nsISupports +{ + void onMessageClassified(in string aMsgURL, in long classification); +}; + +[scriptable, uuid(caf3d467-d57c-11d6-96a9-00039310a47a)] +interface nsIJunkMailPlugin : nsIMsgFilterPlugin +{ + /** + * Message classifications. + */ + const long UNCLASSIFIED = 0; + const long GOOD = 1; + const long JUNK = 2; + + /** + * Given a message URL, determine what its current classification is + * according to the current training set. + */ + void classifyMessage(in string aMsgURL, + in nsIJunkMailClassificationListener aListener); + + void classifyMessages(in unsigned long aCount, + [array, size_is(aCount)] in string aMsgURLs, + in nsIJunkMailClassificationListener aListener); + + /** + * Called when a user forces the classification of a message. Should + * cause the training set to be updated appropriately. + */ + void setMessageClassification(in string aMsgURL, + in long aOldClassification, + in long aNewClassification, + in nsIJunkMailClassificationListener aListener); +};