Skip to content
Snippets Groups Projects
Commit f357a237 authored by cvs2svn's avatar cvs2svn
Browse files

This commit was manufactured by cvs2svn to create tag 'milter-0_7_3-devel'.

Sprout from bmsi 2005-05-31 18:23:49 UTC Stuart Gathman <stuart@gathman.org> 'Development changes since 0.7.2'
Delete:
    Milter.py
parent 9fb3ad70
Branches
Tags
No related merge requests found
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001 Business Management Systems, Inc.
# This code is under GPL. See COPYING for details.
import os
import milter
import thread
from milter import ACCEPT,CONTINUE,REJECT,DISCARD,TEMPFAIL, \
set_flags, setdbg, setbacklog, settimeout, \
ADDHDRS, CHGBODY, ADDRCPT, DELRCPT, CHGHDRS, \
V1_ACTS, V2_ACTS, CURR_ACTS
try: from milter import QUARANTINE
except: pass
_seq_lock = thread.allocate_lock()
_seq = 0
def uniqueID():
"""Return a sequence number unique to this process.
"""
global _seq
_seq_lock.acquire()
seqno = _seq = _seq + 1
_seq_lock.release()
return seqno
class Milter:
"""A simple class interface to the milter module.
"""
def _setctx(self,ctx):
self.__ctx = ctx
if ctx:
ctx.setpriv(self)
# user replaceable callbacks
def log(self,*msg):
print 'Milter:',
for i in msg: print i,
print
def connect(self,hostname,unused,hostaddr):
"Called for each connection to sendmail."
self.log("connect from %s at %s" % (hostname,hostaddr))
return CONTINUE
def hello(self,hostname):
"Called after the HELO command."
self.log("hello from %s" % hostname)
return CONTINUE
def envfrom(self,f,*str):
"""Called to begin each message.
f -> string message sender
str -> tuple additional ESMTP parameters
"""
self.log("mail from",f,str)
return CONTINUE
def envrcpt(self,to,*str):
"Called for each message recipient."
self.log("rcpt to",to,str)
return CONTINUE
def header(self,field,value):
"Called for each message header."
self.log("%s: %s" % (field,value))
return CONTINUE
def eoh(self):
"Called after all headers are processed."
self.log("eoh")
return CONTINUE
def body(self,unused):
"Called to transfer the message body."
return CONTINUE
def eom(self):
"Called at the end of message."
self.log("eom")
return CONTINUE
def abort(self):
"Called if the connection is terminated abnormally."
self.log("abort")
return CONTINUE
def close(self):
"Called at the end of connection, even if aborted."
self.log("close")
return CONTINUE
# Milter methods which can be invoked from callbacks
def getsymval(self,sym):
return self.__ctx.getsymval(sym)
# If sendmail does not support setmlreply, then only the
# first msg line is used.
def setreply(self,rcode,xcode=None,msg=None,*ml):
return self.__ctx.setreply(rcode,xcode,msg,*ml)
# Milter methods which can only be called from eom callback.
def addheader(self,field,value):
return self.__ctx.addheader(field,value)
def chgheader(self,field,idx,value):
return self.__ctx.chgheader(field,idx,value)
def addrcpt(self,rcpt):
return self.__ctx.addrcpt(rcpt)
def delrcpt(self,rcpt):
return self.__ctx.delrcpt(rcpt)
def replacebody(self,body):
return self.__ctx.replacebody(body)
# When quarantined, a message goes into the mailq as if to be delivered,
# but delivery is deferred until the message is unquarantined.
def quarantine(self,reason):
return self.__ctx.quarantine(reason)
def progress(self):
return self.__ctx.progress()
factory = Milter
def connectcallback(ctx,hostname,family,hostaddr):
m = factory()
m._setctx(ctx)
return m.connect(hostname,family,hostaddr)
def closecallback(ctx):
m = ctx.getpriv()
if not m: return CONTINUE
rc = m.close()
m._setctx(None) # release milterContext
return rc
def envcallback(c,args):
"""Convert ESMTP parms to keyword parameters.
Can be used in the envfrom and/or envrcpt callbacks to process
ESMTP parameters as python keyword parameters."""
kw = {}
for s in args[1:]:
pos = s.find('=')
if pos > 0:
kw[s[:pos]] = s[pos+1:]
return apply(c,args,kw)
def runmilter(name,socketname,timeout = 0):
# This bit is here on the assumption that you will be starting this filter
# before sendmail. If sendmail is not running and the socket already exists,
# libmilter will throw a warning. If sendmail is running, this is still
# safe if there are no messages currently being processed. It's safer to
# shutdown sendmail, kill the filter process, restart the filter, and then
# restart sendmail.
pos = socketname.find(':')
if pos > 1:
s = socketname[:pos]
fname = socketname[pos+1:]
else:
s = "unix"
fname = socketname
if s == "unix" or s == "local":
print "Removing %s" % fname
try:
os.unlink(fname)
except:
pass
# The default flags set include everything
# milter.set_flags(milter.ADDHDRS)
milter.set_connect_callback(connectcallback)
milter.set_helo_callback(lambda ctx, host: ctx.getpriv().hello(host))
milter.set_envfrom_callback(lambda ctx,*str:
ctx.getpriv().envfrom(*str))
# envcallback(ctx.getpriv().envfrom,str))
milter.set_envrcpt_callback(lambda ctx,*str:
ctx.getpriv().envrcpt(*str))
# envcallback(ctx.getpriv().envrcpt,str))
milter.set_header_callback(lambda ctx,fld,val:
ctx.getpriv().header(fld,val))
milter.set_eoh_callback(lambda ctx: ctx.getpriv().eoh())
milter.set_body_callback(lambda ctx,chunk: ctx.getpriv().body(chunk))
milter.set_eom_callback(lambda ctx: ctx.getpriv().eom())
milter.set_abort_callback(lambda ctx: ctx.getpriv().abort())
milter.set_close_callback(closecallback)
milter.setconn(socketname)
if timeout > 0: milter.settimeout(timeout)
# The name *must* match the X line in sendmail.cf (supposedly)
milter.register(name)
start_seq = _seq
try:
milter.main()
except milter.error:
if start_seq == _seq: raise # couldn't start
# milter has been running for a while, but now it can't start new threads
raise milter.error("out of thread resources")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment