diff --git a/bms.py b/bms.py index ff54058..551f63b 100644 --- a/bms.py +++ b/bms.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # A simple milter that has grown quite a bit. # $Log$ +# Revision 1.24 2005/08/18 03:36:54 customdesigned +# Don't innoculate with SCREENED mail. +# # Revision 1.23 2005/08/17 19:35:27 customdesigned # Send DSN before adding message to quarantine. # @@ -334,7 +337,7 @@ time_format = '%Y%b%d %H:%M:%S %Z' timeout = 600 cbv_cache = {} try: - too_old = time.time() - 30*24*60*60 # 30 days + too_old = time.time() - 7*24*60*60 # 7 days for ln in open('send_dsn.log'): try: rcpt,ts = ln.strip().split(None,1) @@ -515,7 +518,22 @@ def read_config(list): #print srs_domain def parse_addr(t): + """Split email into user,domain. + + >>> parse_addr('user@example.com') + ['user', 'example.com'] + >>> parse_addr('"user@example.com"') + ['"user@example.com"'] + >>> parse_addr('"user@bar"@example.com') + ['"user@bar"','example.com'] + >>> parse_addr('foo') + ['foo'] + """ if t.startswith('<') and t.endswith('>'): t = t[1:-1] + if t.startswith('"'): + if t.endswith('"'): return [t[1:-1]] + pos = t.find('"@') + if pos > 0: return [t[1:pos],t[pos+2:]] return t.split('@') def parse_header(val): @@ -733,7 +751,7 @@ class bmsMilter(Milter.Milter): 'SPF fail: see http://openspf.com/why.html?sender=%s&ip=%s' % (q.s,q.i)) res,code,txt = q.check() q.result = res - if res == 'unknown' and q.perm_error: + if res == 'unknown' and q.perm_error and q.perm_error.ext: self.cbv_needed = q # report SPF syntax error to sender res,code,txt = q.perm_error.ext # extended (lax processing) result txt = 'EXT: ' + txt @@ -999,7 +1017,21 @@ class bmsMilter(Milter.Milter): self.fp.write("%s: %s\n" % (name,val)) # add new headers to buffer self.fp.write("\n") # terminate headers self.fp.seek(0) + # log when neither sender nor from domains matches mail from domain + mf_domain = self.canon_from.split('@')[-1] + msg = rfc822.Message(self.fp) + for rn,hf in msg.getaddrlist('from')+msg.getaddrlist('sender'): + t = parse_addr(hf) + if len(t) == 2 and t[1].lower() == mf_domain: + break + else: + self.log("NOTE: MFROM domain doesn't match From or Sender"); + for f in msg.getallmatchingheaders('from') \ + + msg.getallmatchingheaders('sender'): + self.log(f) + del msg # copy headers to a temp file for scanning the body + self.fp.seek(0) headers = self.fp.getvalue() self.fp.close() fd,fname = tempfile.mkstemp(".defang") diff --git a/testbms.py b/testbms.py index 56752bd..9cde1f0 100644 --- a/testbms.py +++ b/testbms.py @@ -1,4 +1,5 @@ import unittest +import doctest import Milter import bms import mime @@ -22,7 +23,7 @@ class TestMilter(bms.bmsMilter): def getsymval(self,name): if name == 'j': return 'test.milter.org' - return bms.bmsMilter.getsymval(self,name) + return '' def replacebody(self,chunk): if self._body: @@ -284,7 +285,10 @@ class BMSMilterTestCase(unittest.TestCase): # self.failUnless(rc == Milter.REJECT) # milter.close(); -def suite(): return unittest.makeSuite(BMSMilterTestCase,'test') +def suite(): + s = unittest.makeSuite(BMSMilterTestCase,'test') + s.addTest(doctest.DocTestSuite(bms)) + return s if __name__ == '__main__': if len(sys.argv) > 1: