Build pymilter as separate package.
This commit is contained in:
@@ -0,0 +1,155 @@
|
|||||||
|
## To roll your own milter, create a class that extends Milter.
|
||||||
|
# See the pymilter project at http://bmsi.com/python/milter.html
|
||||||
|
# based on Sendmail's milter API http://www.milter.org/milter_api/api.html
|
||||||
|
# This code is open-source on the same terms as Python.
|
||||||
|
|
||||||
|
## Milter calls methods of your class at milter events.
|
||||||
|
## Return REJECT,TEMPFAIL,ACCEPT to short circuit processing for a message.
|
||||||
|
## You can also add/del recipients, replacebody, add/del headers, etc.
|
||||||
|
|
||||||
|
import Milter
|
||||||
|
import StringIO
|
||||||
|
import time
|
||||||
|
import email
|
||||||
|
from socket import AF_INET, AF_INET6
|
||||||
|
|
||||||
|
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('@')
|
||||||
|
|
||||||
|
class myMilter(Milter.Milter):
|
||||||
|
|
||||||
|
def __init__(self): # A new instance with each new connection.
|
||||||
|
self.id = Milter.uniqueID() # Integer incremented with each call.
|
||||||
|
|
||||||
|
# each connection runs in its own thread and has its own myMilter
|
||||||
|
# instance. Python code must be thread safe. This is trivial if only stuff
|
||||||
|
# in myMilter instances is referenced.
|
||||||
|
def connect(self, IPname, family, hostaddr):
|
||||||
|
# (self, 'ip068.subnet71.example.com', AF_INET, ('215.183.71.68', 4720) )
|
||||||
|
# (self, 'ip6.mxout.example.com', AF_INET6,
|
||||||
|
# ('3ffe:80e8:d8::1', 4720, 1, 0) )
|
||||||
|
self.IP = hostaddr[0]
|
||||||
|
self.port = hostaddr[1]
|
||||||
|
if family == AF_INET6:
|
||||||
|
self.flow = hostaddr[2]
|
||||||
|
self.scope = hostaddr[3]
|
||||||
|
else:
|
||||||
|
self.flow = None
|
||||||
|
self.scope = None
|
||||||
|
self.IPname = IPname # Name from a reverse IP lookup
|
||||||
|
self.H = None
|
||||||
|
self.fp = None
|
||||||
|
self.receiver = self.getsymval('j')
|
||||||
|
self.log("connect from %s at %s" % (IPname, hostaddr) )
|
||||||
|
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
|
||||||
|
## def hello(self,hostname):
|
||||||
|
def hello(self, heloname):
|
||||||
|
# (self, 'mailout17.dallas.texas.example.com')
|
||||||
|
self.H = heloname
|
||||||
|
self.log("HELO %s" % heloname)
|
||||||
|
if heloname.find('.') < 0: # illegal helo name
|
||||||
|
# NOTE: example only - too many real braindead clients to reject on this
|
||||||
|
self.setreply('550','5.7.1','Sheesh people! Use a proper helo name!')
|
||||||
|
return Milter.REJECT
|
||||||
|
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
## def envfrom(self,f,*str):
|
||||||
|
def envfrom(self, mailfrom, *str):
|
||||||
|
self.F = mailfrom
|
||||||
|
self.R = [] # list of recipients
|
||||||
|
self.fromparms = Milter.dictfromlist(str) # ESMTP parms
|
||||||
|
self.user = self.getsymval('{auth_authen}') # authenticated user
|
||||||
|
self.log("mail from:", mailfrom, *str)
|
||||||
|
self.fp = StringIO.StringIO()
|
||||||
|
self.canon_from = '@'.join(parse_addr(mailfrom))
|
||||||
|
self.fp.write('From %s %s\n' % (self.canon_from,time.ctime()))
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
|
||||||
|
## def envrcpt(self, to, *str):
|
||||||
|
def envrcpt(self, recipient, *str):
|
||||||
|
rcptinfo = to,Milter.dictfromlist(str)
|
||||||
|
self.R.append(rcptinfo)
|
||||||
|
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
|
||||||
|
def header(self, name, hval):
|
||||||
|
self.fp.write("%s: %s\n" % (name,hval)) # add header to buffer
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
|
||||||
|
def eoh(self):
|
||||||
|
self.fp.write("\n") # terminate headers
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
|
||||||
|
def body(self, chunk):
|
||||||
|
self.fp.write(chunk)
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
|
||||||
|
def eom(self):
|
||||||
|
self.fp.seek(0)
|
||||||
|
msg = email.message_from_file(self.fp)
|
||||||
|
self.setreply('250','2.5.1','Grokked by pymilter')
|
||||||
|
# many milter functions can only be called from eom()
|
||||||
|
# example of adding a Bcc:
|
||||||
|
self.addrcpt('<%s>' % 'spy@example.com')
|
||||||
|
return Milter.ACCEPT
|
||||||
|
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
# always called, even when abort is called. Clean up
|
||||||
|
# any external resources here.
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
def abort(self):
|
||||||
|
# client disconnected prematurely
|
||||||
|
return Milter.CONTINUE
|
||||||
|
|
||||||
|
## === Support Functions ===
|
||||||
|
|
||||||
|
def log(self,*msg):
|
||||||
|
print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S'),self.id),
|
||||||
|
# 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
|
||||||
|
for i in msg: print i,
|
||||||
|
print
|
||||||
|
|
||||||
|
|
||||||
|
## ===
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Register to have the Milter factory create instances of your class:
|
||||||
|
Milter.factory = myMilter
|
||||||
|
flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
|
||||||
|
flags += Milter.ADDRCPT
|
||||||
|
flags += Milter.DELRCPT
|
||||||
|
Milter.set_flags(flags) # tell Sendmail which features we use
|
||||||
|
print "%s milter startup" % time.strftime('%Y%b%d %H:%M:%S')
|
||||||
|
sys.stdout.flush()
|
||||||
|
Milter.runmilter("pythonfilter",socketname,timeout)
|
||||||
|
print "%s bms milter shutdown" % time.strftime('%Y%b%d %H:%M:%S')
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+14
-3
@@ -1,5 +1,5 @@
|
|||||||
%define name milter
|
%define name pymilter
|
||||||
%define version 0.8.7
|
%define version 0.8.8
|
||||||
%define release 1
|
%define release 1
|
||||||
# what version of RH are we building for?
|
# what version of RH are we building for?
|
||||||
%define redhat7 0
|
%define redhat7 0
|
||||||
@@ -37,7 +37,7 @@ Prefix: %{_prefix}
|
|||||||
Vendor: Stuart D. Gathman <stuart@bmsi.com>
|
Vendor: Stuart D. Gathman <stuart@bmsi.com>
|
||||||
Packager: Stuart D. Gathman <stuart@bmsi.com>
|
Packager: Stuart D. Gathman <stuart@bmsi.com>
|
||||||
Url: http://www.bmsi.com/python/milter.html
|
Url: http://www.bmsi.com/python/milter.html
|
||||||
Requires: %{python} >= 2.4, sendmail >= 8.13, pyspf >= 2.0.4
|
Requires: %{python} >= 2.4, sendmail >= 8.13
|
||||||
%ifos Linux
|
%ifos Linux
|
||||||
Requires: chkconfig
|
Requires: chkconfig
|
||||||
%endif
|
%endif
|
||||||
@@ -49,6 +49,14 @@ attach to sendmail's libmilter functionality. Additional python
|
|||||||
modules provide for navigating and modifying MIME parts, sending
|
modules provide for navigating and modifying MIME parts, sending
|
||||||
DSNs, and doing CBV.
|
DSNs, and doing CBV.
|
||||||
|
|
||||||
|
%package -n milter
|
||||||
|
Group: Applications/System
|
||||||
|
Summary: BMS spam and reputation milter
|
||||||
|
Requires: pyspf >= 2.0.4
|
||||||
|
|
||||||
|
%description -n milter
|
||||||
|
An effective spam filtering and reputation tracking mail application.
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup
|
%setup
|
||||||
#patch -p0 -b .bms
|
#patch -p0 -b .bms
|
||||||
@@ -158,6 +166,9 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
%files -f INSTALLED_FILES
|
%files -f INSTALLED_FILES
|
||||||
%defattr(-,root,root)
|
%defattr(-,root,root)
|
||||||
%doc README HOWTO ChangeLog NEWS TODO CREDITS sample.py milter-template.py
|
%doc README HOWTO ChangeLog NEWS TODO CREDITS sample.py milter-template.py
|
||||||
|
|
||||||
|
%files -n milter
|
||||||
|
%defattr(-,root,root)
|
||||||
/etc/logrotate.d/milter
|
/etc/logrotate.d/milter
|
||||||
/etc/cron.daily/milter
|
/etc/cron.daily/milter
|
||||||
%ifos aix4.1
|
%ifos aix4.1
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ if sys.version < '2.2.3':
|
|||||||
DistributionMetadata.download_url = None
|
DistributionMetadata.download_url = None
|
||||||
|
|
||||||
# NOTE: importing Milter to obtain version fails when milter.so not built
|
# NOTE: importing Milter to obtain version fails when milter.so not built
|
||||||
setup(name = "milter", version = '0.8.8',
|
setup(name = "pymilter", version = '0.8.8',
|
||||||
description="Python interface to sendmail milter API",
|
description="Python interface to sendmail milter API",
|
||||||
long_description="""\
|
long_description="""\
|
||||||
This is a python extension module to enable python scripts to
|
This is a python extension module to enable python scripts to
|
||||||
|
|||||||
Reference in New Issue
Block a user