Skip to content
Snippets Groups Projects
Commit 732e7317 authored by Stuart Gathman's avatar Stuart Gathman
Browse files

Move AddrCache to Milter package.

parent 702ec2d4
No related branches found
No related tags found
No related merge requests found
# 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)
When bms.py can't find templates, it passes None to dsn.create_msg(), 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. which uses local variable as backup, which no longer exist. Do plain
CBV in that case instead.
Purge old GOSSiP records nightly.
Find and use X-GOSSiP: header for SPAM: and FP: submissions. Would need to Find and use X-GOSSiP: header for SPAM: and FP: submissions. Would need to
keep tags longer. keep tags longer.
......
#!/usr/bin/env python #!/usr/bin/env python
# A simple milter that has grown quite a bit. # A simple milter that has grown quite a bit.
# $Log$ # $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 # Revision 1.77 2006/12/31 03:07:20 customdesigned
# Use HELO identity if good when MAILFROM is bad. # Use HELO identity if good when MAILFROM is bad.
# #
...@@ -510,79 +513,7 @@ def iniplist(ipaddr,iplist): ...@@ -510,79 +513,7 @@ def iniplist(ipaddr,iplist):
return True return True
return False return False
class AddrCache(object): from Milter.cache import AddrCache
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)
cbv_cache = AddrCache(renew=7) cbv_cache = AddrCache(renew=7)
cbv_cache.load('send_dsn.log',age=7) cbv_cache.load('send_dsn.log',age=7)
......
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
# some systems dont have initrddir defined # some systems dont have initrddir defined
%{?_initrddir:%define _initrddir /etc/rc.d/init.d} %{?_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 %define sysvinit milter.rc7
%else %else
%define sysvinit milter.rc %define sysvinit milter.rc
...@@ -167,6 +168,7 @@ rm -rf $RPM_BUILD_ROOT ...@@ -167,6 +168,7 @@ rm -rf $RPM_BUILD_ROOT
%config /var/log/milter/bms.py %config /var/log/milter/bms.py
%config(noreplace) /var/log/milter/strike3.txt %config(noreplace) /var/log/milter/strike3.txt
%config(noreplace) /var/log/milter/softfail.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/neutral.txt
%config(noreplace) /var/log/milter/quarantine.txt %config(noreplace) /var/log/milter/quarantine.txt
%config(noreplace) /var/log/milter/permerror.txt %config(noreplace) /var/log/milter/permerror.txt
......
...@@ -2,6 +2,7 @@ import unittest ...@@ -2,6 +2,7 @@ import unittest
import testbms import testbms
import testmime import testmime
import testsample import testsample
import testcache
import os import os
def suite(): def suite():
...@@ -9,6 +10,7 @@ def suite(): ...@@ -9,6 +10,7 @@ def suite():
s.addTest(testbms.suite()) s.addTest(testbms.suite())
s.addTest(testmime.suite()) s.addTest(testmime.suite())
s.addTest(testsample.suite()) s.addTest(testsample.suite())
s.addTest(testcache.suite())
return s return s
if __name__ == '__main__': if __name__ == '__main__':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment