Move AddrCache to Milter package.

This commit is contained in:
Stuart Gathman
2007-01-05 21:25:40 +00:00
parent 702ec2d4ca
commit 732e7317f1
5 changed files with 120 additions and 78 deletions
+108
View File
@@ -0,0 +1,108 @@
# Email address list with expiration
#
# This class acts like a map. Entries with a value of None are persistent,
# but disappear after a time limit. This is useful for automatic whitelists
# and blacklists with expiration. The persistent store is a simple ascii
# file with sender and timestamp on each line. Entries can be appended
# to the store, and will be picked up the next time it is loaded.
#
# Entries with other values are not persistent. This is used to hold failed
# CBV results.
#
# $Log$
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001,2002,2003,2004,2005 Business Management Systems, Inc.
# This code is under the GNU General Public License. See COPYING for details.
import time
class AddrCache(object):
time_format = '%Y%b%d %H:%M:%S %Z'
def __init__(self,renew=7,fname=None):
self.age = renew
self.cache = {}
self.fname = fname
def load(self,fname,age=0):
"Load address cache from persistent store."
if not age:
age = self.age
self.fname = fname
cache = {}
self.cache = cache
now = time.time()
try:
too_old = now - age*24*60*60 # max age in days
for ln in open(self.fname):
try:
rcpt,ts = ln.strip().split(None,1)
l = time.strptime(ts,AddrCache.time_format)
t = time.mktime(l)
if t > too_old:
cache[rcpt.lower()] = (t,None)
except:
cache[ln.strip().lower()] = (now,None)
except IOError: pass
def has_key(self,sender):
"True if sender is cached and has not expired."
try:
lsender = sender.lower()
ts,res = self.cache[lsender]
too_old = time.time() - self.age*24*60*60 # max age in days
if not ts or ts > too_old:
return True
del self.cache[lsender]
try:
user,host = sender.split('@',1)
return self.has_key(host)
except ValueError:
pass
except KeyError:
try:
user,host = sender.split('@',1)
return self.has_key(host)
except ValueError:
pass
return False
def __getitem__(self,sender):
try:
lsender = sender.lower()
ts,res = self.cache[lsender]
too_old = time.time() - self.age*24*60*60 # max age in days
if not ts or ts > too_old:
return res
del self.cache[lsender]
raise KeyError, sender
except KeyError,x:
try:
user,host = sender.split('@',1)
return self.__getitem__(host)
except ValueError:
raise x
def addperm(self,sender,res=None):
"Add a permanent sender."
lsender = sender.lower()
if self.has_key(lsender):
ts,res = self.cache[lsender]
if not ts: return # already permanent
self.cache[lsender] = (None,res)
if not res:
print >>open(self.fname,'a'),sender
def __setitem__(self,sender,res):
lsender = sender.lower()
now = time.time()
cached = self.has_key(sender)
if not cached:
self.cache[lsender] = (now,res)
if not res and self.fname:
s = time.strftime(AddrCache.time_format,time.localtime(now))
print >>open(self.fname,'a'),sender,s # log refreshed senders
def __len__(self):
return len(self.cache)
+3 -4
View File
@@ -1,7 +1,6 @@
When bms.py can't find templates, it passes None to dsn.create_msg(),
which uses local variable as backup, which no longer exist.
Purge old GOSSiP records nightly.
DONE When bms.py can't find templates, it passes None to dsn.create_msg(),
which uses local variable as backup, which no longer exist. Do plain
CBV in that case instead.
Find and use X-GOSSiP: header for SPAM: and FP: submissions. Would need to
keep tags longer.
+4 -73
View File
@@ -1,6 +1,9 @@
#!/usr/bin/env python
# A simple milter that has grown quite a bit.
# $Log$
# Revision 1.78 2007/01/04 18:01:10 customdesigned
# Do plain CBV when template missing.
#
# Revision 1.77 2006/12/31 03:07:20 customdesigned
# Use HELO identity if good when MAILFROM is bad.
#
@@ -510,79 +513,7 @@ def iniplist(ipaddr,iplist):
return True
return False
class AddrCache(object):
time_format = '%Y%b%d %H:%M:%S %Z'
def __init__(self,renew=7):
self.age = renew
def load(self,fname,age=0):
if not age:
age = self.age
self.fname = fname
cache = {}
self.cache = cache
now = time.time()
try:
too_old = now - age*24*60*60 # max age in days
for ln in open(self.fname):
try:
rcpt,ts = ln.strip().split(None,1)
l = time.strptime(ts,AddrCache.time_format)
t = time.mktime(l)
if t > too_old:
cache[rcpt.lower()] = (t,None)
except:
cache[ln.strip().lower()] = (now,None)
except IOError: pass
def has_key(self,sender):
try:
ts,res = self.cache[sender.lower()]
too_old = time.time() - self.age*24*60*60 # max age in days
if ts > too_old:
return True
del self.cache[sender.lower()]
try:
user,host = sender.split('@',1)
return self.has_key(host)
except ValueError:
pass
except KeyError:
try:
user,host = sender.split('@',1)
return self.has_key(host)
except ValueError:
pass
return False
def __getitem__(self,sender):
try:
ts,res = self.cache[sender.lower()]
too_old = time.time() - self.age*24*60*60 # max age in days
if ts > too_old:
return res
del self.cache[sender.lower()]
raise KeyError, sender
except KeyError,x:
try:
user,host = sender.split('@',1)
return self.__getitem__(host)
except ValueError:
raise x
def __setitem__(self,sender,res):
lsender = sender.lower()
now = time.time()
cached = self.has_key(sender)
if not cached:
self.cache[lsender] = (now,res)
if not res:
s = time.strftime(AddrCache.time_format,time.localtime(now))
print >>open(self.fname,'a'),sender,s # log refreshed senders
def __len__(self):
return len(self.cache)
from Milter.cache import AddrCache
cbv_cache = AddrCache(renew=7)
cbv_cache.load('send_dsn.log',age=7)
+3 -1
View File
@@ -11,7 +11,8 @@
# some systems dont have initrddir defined
%{?_initrddir:%define _initrddir /etc/rc.d/init.d}
%if %{redhat7} # Redhat 7.x and earlier (multiple ps lines per thread)
%if %{redhat7}
# Redhat 7.x and earlier (multiple ps lines per thread)
%define sysvinit milter.rc7
%else
%define sysvinit milter.rc
@@ -167,6 +168,7 @@ rm -rf $RPM_BUILD_ROOT
%config /var/log/milter/bms.py
%config(noreplace) /var/log/milter/strike3.txt
%config(noreplace) /var/log/milter/softfail.txt
%config(noreplace) /var/log/milter/fail.txt
%config(noreplace) /var/log/milter/neutral.txt
%config(noreplace) /var/log/milter/quarantine.txt
%config(noreplace) /var/log/milter/permerror.txt
+2
View File
@@ -2,6 +2,7 @@ import unittest
import testbms
import testmime
import testsample
import testcache
import os
def suite():
@@ -9,6 +10,7 @@ def suite():
s.addTest(testbms.suite())
s.addTest(testmime.suite())
s.addTest(testsample.suite())
s.addTest(testcache.suite())
return s
if __name__ == '__main__':