Skip to content
Snippets Groups Projects
Select Git revision
  • a2215124bb8cc8744f1a81dc9dcb776184161195
  • master default protected
  • pymilter-1.0.4
  • pymilter-1.0.3
  • pymilter-1.0.2
  • pymilter-1.0.1
  • pymilter-1_0
  • milter-0_8_18
  • pymilter-0_9_8
  • pymilter-0_9_7
  • pymilter-0_9_6
  • pymilter-0_9_5
  • pymilter-0_9_4
  • pymilter-0_9_2
  • pymilter-0_9_1
  • pymilter-0_9_0
  • pymilter-0_8_12
  • pymilter-0_8_11
  • pymilter-0_8_10
  • pymilter-0_8_9
  • milter-0_8_8
  • milter-0_8_7
22 results

cache.py

Blame
  • cache.py 3.95 KiB
    # 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$
    # Revision 1.6  2007/01/19 23:31:38  customdesigned
    # Move parse_header to Milter.utils.
    # Test case for delayed DSN parsing.
    # Fix plock when source missing or cannot set owner/group.
    #
    # Revision 1.5  2007/01/11 19:59:40  customdesigned
    # Purge old entries in auto_whitelist and send_dsn logs.
    #
    # Revision 1.4  2007/01/11 04:31:26  customdesigned
    # Negative feedback for bad headers.  Purge cache logs on startup.
    #
    # Revision 1.3  2007/01/08 23:20:54  customdesigned
    # Get user feedback.
    #
    # Revision 1.2  2007/01/05 23:33:55  customdesigned
    # Make blacklist an AddrCache
    #
    # Revision 1.1  2007/01/05 21:25:40  customdesigned
    # Move AddrCache to Milter package.
    #
    
    # 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
    from plock import PLock
    
    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()
        lock = PLock(self.fname)
        wfp = lock.lock()
        changed = False
        try:
          too_old = now - age*24*60*60	# max age in days
          try:
            fp = open(self.fname)
          except OSError:
            fp = ()
          for ln in fp:
    	try:
    	  rcpt,ts = ln.strip().split(None,1)
    	  l = time.strptime(ts,AddrCache.time_format)
    	  t = time.mktime(l)
    	  if t < too_old:
    	    changed = True
    	    continue
    	  cache[rcpt.lower()] = (t,None)
    	except:
    	  cache[ln.strip().lower()] = (now,None)
    	wfp.write(ln)
          if changed:
    	lock.commit(self.fname+'.old')
          else:
            lock.unlock()
        except IOError:
          lock.unlock()
    
      def has_key(self,sender):
        "True if sender is cached and has not expired."
        try:
          lsender = sender and 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: pass
        return False
    
      __contains__ = has_key
    
      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()
        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)