CVS: tmda-cgi CgiUtil.py, 1.25, 1.26 ChangeLog, 1.80, 1.81 PendList.py, 1.38, 1.39 THANKS, 1.24, 1.25 TODO, 1.29, 1.30 View.py, 1.24, 1.25 defaults.ini, 1.27, 1.28 reporter.py, 1.3, 1.4

Jim Ramsay <[email protected]> Thu, 08 Apr 2004 08:05:22 -0700
Newsgroups gmane.mail.spam.tmda.cvs
Message-ID <[email protected]>
Update of /cvsroot/tmda/tmda-cgi
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29702

Modified Files:
	CgiUtil.py ChangeLog PendList.py THANKS TODO View.py 
	defaults.ini reporter.py 
Log Message:
Cool Spamassassin integration from Jared Wangen, also better spamcop
reporting (multiple reports sent in a single email).

Details from ChangeLog:





Index: CgiUtil.py
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/CgiUtil.py,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- CgiUtil.py	18 Feb 2004 17:09:50 -0000	1.25
+++ CgiUtil.py	8 Apr 2004 15:05:03 -0000	1.26
@@ -146,7 +146,7 @@
     else:
       return RetVal + Str
 
-def ReportToSpamCop(MsgObj):
+def ReportToSpamCop(MsgObjs):
   "Report a given message to SpamCop."
 
   if PVars[("NoOverride", "Sendmail")]:
@@ -160,7 +160,8 @@
   Command = "%s%s reporter.py %s%s" % (Filter, sys.executable, Sendmail,
     PVars[("General", "SpamCopAddr")])
   P = os.popen(Command, "w")
-  P.write(MsgObj.msgobj.as_string(1))
+  for MsgObj in MsgObjs:
+    P.write(MsgObj.msgobj.as_string(1))
   P.close()
 
 def FindCharSet(MsgObj):

Index: ChangeLog
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/ChangeLog,v
retrieving revision 1.80
retrieving revision 1.81
diff -u -r1.80 -r1.81
--- ChangeLog	18 Mar 2004 17:54:17 -0000	1.80
+++ ChangeLog	8 Apr 2004 15:05:03 -0000	1.81
@@ -1,3 +1,17 @@
+2004-04-07  Jared Wangen    <[email protected]>
+
+	* Added Spam score column to TMDA-X and Blue themes
+
+	* Added the ability to select "Spam" in TMDA-X theme for spam which 
+	  scored above a user-defined threshold
+
+	* Modified reporter.py (SpamCop reporter) and CgiUtil.ReportToSpamCop() 
+	  to send multiple reported spam in one e-mail.
+	  CgiUtil.ReportToSpamCop() now expects arrays of message objects.
+
+	* Fixed bug in Blue theme so the selection of all SpamCop radios works 
+	  now
+
 2004-03-18  Jim Ramsay      <[email protected]>
 
 	* Made text-size in TMDA-X theme user-configurable

Index: PendList.py
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/PendList.py,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -r1.38 -r1.39
--- PendList.py	18 Mar 2004 18:59:16 -0000	1.38
+++ PendList.py	8 Apr 2004 15:05:03 -0000	1.39
@@ -51,6 +51,7 @@
       WhiteList   = []
       BlackList   = []
       DeleteList  = []
+      SpamList    = []
       OtherList   = []
       OtherAction = "Pass"
       for Count in range(int(PVars[("PendingList", "PagerSize")])):
@@ -78,8 +79,7 @@
               BlackList.append(MsgObj)
               DeleteList.append(MsgObj)
             elif Form["a%d" % Count].value == "report":
-              OtherAction = "Report"
-              OtherList.append(MsgObj)
+              SpamList.append(MsgObj)
             elif Form["a%d" % Count].value == "other":
               if Form["Action"].value == "Release":
                 ReleaseList.append(MsgObj)
@@ -87,12 +87,15 @@
                 DeleteList.append(MsgObj)
               elif Form["Action"].value == "Whitelist":
                 WhiteList.append(MsgObj)
+		# TODO: Separate release not needed for TMDA 1.1.x
                 ReleaseList.append(MsgObj)
               elif Form["Action"].value == "Blacklist":
                 BlackList.append(MsgObj)
                 DeleteList.append(MsgObj)  
               elif Form["Action"].value == "Read":
                 ReadList.append(MsgObj)
+              elif Form["Action"].value == "Report":
+                SpamList.append(MsgObj)
               else:
                 OtherList.append(MsgObj)
                 OtherAction = Form["Action"].value
@@ -118,10 +121,10 @@
               DeleteList.append( MsgObj )
             elif Form.has_key("WhitelistButton"):
               WhiteList.append( MsgObj )
+              # TODO: Separate release not needed for TMDA 1.1.x
               ReleaseList.append( MsgObj )
             elif Form.has_key("ReportButton"):
-              OtherAction = "Report"
-              OtherList.append( MsgObj )
+              SpamList.append( MsgObj )
             elif Form.has_key("ExecuteButton"):
               OtherAction = Form["Action"].value
               if OtherAction == "Release":
@@ -136,19 +139,25 @@
                 DeleteList.append( MsgObj )
               elif OtherAction == "Read":
                 ReadList.append( MsgObj )
+              elif OtherAction == "Report":
+                SpamList.append( MsgObj )
               else: 
                 OtherList.append( MsgObj )
           except IOError: pass
+      
       # Process the messages found:
-      # Apply "other" action... May be Report or a custom filter
+      # Apply "other" action...
       for MsgObj in OtherList:
-        if OtherAction == "Report":
-          CgiUtil.ReportToSpamCop(MsgObj)
+        if OtherAction == "someotheraction":
           DeleteList.append(MsgObj)
         # TODO: Check if OtherAction is a custom filter
         #       If so, run it on the message and check the return value
         #       and add the MsgObj to the appropriate action list based on the
         #       filter output.
+      if SpamList:
+        CgiUtil.ReportToSpamCop(SpamList)
+      for MsgObj in SpamList:
+        DeleteList.append(MsgObj)
       for MsgObj in WhiteList:
         # Whitelist (and release) each message
         MsgObj.whitelist()
@@ -328,6 +337,7 @@
 
   NumCols = int(T["NumCols"])
   NumBlankCols = int(T["NumBlankCols"])
+  NumMainCols = int(T["NumMainCols"])
 
   # Grab the radiobuttons if they exist
   RlRadio = T["RlRadio"]
@@ -344,12 +354,14 @@
   WhAllowed = 1 and Defaults.PENDING_WHITELIST_APPEND
   BlAllowed = 1 and Defaults.PENDING_BLACKLIST_APPEND
   ScAllowed = 1 and PVars[("General", "SpamCopAddr")]
+  SsAllowed = 1
   FltAllowed = 1
   RlShow    = RlAllowed and 1
   DlShow    = DlAllowed and (PVars[("PendingList", "ShowDelete")] == "Yes")
   WhShow    = WhAllowed and 1
   BlShow    = BlAllowed and (PVars[("PendingList", "ShowBlack")] == "Yes")
   ScShow    = ScAllowed and 1
+  SsShow    = SsAllowed and (PVars[("PendingList", "ShowSpamScore")] == "Yes")
  
   if not RlAllowed:
     T["RlAction"]
@@ -381,6 +393,12 @@
     T["SCIcon"]
     NumCols -= 1
     NumBlankCols -= 1
+  if not SsShow:
+    T["SsTh"].Clear()
+    T["SsTd"].Clear()
+    T["SsPr"].Clear()
+    NumCols -= 1
+    NumMainCols -= 1
     
   if FltAllowed:
     T["FilterOptions"] = CgiUtil.getFilterOptions() 
@@ -389,6 +407,7 @@
 
   T["NumCols"] = NumCols
   T["NumBlankCols"] = NumBlankCols
+  T["NumMainCols"] = NumMainCols
 
   # Javascript confirmation?
   if PVars[("General", "UseJSConfirm")] == "Yes":
@@ -398,6 +417,16 @@
   T["PagerSize"] = PVars[("PendingList", "PagerSize")]
 
   ReadArray = []
+  SpamArray = []
+  
+  # get Spam related vars
+  SpamSearch = re.compile(PVars[("NoOverride", "SpamScoreRegEx")])
+  SpamThreshold = PVars[("General", "SpamScoreThreshold")]
+  SpamHeader = PVars[("NoOverride", "SpamScoreHeader")]
+  
+  if not SpamThreshold:
+    if T["ShowSelectSpam"]:
+      T["ShowSelectSpam"].Clear()
 
   # Parse out embedded variables from template
   Row          = T["Row"]
@@ -554,6 +583,33 @@
         else:
           T["MsgClass"] = "NewMsg"
           ReadArray.append(0)
+        
+        # Grab this specific header
+        SpamScoreHead = MsgObj.msgobj[SpamHeader]
+        
+        if not SpamScoreHead:
+          SpamArray.append(0)
+          Score = "-"
+        else:
+          Temp = SpamSearch.search(SpamScoreHead)
+          if not SpamThreshold:
+            SpamArray.append(0)
+            if not Temp:
+              Score = "-"
+            else:
+              Score = Temp.group(1)
+          else:
+            if not Temp:
+              SpamArray.append(0)
+              Score = "-"
+            else:
+              Score = Temp.group(1)
+              if not float(Score) >= float(SpamThreshold):
+                SpamArray.append(0)
+              else:
+                SpamArray.append(1)
+        
+        T["Score"] = Score
 
         if RlShow and RlRadio:
           RlRadio.Clear()
@@ -585,6 +641,18 @@
       else:
         ReadArrayText += ", "
     T["ReadArray"] = ReadArrayText
+    
+    SpamArrayText = "SpamArray = new Array("
+    for SubCount in range( 0, Count ):
+      if SpamArray[SubCount]:
+        SpamArrayText += "true"
+      else:
+        SpamArrayText += "false"
+      if SubCount == ( Count - 1 ):
+        SpamArrayText += ")"
+      else:
+        SpamArrayText += ", "
+    T["SpamArray"] = SpamArrayText
 
     # Disallow searching if defaults.ini prohibits
     if not Searching and PVars[("NoOverride", "MaySearchPendList")][0].lower() == "n":
@@ -593,6 +661,7 @@
   # No messages to display
   else:
     T["ReadArray"] = ""
+    T["SpamArray"] = ""
     T["FirstButton1Active"]
     T["PrevButton1Active"]
     T["FirstButton2Active"]

Index: THANKS
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/THANKS,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- THANKS	18 Feb 2004 17:57:21 -0000	1.24
+++ THANKS	8 Apr 2004 15:05:04 -0000	1.25
@@ -16,16 +16,18 @@
 
     * Dan Davis -- case insensative sorting
 
-    * Julian Easterling -- bug finding
-
     * Dan Egli -- bug finding
 
     * Dario Gomes -- bug finding
 
+    * Jared Wangen -- better Spamcop reporting and Spamassassin integration
+
     * Jesse Guardiani -- providing valuable insight into virtual user
                          setup and the proper way to interface to the
                          libraries, suggesting a way to simplify anomalies
 
+    * Julian Easterling -- bug finding
+
     * Samuel Hill -- bug fixing
 
     * Brian Ipsen -- bug fixing

Index: TODO
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/TODO,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- TODO	7 Apr 2004 20:28:57 -0000	1.29
+++ TODO	8 Apr 2004 15:05:04 -0000	1.30
@@ -33,10 +33,6 @@
     * Sort -- Allow the Pending List to be sorted by other methods than Date:
               Size, subject, etc.
 
-    * SpamAssassin -- Mark every email with a spam score greater than some
-                      threshold as "spam", not unlike "read"/"unread" done 
-		      currently.  (Idea from Jared <[email protected]>)
-
     * Un-ugly Errors -- Samuel Hill writes:
         Those python errors just freak normal people out when there is not
         really a serious problem.  Maybe tmda-cgi, instead of dumping

Index: View.py
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/View.py,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- View.py	18 Mar 2004 17:54:17 -0000	1.24
+++ View.py	8 Apr 2004 15:05:04 -0000	1.25
@@ -145,7 +145,9 @@
           MsgObj.blacklist()
           MsgObj.delete()
         elif Form["subcmd"].value == "spamcop":
-          CgiUtil.ReportToSpamCop(MsgObj)
+          SpamArr = []
+          SpamArr.append(MsgObj)
+          CgiUtil.ReportToSpamCop(SpamArr)
           MsgObj.delete()
         # TODO: Check if subcmd is a custom filter and process accordingly
         del Msgs[MsgIdx]

Index: defaults.ini
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/defaults.ini,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -r1.27 -r1.28
--- defaults.ini	18 Mar 2004 17:54:17 -0000	1.27
+++ defaults.ini	8 Apr 2004 15:05:04 -0000	1.28
@@ -28,6 +28,8 @@
 MaySearchPendList  = Yes
 Sendmail           =
 SpamCopFilter      =
+SpamScoreHeader    = x-spam-status
+SpamScoreRegEx     = .*hits=([0-9]+\.[0-9]).*
 UninstallBackupTGZ = TMDA_restore.tgz
 UninstallInstruct  = You will need to change the outgoing mail settings on your
   e-mail client. Please set your SMTP port to 25 (instead of 8025). Contact the
@@ -46,10 +48,11 @@
 ;;                                                  ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 [General]
-CSEncoding   = iso-8859-1
-SpamCopAddr  =
-Theme        = TMDA-X
-UseJSConfirm = Yes
+CSEncoding         = iso-8859-1
+SpamCopAddr        =
+SpamScoreThreshold = 
+Theme              = TMDA-X
+UseJSConfirm       = Yes
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;                                                  ;;
@@ -69,14 +72,15 @@
 InitPage    = pending
 
 [PendingList]
-CropDest    = 25
-CropSender  = 25
-CropSubject = 40
-DateFormat  = %Y-%m-%d
-PagerSize   = 15
-ShowAddr    = Name
-ShowBlack   = No
-ShowDelete  = No
+CropDest      = 25
+CropSender    = 25
+CropSubject   = 40
+DateFormat    = %Y-%m-%d
+PagerSize     = 15
+ShowAddr      = Name
+ShowBlack     = No
+ShowDelete    = No
+ShowSpamScore = No
 
 [ViewPending]
 AltPref     = text/plain

Index: reporter.py
===================================================================
RCS file: /cvsroot/tmda/tmda-cgi/reporter.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- reporter.py	17 Nov 2003 00:33:33 -0000	1.3
+++ reporter.py	8 Apr 2004 15:05:04 -0000	1.4
@@ -63,6 +63,9 @@
 # 2003/11/12 - Tim Legant
 #   Ripped out all address/domain hiding code.  SpamCop is now complaining
 #   about that.
+# 2004/04/07 - Jared Wangen
+#   Modified code to send multiple spams in one e-mail for processing instead
+#   of one e-mail for every spam. There is enough clog on the net as it is! :)
 # 
 
 import getopt
@@ -107,14 +110,14 @@
 """
     sys.exit(ec)
    
-def sendspam(spam, seq, conf):
+def sendspam(spams, conf):
     if conf.mailto:
         mailto = conf.mailto
         outfile = os.popen("%s -oi -t" % (conf.sendmail,), 'w')
     else:
         mailto = 'SPAMCOP'
         outfile = sys.stdout
-    subjstr = "%s #%03d" % (conf.subject, seq)
+    subjstr = "%s" % (conf.subject)
     # headers
     outfile.write("""To: %s
 Subject: %s
@@ -123,31 +126,34 @@
 
 This is a multi-part message in MIME format.
 
---%s
+""" % (mailto, subjstr, conf.MIME_delim))
+
+    for spam in spams: 
+        outfile.write("""--%s
 Content-Type: message/rfc822
-Content-Disposition: attachment
+Content-Disposition: attachment""" % (conf.MIME_delim))
 
-""" % (mailto, subjstr, conf.MIME_delim, conf.MIME_delim))
-    # copy message
-    skip = 0
-    body = 0
-    for l in spam:
-        if re.match(r"^Subject:\s+\*+SPAM\*+\s+", l):
-            outfile.write(re.sub(r"\s+\*+SPAM\*+", "", l, 1))
-        elif re.match(r"^X-Spam-", l):
-            skip = 1
-        elif re.match(r"^SPAM:\s+", l):
-            skip = 2
-        elif skip and re.match(r"^\s+\S", l):
-            pass
-        elif skip > 1 and re.match(r"^\s*$", l):
-            skip = 0
-            body = 1
-        else:
-            skip = 0
-            outfile.write(l)
+        # copy message
+        skip = 0
+        body = 0
+        outfile.write("\n\n")
+        for l in spam:
+            if re.match(r"^Subject:\s+\*+SPAM\*+\s+", l):
+                outfile.write(re.sub(r"\s+\*+SPAM\*+", "", l, 1))
+            elif re.match(r"^X-Spam-", l):
+                skip = 1
+            elif re.match(r"^SPAM:\s+", l):
+                skip = 2
+            elif skip and re.match(r"^\s+\S", l):
+                pass
+            elif skip > 1 and re.match(r"^\s*$", l):
+                skip = 0
+                body = 1
+            else:
+                skip = 0
+                outfile.write(l)
     # finish MIME part
-    outfile.write("\n\n--%s\n\n" % (conf.MIME_delim,))
+    outfile.write("\n\n--%s--\n\n" % (conf.MIME_delim,))
     # report success
     sys.stderr.write("Message '%s' sent to %s\n"
                      % (subjstr, mailto))
@@ -163,10 +169,8 @@
         currspam.append(l)
     if len(currspam):
         spams.append(currspam)
-    cnt = 0
-    for currspam in spams:
-        cnt = cnt + 1
-        sendspam(currspam, cnt, conf)
+    if len(spams):
+        sendspam(spams, conf)
 
 # main()