Compare commits

..

15 Commits

Author SHA1 Message Date
cvs2svn d7ef47d76b This commit was manufactured by cvs2svn to create tag 'pymilter-1_0'.
Sprout from master 2014-03-01 23:38:51 UTC Stuart Gathman <stuart@gathman.org> 'Release 1.0-2'
Cherrypick from bmsi 2005-05-31 18:10:47 UTC Stuart Gathman <stuart@gathman.org> 'Release 0.7.2':
    test/big5
    test/bounce
    test/bounce1
    test/bound
    test/honey
    test/missingboundary
    test/samp1
    test/spam44
    test/spam7
    test/spam8
    test/test1
    test/test8
    test/virus1
    test/virus13
    test/virus2
    test/virus3
    test/virus4
    test/virus5
    test/virus6
    test/virus7
2014-03-01 23:38:52 +00:00
Stuart Gathman 8f7c090879 Release 1.0-2 2014-03-01 23:38:51 +00:00
Stuart Gathman d69c002020 Release 1.0 2014-03-01 23:30:12 +00:00
Stuart Gathman 980dc5f599 pymilter SELinux policy as addon package 2013-06-26 22:24:02 +00:00
Stuart Gathman 8770262622 Initial selinux policy support 2013-06-26 18:28:49 +00:00
Stuart Gathman af49a7a45e Clean while exporting, and handle exporting IP6 2013-06-16 03:39:47 +00:00
Stuart Gathman fca8d83370 Import and export csv for converting existing greylist database. 2013-05-22 18:25:13 +00:00
Stuart Gathman f28cab2d1c Doc updates 2013-04-18 04:06:02 +00:00
Stuart Gathman 76424c7c3f Selinux policy additions. 2013-04-18 04:04:42 +00:00
Stuart Gathman 3e1754acff Call opensocket to check and remove unix domain sockets before starting. 2013-04-18 04:03:36 +00:00
Stuart Gathman 40de08925d Recognize IPv6 localhost. 2013-03-27 02:21:30 +00:00
Stuart Gathman 522a631192 Update Doxyfile 2013-03-22 18:12:50 +00:00
Stuart Gathman 5c8c189330 Remove bad setreply example, doc updates. 2013-03-19 21:25:10 +00:00
Stuart Gathman 5330047902 Move many configs to datadir 2013-03-15 23:04:38 +00:00
Stuart Gathman a8f373ea65 Allow ACCEPT as an exception policy. 2013-03-15 20:50:01 +00:00
18 changed files with 940 additions and 760 deletions
+2 -3
View File
@@ -1,5 +1,5 @@
Jim Niemira (urmane@urmane.org) wrote the original C module and some quick Jim Niemira (urmane@urmane.org) wrote the original C module and some quick
and dirty python to use it. Stuart D. Gathman (stuart@bmsi.com) took that and dirty python to use it. Stuart D. Gathman (stuart@gathman.org) took that
kludge and added threading and context objects to it, wrote a proper OO kludge and added threading and context objects to it, wrote a proper OO
wrapper (Milter.py) that handles attachments, did lots of testing, packaged wrapper (Milter.py) that handles attachments, did lots of testing, packaged
it with distutils, and generally transformed it from a quick hack to a it with distutils, and generally transformed it from a quick hack to a
@@ -7,7 +7,6 @@ real, usable Python extension.
Other contributors (in random order): Other contributors (in random order):
Daniel Troeder Daniel Troeder
for pointing out a typo in @noreply for pointing out a typo in @noreply
arkanes@irc.freenode.net arkanes@irc.freenode.net
@@ -44,4 +43,4 @@ Business Management Systems - http://www.bmsi.com
for hosting the website, and providing paying clients who need milter service for hosting the website, and providing paying clients who need milter service
so I can work on it as part of my day job. so I can work on it as part of my day job.
If I have left anybody out, send me a reminder: stuart@bmsi.com If I have left anybody out, send me a reminder: stuart@gathman.org
+86 -37
View File
@@ -1,4 +1,4 @@
# Doxyfile 1.5.7.1 # Doxyfile 1.6.1
# This file describes the settings to be used by the documentation system # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project # doxygen (www.doxygen.org) for a project
@@ -31,7 +31,7 @@ PROJECT_NAME = pymilter
# This could be handy for archiving the generated documentation or # This could be handy for archiving the generated documentation or
# if some version control system is used. # if some version control system is used.
PROJECT_NUMBER = 0.9.6 PROJECT_NUMBER = 0.9.8
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put. # base path where the generated documentation will be put.
@@ -54,11 +54,11 @@ CREATE_SUBDIRS = NO
# information to generate all constant output in the proper language. # information to generate all constant output in the proper language.
# The default language is English, other supported languages are: # The default language is English, other supported languages are:
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
# Spanish, Swedish, and Ukrainian. # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
@@ -207,6 +207,17 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it parses.
# With this tag you can assign which parser to use for a given extension.
# Doxygen has a built-in mapping, but you can override or extend it using this tag.
# The format is ext=language, where ext is a file extension, and language is one of
# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
EXTENSION_MAPPING =
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should # to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and # set this tag to YES in order to let doxygen match functions declarations and
@@ -394,6 +405,10 @@ SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO SORT_BRIEF_DOCS = NO
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
SORT_MEMBERS_CTORS_1ST = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default) # hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order. # the group names will appear in their defined order.
@@ -468,7 +483,8 @@ SHOW_DIRECTORIES = YES
SHOW_FILES = YES SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page. This will remove the Namespaces entry from the Quick Index # Namespaces page.
# This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES. # and from the Folder Tree View (if specified). The default is YES.
SHOW_NAMESPACES = YES SHOW_NAMESPACES = YES
@@ -511,7 +527,7 @@ WARNINGS = YES
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled. # automatically be disabled.
WARN_IF_UNDOCUMENTED = YES WARN_IF_UNDOCUMENTED = NO
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some # potential errors in the documentation, such as not documenting some
@@ -552,7 +568,10 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories # directories like "/usr/src/myproject". Separate the files or directories
# with spaces. # with spaces.
INPUT = mime.py doc/mainpage.py doc/milter.py Milter INPUT = mime.py \
doc/mainpage.py \
doc/milter.py \
Milter
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -636,14 +655,17 @@ IMAGE_PATH =
# by executing (via popen()) the command <filter> <input-file>, where <filter> # by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an # is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes # input file. Doxygen will then use the output that the filter program writes
# to standard output. If FILTER_PATTERNS is specified, this tag will be # to standard output.
# If FILTER_PATTERNS is specified, this tag will be
# ignored. # ignored.
INPUT_FILTER = INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the # basis.
# filter if there is a match. The filters are a list of the form: # Doxygen will compare the file name with each pattern and apply the
# filter if there is a match.
# The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
# is applied to all files. # is applied to all files.
@@ -693,7 +715,8 @@ REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code. Otherwise they will link to the documentstion. # link to the source code.
# Otherwise they will link to the documentation.
REFERENCES_LINK_SOURCE = YES REFERENCES_LINK_SOURCE = YES
@@ -767,6 +790,11 @@ HTML_HEADER =
HTML_FOOTER = HTML_FOOTER =
# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
# documentation will contain the timesstamp.
HTML_TIMESTAMP = NO
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading # The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to # style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen # fine-tune the look of the HTML output. If the tag is left blank doxygen
@@ -875,16 +903,33 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating # The QHP_NAMESPACE tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see # Qt Help Project output. For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>. # http://doc.trolltech.com/qthelpproject.html#namespace
QHP_NAMESPACE = org.doxygen.Project QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see # Qt Help Project output. For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>. # http://doc.trolltech.com/qthelpproject.html#virtual-folders
QHP_VIRTUAL_FOLDER = doc QHP_VIRTUAL_FOLDER = doc
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
# For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
# filter section matches.
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
QHP_SECT_FILTER_ATTRS =
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator. # be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated # If non-empty doxygen will try to run qhelpgenerator on the generated
@@ -905,21 +950,19 @@ ENUM_VALUES_PER_LINE = 4
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. # structure should be generated to display hierarchical information.
# If the tag value is set to FRAME, a side panel will be generated # If the tag value is set to YES, a side panel will be generated
# containing a tree-like index structure (just like the one that # containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports # is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # Windows users are probably better off using the HTML help feature.
# probably better off using the HTML help feature. Other possible values
# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list;
# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
# disables this behavior completely. For backwards compatibility with previous
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
# respectively.
GENERATE_TREEVIEW = NO GENERATE_TREEVIEW = NO
# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list.
USE_INLINE_TREES = NO
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree # used to set the initial width (in pixels) of the frame in which the tree
# is shown. # is shown.
@@ -934,6 +977,13 @@ TREEVIEW_WIDTH = 250
FORMULA_FONTSIZE = 10 FORMULA_FONTSIZE = 10
# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
# there is already a search function so this one should typically
# be disabled.
SEARCHENGINE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# configuration options related to the LaTeX output # configuration options related to the LaTeX output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -1010,6 +1060,10 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO LATEX_HIDE_INDICES = NO
# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# configuration options related to the RTF output # configuration options related to the RTF output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -1146,8 +1200,10 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader. This is useful # nicely formatted so it can be parsed by a human reader.
# if you want to understand what is going on. On the other hand, if this # This is useful
# if you want to understand what is going on.
# On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller # tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same. # and Perl will parse it just the same.
@@ -1234,8 +1290,10 @@ SKIP_FUNCTION_MACROS = YES
# Optionally an initial location of the external documentation # Optionally an initial location of the external documentation
# can be added for each tagfile. The format of a tag file without # can be added for each tagfile. The format of a tag file without
# this location is as follows: # this location is as follows:
#
# TAGFILES = file1 file2 ... # TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows: # Adding location for the tag files is done as follows:
#
# TAGFILES = file1=loc1 "file2 = loc2" ... # TAGFILES = file1=loc1 "file2 = loc2" ...
# where "loc1" and "loc2" can be relative or absolute paths or # where "loc1" and "loc2" can be relative or absolute paths or
# URLs. If a location is present for each tag, the installdox tool # URLs. If a location is present for each tag, the installdox tool
@@ -1462,12 +1520,3 @@ GENERATE_LEGEND = YES
# the various graphs. # the various graphs.
DOT_CLEANUP = YES DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
# The SEARCHENGINE tag specifies whether or not a search engine should be
# used. If set to NO the values of all tags below this one will be ignored.
SEARCHENGINE = NO
+9 -28
View File
@@ -21,12 +21,6 @@ from functools import wraps
_seq_lock = thread.allocate_lock() _seq_lock = thread.allocate_lock()
_seq = 0 _seq = 0
## @fn set_flags(flags)
# @brief Enable optional %milter actions.
# Certain %milter actions need to be enabled before calling milter.runmilter()
# or they throw an exception.
# @param flags Bit ored mask of optional actions to enable
def uniqueID(): def uniqueID():
"""Return a unique sequence number (incremented on each call). """Return a unique sequence number (incremented on each call).
""" """
@@ -724,28 +718,7 @@ def envcallback(c,args):
# @param socketname the socket to be passed to milter.setconn() # @param socketname the socket to be passed to milter.setconn()
# @param timeout the time in secs the MTA should wait for a response before # @param timeout the time in secs the MTA should wait for a response before
# considering this %milter dead # considering this %milter dead
def runmilter(name,socketname,timeout = 0): def runmilter(name,socketname,timeout = 0,rmsock=True):
# 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 os.error, x:
import errno
if x.errno != errno.ENOENT:
raise milter.error(x)
# The default flags set include everything # The default flags set include everything
# milter.set_flags(milter.ADDHDRS) # milter.set_flags(milter.ADDHDRS)
@@ -776,6 +749,14 @@ def runmilter(name,socketname,timeout = 0):
unknown=lambda ctx,cmd: ctx.getpriv().unknown(cmd), unknown=lambda ctx,cmd: ctx.getpriv().unknown(cmd),
negotiate=ncb negotiate=ncb
) )
# We remove the socket here by default 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.
milter.opensocket(rmsock)
start_seq = _seq start_seq = _seq
try: try:
milter.main() milter.main()
+6 -4
View File
@@ -1,4 +1,5 @@
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
import os.path
class MilterConfigParser(ConfigParser): class MilterConfigParser(ConfigParser):
@@ -20,7 +21,7 @@ class MilterConfigParser(ConfigParser):
return [q.strip() for q in self.get(sect,opt).split(',')] return [q.strip() for q in self.get(sect,opt).split(',')]
return [] return []
def getaddrset(self,sect,opt): def getaddrset(self,sect,opt,dir=''):
if not self.has_option(sect,opt): if not self.has_option(sect,opt):
return {} return {}
s = self.get(sect,opt) s = self.get(sect,opt)
@@ -29,13 +30,14 @@ class MilterConfigParser(ConfigParser):
q = q.strip() q = q.strip()
if q.startswith('file:'): if q.startswith('file:'):
domain = q[5:].lower() domain = q[5:].lower()
d[domain] = d.setdefault(domain,[]) + open(domain,'r').read().split() fname = os.path.join(dir,domain)
d[domain] = d.setdefault(domain,[]) + open(fname,'r').read().split()
else: else:
user,domain = q.split('@') user,domain = q.split('@')
d.setdefault(domain.lower(),[]).append(user) d.setdefault(domain.lower(),[]).append(user)
return d return d
def getaddrdict(self,sect,opt): def getaddrdict(self,sect,opt,dir=''):
if not self.has_option(sect,opt): if not self.has_option(sect,opt):
return {} return {}
d = {} d = {}
@@ -46,7 +48,7 @@ class MilterConfigParser(ConfigParser):
for addr in l.split(','): for addr in l.split(','):
addr = addr.strip() addr = addr.strip()
if addr.startswith('file:'): if addr.startswith('file:'):
fname = addr[5:] fname = os.path.join(dir,addr[5:])
for a in open(fname,'r').read().split(): for a in open(fname,'r').read().split():
d[a] = q d[a] = q
else: else:
+18
View File
@@ -41,6 +41,17 @@ class Greylist(object):
self.dbp = shelve.open(dbname,'c',protocol=2) self.dbp = shelve.open(dbname,'c',protocol=2)
self.lock = thread.allocate_lock() self.lock = thread.allocate_lock()
def export_csv(self,fp,timeinc=0):
"Export records to csv."
import csv
dbp = self.dbp
w = csv.writer(fp)
now = time.time() + timeinc
for key, r in dbp.iteritems():
if now > r.lastseen + self.greylist_retain: continue
ip,sender,recipient = key.rsplit(':',2)
w.writerow([ip,sender,recipient,r.firstseen,r.lastseen,r.cnt,r.umis])
def clean(self,timeinc=0): def clean(self,timeinc=0):
"Delete records past the retention limit." "Delete records past the retention limit."
now = time.time() + timeinc now = time.time() + timeinc
@@ -100,3 +111,10 @@ class Greylist(object):
def close(self): def close(self):
self.dbp.close() self.dbp.close()
if __name__ == '__main__':
import sys
g = Greylist(sys.argv[1],5,24,36)
try:
g.export_csv(sys.stdout)
finally: g.close()
+20
View File
@@ -25,6 +25,19 @@ class Greylist(object):
primary key (ip,sender,recipient))''') primary key (ip,sender,recipient))''')
except: pass except: pass
def import_csv(self,fp):
import csv
rdr = csv.reader(fp)
cur = self.conn.execute('begin immediate')
try:
for r in rdr:
cur.execute('''insert into
greylist(ip,sender,recipient,firstseen,lastseen,cnt,umis)
values(?,?,?,?,?,?,?)''', r)
self.conn.commit()
finally:
cur.close();
def clean(self,timeinc=0): def clean(self,timeinc=0):
"Delete records past the retention limit." "Delete records past the retention limit."
now = time.time() + timeinc - self.greylist_retain now = time.time() + timeinc - self.greylist_retain
@@ -84,3 +97,10 @@ class Greylist(object):
def close(self): def close(self):
self.conn.close() self.conn.close()
if __name__ == '__main__':
import sys
g = Greylist(sys.argv[1])
try:
g.import_csv(sys.stdin)
finally: g.close()
+10 -10
View File
@@ -7,7 +7,7 @@ import Milter
Milter.NOREPLY = Milter.CONTINUE Milter.NOREPLY = Milter.CONTINUE
## Test mixin for unit testing milter applications. ## Test mixin for unit testing %milter applications.
# This mixin overrides many Milter.MilterBase methods # This mixin overrides many Milter.MilterBase methods
# with stub versions that simply record what was done. # with stub versions that simply record what was done.
# @since 0.9.8 # @since 0.9.8
@@ -24,13 +24,13 @@ class TestBase(object):
self._macros = { } self._macros = { }
## The message body. ## The message body.
self._body = None self._body = None
## True if the milter replaced the message body. ## True if the %milter replaced the message body.
self._bodyreplaced = False self._bodyreplaced = False
## True if the milter changed any headers. ## True if the %milter changed any headers.
self._headerschanged = False self._headerschanged = False
## Reply codes and messages set by milter ## Reply codes and messages set by the %milter
self._reply = None self._reply = None
## The rfc822 message object for the current email being fed to the milter. ## The rfc822 message object for the current email being fed to the %milter.
self._msg = None self._msg = None
self._symlist = [ None, None, None, None, None, None, None ] self._symlist = [ None, None, None, None, None, None, None ]
@@ -39,7 +39,7 @@ class TestBase(object):
print >>self.logfp print >>self.logfp
## Set a macro value. ## Set a macro value.
# These are retrieved by the milter with getsymval. # These are retrieved by the %milter with getsymval.
# @param name the macro name, as passed to getsymval # @param name the macro name, as passed to getsymval
# @param val the macro value # @param val the macro value
def setsymval(self,name,val): def setsymval(self,name,val):
@@ -57,7 +57,7 @@ class TestBase(object):
raise IOError,"replacebody not called from eom()" raise IOError,"replacebody not called from eom()"
# FIXME: rfc822 indexing does not really reflect the way chg/add header # FIXME: rfc822 indexing does not really reflect the way chg/add header
# work for a milter # work for a %milter
def chgheader(self,field,idx,value): def chgheader(self,field,idx,value):
if not self._body: if not self._body:
raise IOError,"chgheader not called from eom()" raise IOError,"chgheader not called from eom()"
@@ -103,9 +103,9 @@ class TestBase(object):
a += m a += m
self._symlist[stage] = set(a) self._symlist[stage] = set(a)
## Feed a file like object to the milter. Calls envfrom, envrcpt for ## Feed a file like object to the %milter. Calls envfrom, envrcpt for
# each recipient, header for each header field, body for each body # each recipient, header for each header field, body for each body
# block, and finally eom. A return code from the milter other than # block, and finally eom. A return code from the %milter other than
# CONTINUE returns immediately with that return code. # CONTINUE returns immediately with that return code.
# #
# This is a convenience method, a test could invoke the callbacks # This is a convenience method, a test could invoke the callbacks
@@ -164,7 +164,7 @@ class TestBase(object):
self._body.write(body) self._body.write(body)
return rc return rc
## Feed an email contained in a file to the milter. ## Feed an email contained in a file to the %milter.
# This is a convenience method that invokes @link #feedFile feedFile @endlink. # This is a convenience method that invokes @link #feedFile feedFile @endlink.
# @param sender MAIL FROM # @param sender MAIL FROM
# @param rcpts RCPT TO, multiple recipients may be supplied # @param rcpts RCPT TO, multiple recipients may be supplied
+1 -3
View File
@@ -135,8 +135,6 @@ http://www.bmsi.com/linux/sendmail-rh72.spec
IPv6 Notes IPv6 Notes
---------- ----------
IPv6 is still experimental.
The IPv6 protocol is supported if your operation system supports it The IPv6 protocol is supported if your operation system supports it
and if sendmail was compiled with IPv6 support. To determine if your and if sendmail was compiled with IPv6 support. To determine if your
sendmail supports IPv6, run "sendmail -d0" and check for the NETINET6 sendmail supports IPv6, run "sendmail -d0" and check for the NETINET6
@@ -194,7 +192,7 @@ Authors
------- -------
Jim Niemira (urmane@urmane.org) wrote the original C module and some quick Jim Niemira (urmane@urmane.org) wrote the original C module and some quick
and dirty python to use it. Stuart D. Gathman (stuart@bmsi.com) took that and dirty python to use it. Stuart D. Gathman (stuart@gathman.org) took that
kludge and added threading and context objects to it, wrote a proper OO kludge and added threading and context objects to it, wrote a proper OO
wrapper (Milter.py) that handles attachments, did lots of testing, packaged wrapper (Milter.py) that handles attachments, did lots of testing, packaged
it with distutils, and generally transformed it from a quick hack to a it with distutils, and generally transformed it from a quick hack to a
-4
View File
@@ -1,6 +1,2 @@
Support smfi_negotiate and auto negotiate only those callbacks for which
Milter.Milter methods have been overridden. (Python should be able to
do that.)
Lookup exact RFC syntax of real name / email and make Lookup exact RFC syntax of real name / email and make
Milter.utils.parse_addr() pass all unit tests. Milter.utils.parse_addr() pass all unit tests.
+14 -11
View File
@@ -7,30 +7,32 @@
# events include the initial connection from a MTA, the envelope sender and # events include the initial connection from a MTA, the envelope sender and
# recipients, the top level mail headers, and the message body. There are # recipients, the top level mail headers, and the message body. There are
# options to mangle all of these components of the message as it passes through # options to mangle all of these components of the message as it passes through
# the milter. # the %milter.
# #
# At the next level, the <code>Milter</code> module (note the case difference) # At the next level, the <code>Milter</code> module (note the case difference)
# provides a Python friendly object oriented wrapper for the low level API. To # provides a Python friendly object oriented wrapper for the low level API. To
# use the Milter module, an application registers a 'factory' to create an # use the Milter module, an application registers a 'factory' to create an
# object for each connection from a MTA to sendmail. These connection objects # object for each connection from a MTA to sendmail. These connection objects
# must provide methods corresponding to the libmilter callback events. # must provide methods corresponding to the libmilter event callbacks.
# #
# Each event method returns a code to tell sendmail whether to proceed with # Each callback method returns a code to tell sendmail whether to proceed with
# processing the message. This is a big advantage of milters over other mail # processing the message. This is a big advantage of milters over other mail
# filtering systems. Unwanted mail can be stopped in its tracks at the # filtering systems. Unwanted mail can be stopped in its tracks at the
# earliest possible point. # earliest possible point. The callback return codes are
# milter.CONTINUE, milter.REJECT, milter.DISCARD, milter.ACCEPT,
# milter.TEMPFAIL, milter.SKIP, milter.NOREPLY.
# #
# The <code>Milter.Base</code> class provides default implementations for # The Milter.Base class provides default implementations for
# event methods that do nothing, and also provides wrappers for the libmilter # event methods that do nothing, and also provides wrappers for the libmilter
# methods to mutate the message. It automatically negotiates with MTA # methods to mutate the message. It automatically negotiates with MTA
# which protocol steps need to be processed by the milter, based on # which protocol steps need to be processed by the %milter, based on
# which callback methods are overridden. # which callback methods are overridden.
# #
# The <code>Milter.Milter</code> class provides an alternate default # The Milter.Milter class provides an alternate default
# implementation that logs the main milter events, but otherwise does nothing. # implementation that logs the main milter callbacks, but otherwise does
# It is provided for compatibility. # nothing. It is provided for compatibility.
# #
# The <code>mime</code> module provides a wrapper for the Python email package # The mime module provides a wrapper for the Python email package
# that fixes some bugs, and simplifies modifying selected parts of a MIME # that fixes some bugs, and simplifies modifying selected parts of a MIME
# message. # message.
# #
@@ -50,4 +52,5 @@
# You may find the # You may find the
# <a href="http://docs.python.org/release/2.6.6/library/multiprocessing.html"> # <a href="http://docs.python.org/release/2.6.6/library/multiprocessing.html">
# multiprocessing</a> module useful. It can be a drop-in # multiprocessing</a> module useful. It can be a drop-in
# replacement for threading as illustrated in @ref milter-template.py. # replacement for threading as illustrated in
# <a href="milter-template_8py-example.html">milter-template.py</a>.
+97 -23
View File
@@ -3,10 +3,65 @@
## @package milter ## @package milter
# #
# A thin wrapper around libmilter. # A thin wrapper around libmilter. Most users will not import
# milter directly, but will instead import Milter and subclass
# Milter.Base. This module gives you ultimate low level control
# from python.
# #
## Hold context for a milter connection. ## Continue processing the current connection, message, or recipient.
CONTINUE = 0
## For a connection-oriented routine, reject this connection;
# call Milter.Base.close(). For a message-oriented routine, except
# Milter.Base.eom() or Milter.Base.abort(), reject this message. For a
# recipient-oriented routine, reject the current recipient (but continue
# processing the current message).
REJECT = 1
## For a message- or recipient-oriented routine, accept this message, but
# silently discard it. SMFIS_DISCARD should not be returned by a
# connection-oriented routine.
DISCARD = 2
## For a connection-oriented routine, accept this connection without further
# filter processing; call Milter.Base.close(). For a message- or
# recipient-oriented routine, accept this message without further filtering.
ACCEPT = 3
## Return a temporary failure, i.e., the corresponding SMTP command will return
# an appropriate 4xx status code. For a message-oriented routine, except
# Milter.Base.envfrom(), fail for this message. For a connection-oriented
# routine, fail for this connection; call Milter.Base.close(). For a recipient-oriented
# routine, only
# fail for the current recipient; continue message processing.
TEMPFAIL = 4
## Skip further callbacks of the same type in this transaction.
# Currently this return value is only allowed in Milter.Base.body(). It can be
# used if a %milter has received sufficiently many body chunks to make a
# decision, but still wants to invoke message modification functions that are
# only allowed to be called from Milter.Base.eom(). Note: the %milter must
# negotiate this behavior with the MTA, i.e., it must check whether the
# protocol action SMFIP_SKIP is available and if so, the %milter must request
# it.
SKIP = 5
## Do not send a reply back to the MTA.
# The %milter must negotiate this behavior with the MTA, i.e., it must check
# whether the appropriate protocol action P_NR_* is available and if so,
# the %milter must request it. If you set the P_NR_* protocol action for a
# callback, that callback must always reply with NOREPLY. Using any other
# reply code is a violation of the API. If in some cases your callback may
# return another value (e.g., due to some resource shortages), then you must
# not set P_NR_* and you must use CONTINUE as the default return
# code. (Alternatively you can try to delay reporting the problem to a later
# callback for which P_NR_* is not set.)
#
# This is negotiated and returned automatically by the Milter.noreply
# function decorator.
NOREPLY = 6
## Hold context for a %milter connection.
# Each connection to sendmail creates a new <code>SMFICTX</code> struct within # Each connection to sendmail creates a new <code>SMFICTX</code> struct within
# libmilter. The milter module in turn creates a milterContext # libmilter. The milter module in turn creates a milterContext
# tied to the <code>SMFICTX</code> struct via <code>smfi_setpriv</code> # tied to the <code>SMFICTX</code> struct via <code>smfi_setpriv</code>
@@ -59,12 +114,13 @@ class milterContext(object):
# M_CONNECT, M_HELO, M_ENVFROM, M_ENVRCPT, M_DATA, M_EOM, M_EOH. # M_CONNECT, M_HELO, M_ENVFROM, M_ENVRCPT, M_DATA, M_EOM, M_EOH.
# Calls <a href="https://www.milter.org/developers/api/smfi_setsymlist">smfi_setsymlist</a>. # Calls <a href="https://www.milter.org/developers/api/smfi_setsymlist">smfi_setsymlist</a>.
# @param stage protocol stage in which the macro list should be used # @param stage protocol stage in which the macro list should be used
# @param macrolist a space separated list of macro names
def setsymlist(self,stage,macrolist): pass def setsymlist(self,stage,macrolist): pass
class error(Exception): pass class error(Exception): pass
## Enable optional milter actions. ## Enable optional %milter actions.
# Certain milter actions need to be enabled before calling main() # Certain %milter actions need to be enabled before calling main()
# or they throw an exception. Pymilter enables them all by # or they throw an exception. Pymilter enables them all by
# default (since 0.9.2), but you may wish to disable unneeded # default (since 0.9.2), but you may wish to disable unneeded
# actions as an optimization. # actions as an optimization.
@@ -82,24 +138,27 @@ def set_abort_callback(cb): pass
def set_close_callback(cb): pass def set_close_callback(cb): pass
## Sets the return code for untrapped Python exceptions during a callback. ## Sets the return code for untrapped Python exceptions during a callback.
# Must be one of TEMPFAIL,REJECT,CONTINUE. The default is TEMPFAIL. # The default is TEMPFAIL. You should not depend on this handler. Your
# You should not depend on this handler. Your application should # application should have its own top level exception handler for each
# have its own top level exception handler for each callback. You can # callback. You can then choose your own reply message, log the stack track
# then choose your own reply message, log the stack track were you please, # were you please, and so on. However, if you miss one, this last ditch
# and so on. However, if you miss one, this last ditch handler will # handler will print a standard stack trace to sys.stderr, and return to
# print a standard stack trace to sys.stderr, and return to sendmail. # sendmail.
# @param code one of #TEMPFAIL,#REJECT,#CONTINUE, or since 1.0, #ACCEPT
def set_exception_policy(code): pass def set_exception_policy(code): pass
## Register python milter with libmilter. ## Register python %milter with libmilter.
# The name we pass is used to identify the milter in the MTA configuration. # The name we pass is used to identify the %milter in the MTA configuration.
# Callback functions must be set using the set_*_callback() functions before # Callback functions must be set using the set_*_callback() functions before
# registering the milter. # registering the %milter.
# Three additional callbacks are specified as keyword parameters. These # Three additional callbacks are specified as keyword parameters. These
# were added by recent versions of libmilter. The keyword parameters is # were added by recent versions of libmilter. The keyword parameters is
# a nicer way to do it, I think, since it makes clear that you have to do # a nicer way to do it, I think, since it makes clear that you have to do
# it before registering. I may move all the callbacks # it before registering. I may move all the callbacks in the future (perhaps
# in the future (perhaps keeping the set functions for compatibility). # keeping the set functions for compatibility). Note that Milter.Base
# @param name the milter name by which the MTA finds us # automatically maps all callbacks to member functions, and negotiates which
# member functions are actually overridden by an application class.
# @param name the %milter name by which the MTA finds us
# @param negotiate the # @param negotiate the
# <a href="https://www.milter.org/developers/api/xxfi_negotiate"> # <a href="https://www.milter.org/developers/api/xxfi_negotiate">
# xxfi_negotiate</a> callback, called to negotiate supported # xxfi_negotiate</a> callback, called to negotiate supported
@@ -113,6 +172,16 @@ def set_exception_policy(code): pass
# xxfi_data</a> callback, called when the DATA # xxfi_data</a> callback, called when the DATA
# SMTP command is received. # SMTP command is received.
def register(name,negotiate=None,unknown=None,data=None): pass def register(name,negotiate=None,unknown=None,data=None): pass
## Attempt to create the socket used to communicate with the MTA.
# milter.opensocket() attempts to create the socket specified previously by a
# call to milter.setconn() which will be the interface between MTAs and the
# %milter. This allows the calling application to ensure that the socket can be
# created. If this is not called, milter.main() will do so implicitly.
# Calls <a href="https://www.milter.org/developers/api/smfi_opensocket">
# smfi_opensocket</a>. While not documented for libmilter, my experiments
# indicate that you must call register() before calling opensocket().
# @param rmsock Try to remove an existing unix domain socket if true.
def opensocket(rmsock): pass def opensocket(rmsock): pass
## Transfer control to libmilter. ## Transfer control to libmilter.
@@ -122,7 +191,7 @@ def main(): pass
## Set the libmilter debugging level. ## Set the libmilter debugging level.
# <a href="https://www.milter.org/developers/api/smfi_setdbg">smfi_setdbg</a> # <a href="https://www.milter.org/developers/api/smfi_setdbg">smfi_setdbg</a>
# sets the milter library's internal debugging level to a new level # sets the %milter library's internal debugging level to a new level
# so that code details may be traced. A level of zero turns off debugging. The # so that code details may be traced. A level of zero turns off debugging. The
# greater (more positive) the level the more detailed the debugging. Six is the # greater (more positive) the level the more detailed the debugging. Six is the
# current, highest, useful value. Must be called before calling main(). # current, highest, useful value. Must be called before calling main().
@@ -143,16 +212,21 @@ def setbacklog(n): pass
# unix, inet, or inet6 socket. By default, a unix domain socket # unix, inet, or inet6 socket. By default, a unix domain socket
# is used. It must not exist, # is used. It must not exist,
# and sendmail will throw warnings if, eg, the file is under a # and sendmail will throw warnings if, eg, the file is under a
# group or world writable directory. # group or world writable directory. milter.setconn() will not fail with
# an invalid socket - this will be detected only when calling milter.main()
# or milter.opensocket().
# @param s the socket address in proto:address format
# <pre> # <pre>
# setconn('unix:/var/run/pythonfilter') # milter.setconn('unix:/var/run/pythonfilter') # a named pipe
# setconn('inet:8800') # listen on ANY interface # milter.setconn('local:/var/run/pythonfilter') # a named pipe
# setconn('inet:7871@@publichost') # listen on a specific interface # milter.setconn('inet:8800') # listen on ANY interface
# setconn('inet6:8020') # milter.setconn('inet:7871@@publichost') # listen on a specific interface
# milter.setconn('inet6:8020')
# milter.setconn('inet6:8020@[2001:db8:1234::1]') # listen on specific IP
# </pre> # </pre>
def setconn(s): pass def setconn(s): pass
## Stop the milter gracefully. ## Stop the %milter gracefully.
def stop(): pass def stop(): pass
## Retrieve diagnostic info. ## Retrieve diagnostic info.
+3 -2
View File
@@ -1,9 +1,10 @@
web: web:
doxygen doxygen
cd doc/html; zip -r ../../doc .
rsync -ravK doc/html/ spidey2.bmsi.com:/Public/pymilter rsync -ravK doc/html/ spidey2.bmsi.com:/Public/pymilter
VERSION=0.9.8 VERSION=1.0
CVSTAG=pymilter-0_9_8 CVSTAG=pymilter-1_0
PKG=pymilter-$(VERSION) PKG=pymilter-$(VERSION)
SRCTAR=$(PKG).tar.gz SRCTAR=$(PKG).tar.gz
+3 -1
View File
@@ -71,6 +71,9 @@ class myMilter(Milter.Base):
self.fromparms = Milter.dictfromlist(str) # ESMTP parms self.fromparms = Milter.dictfromlist(str) # ESMTP parms
self.user = self.getsymval('{auth_authen}') # authenticated user self.user = self.getsymval('{auth_authen}') # authenticated user
self.log("mail from:", mailfrom, *str) self.log("mail from:", mailfrom, *str)
# NOTE: self.fp is only an *internal* copy of message data. You
# must use addheader, chgheader, replacebody to change the message
# on the MTA.
self.fp = StringIO.StringIO() self.fp = StringIO.StringIO()
self.canon_from = '@'.join(parse_addr(mailfrom)) self.canon_from = '@'.join(parse_addr(mailfrom))
self.fp.write('From %s %s\n' % (self.canon_from,time.ctime())) self.fp.write('From %s %s\n' % (self.canon_from,time.ctime()))
@@ -104,7 +107,6 @@ class myMilter(Milter.Base):
def eom(self): def eom(self):
self.fp.seek(0) self.fp.seek(0)
msg = email.message_from_file(self.fp) 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() # many milter functions can only be called from eom()
# example of adding a Bcc: # example of adding a Bcc:
self.addrcpt('<%s>' % 'spy@example.com') self.addrcpt('<%s>' % 'spy@example.com')
+10 -3
View File
@@ -35,6 +35,9 @@ $ python setup.py help
libraries=["milter","smutil","resolv"] libraries=["milter","smutil","resolv"]
* $Log$ * $Log$
* Revision 1.35 2013/03/14 22:11:25 customdesigned
* Release 0.9.8
*
* Revision 1.34 2013/03/09 05:42:14 customdesigned * Revision 1.34 2013/03/09 05:42:14 customdesigned
* Make TestBase members private, fix getsymlist misspelling. * Make TestBase members private, fix getsymlist misspelling.
* *
@@ -641,7 +644,8 @@ milter_set_exception_policy(PyObject *self, PyObject *args) {
if (!PyArg_ParseTuple(args, "i:set_exception_policy", &i)) if (!PyArg_ParseTuple(args, "i:set_exception_policy", &i))
return NULL; return NULL;
switch (i) { switch (i) {
case SMFIS_REJECT: case SMFIS_TEMPFAIL: case SMFIS_CONTINUE: case SMFIS_REJECT: case SMFIS_TEMPFAIL:
case SMFIS_CONTINUE: case SMFIS_ACCEPT:
exception_policy = i; exception_policy = i;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
@@ -661,9 +665,9 @@ _release_thread(PyThreadState *t) {
The interpreter is locked when we are called, and we unlock it. */ The interpreter is locked when we are called, and we unlock it. */
static int _report_exception(milter_ContextObject *self) { static int _report_exception(milter_ContextObject *self) {
char untrapped_msg[80]; char untrapped_msg[80];
if (PyErr_Occurred()) {
sprintf(untrapped_msg,"pymilter: untrapped exception in %.40s", sprintf(untrapped_msg,"pymilter: untrapped exception in %.40s",
description.xxfi_name); description.xxfi_name);
if (PyErr_Occurred()) {
PyErr_Print(); PyErr_Print();
PyErr_Clear(); /* must clear since not returning to python */ PyErr_Clear(); /* must clear since not returning to python */
_release_thread(self->t); _release_thread(self->t);
@@ -675,8 +679,11 @@ static int _report_exception(milter_ContextObject *self) {
smfi_setreply(self->ctx, "451", "4.3.0", untrapped_msg); smfi_setreply(self->ctx, "451", "4.3.0", untrapped_msg);
return SMFIS_TEMPFAIL; return SMFIS_TEMPFAIL;
} }
return SMFIS_CONTINUE; return exception_policy;
} }
/* This should never happen, _report_exception is only called when
* the caller has already detected a python exception. If it
* does somehow happen, pretend nothing is wrong... */
_release_thread(self->t); _release_thread(self->t);
return SMFIS_CONTINUE; return SMFIS_CONTINUE;
} }
+43 -26
View File
@@ -6,9 +6,10 @@
Summary: Python interface to sendmail milter API Summary: Python interface to sendmail milter API
Name: %{pythonbase}-pymilter Name: %{pythonbase}-pymilter
Version: 0.9.8 Version: 1.0
Release: 1%{dist} Release: 1%{dist}
Source: http://downloads.sourceforge.net/pymilter/pymilter-%{version}.tar.gz Source: http://downloads.sourceforge.net/pymilter/pymilter-%{version}.tar.gz
Source1: pymilter.te
License: GPLv2+ License: GPLv2+
Group: Development/Libraries Group: Development/Libraries
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
@@ -26,11 +27,23 @@ 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 selinux
Summary: SELinux policy module for pymilter
Group: System Environment/Base
Requires: policycoreutils, selinux-policy, %{name}
BuildRequires: policycoreutils, checkpolicy
%description selinux
SELinux policy module for using pymilter with sendmail with selinux enforcing
%prep %prep
%setup -q -n pymilter-%{version} %setup -q -n pymilter-%{version}
cp %{SOURCE1} pymilter.te
%build %build
env CFLAGS="$RPM_OPT_FLAGS" %{__python} setup.py build env CFLAGS="$RPM_OPT_FLAGS" %{__python} setup.py build
checkmodule -m -M -o pymilter.mod pymilter.te
semodule_package -o pymilter.pp -m pymilter.mod
%install %install
rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT
@@ -38,31 +51,11 @@ rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/milter mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/milter
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/milter mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/milter
mkdir -p $RPM_BUILD_ROOT%{libdir} mkdir -p $RPM_BUILD_ROOT%{libdir}
cp start.sh $RPM_BUILD_ROOT%{libdir}
ed $RPM_BUILD_ROOT%{libdir}/start.sh <<'EOF'
/^datadir=/
c
datadir="%{_localstatedir}/log/milter"
.
/^piddir=/
c
piddir="%{_localstatedir}/run/milter"
.
/^libdir=/
c
libdir="%{libdir}"
.
/^python=/
c
python="%{__python}"
.
w
q
EOF
chmod a+x $RPM_BUILD_ROOT%{libdir}/start.sh
# start.sh is used by spfmilter, srsmilter, and milter, and could be used by # install selinux modules
# other milters using pymilter. mkdir -p %{buildroot}%{_datadir}/selinux/targeted
cp -p pymilter.pp %{buildroot}%{_datadir}/selinux/targeted
%files %files
%defattr(-,root,root,-) %defattr(-,root,root,-)
%doc README ChangeLog NEWS TODO CREDITS sample.py milter-template.py %doc README ChangeLog NEWS TODO CREDITS sample.py milter-template.py
@@ -71,17 +64,41 @@ chmod a+x $RPM_BUILD_ROOT%{libdir}/start.sh
%dir %attr(0755,mail,mail) %{_localstatedir}/run/milter %dir %attr(0755,mail,mail) %{_localstatedir}/run/milter
%dir %attr(0755,mail,mail) %{_localstatedir}/log/milter %dir %attr(0755,mail,mail) %{_localstatedir}/log/milter
%files selinux
%doc pymilter.te
%{_datadir}/selinux/targeted/*
%clean %clean
rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT
%post selinux
/usr/sbin/semodule -s targeted -i %{_datadir}/selinux/targeted/pymilter.pp \
&>/dev/null || :
%postun selinux
if [ $1 -eq 0 ] ; then
/usr/sbin/semodule -s targeted -r pymilter &> /dev/null || :
fi
%changelog %changelog
* Sat Mar 1 2014 Stuart Gathman <stuart@gathman.org> 1.0-2
- Remove start.sh to track EPEL repository, suggest daemonize as replacement
- Selinux subpackage should not care about pymilter version
* Wed Jun 26 2013 Stuart Gathman <stuart@gathman.org> 1.0-1
- Allow ACCEPT as untrapped exception policy
- Optional dir for getaddrset and getaddrdict in Milter.config
- Show registered milter name in untrapped exception message.
- Include selinux subpackage
- Provide Milter.greylist export and Milter.greylist import to migrate data
* Sat Mar 9 2013 Stuart Gathman <stuart@bmsi.com> 0.9.8-1 * Sat Mar 9 2013 Stuart Gathman <stuart@bmsi.com> 0.9.8-1
- Add Milter.test module for unit testing milters. - Add Milter.test module for unit testing milters.
- Fix typo that prevented setsymlist from being active. - Fix typo that prevented setsymlist from being active.
- Change untrapped exception message to: - Change untrapped exception message to:
- "pymilter: untrapped exception in milter app" - "pymilter: untrapped exception in milter app"
* Sat Feb 25 2012 Stuart Gathman <stuart@bmsi.com> 0.9.7-1 * Thu Apr 12 2012 Stuart Gathman <stuart@bmsi.com> 0.9.7-1
- Raise RuntimeError when result != CONTINUE for @noreply and @nocallback - Raise RuntimeError when result != CONTINUE for @noreply and @nocallback
- Remove redundant table in miltermodule - Remove redundant table in miltermodule
- Fix CNAME chain duplicating TXT records in Milter.dns (from pyspf). - Fix CNAME chain duplicating TXT records in Milter.dns (from pyspf).
+13
View File
@@ -0,0 +1,13 @@
module pymilter 1.0;
require {
type sendmail_t;
type var_run_t;
type initrc_t;
class sock_file { write getattr };
class unix_stream_socket connectto;
}
#============= sendmail_t ==============
allow sendmail_t initrc_t:unix_stream_socket connectto;
allow sendmail_t var_run_t:sock_file { write getattr };
+2 -2
View File
@@ -1,5 +1,5 @@
[bdist_rpm] [bdist_rpm]
python=python2.6 python=python2.6
doc_files=README NEWS TODO doc_files=README NEWS TODO COPYING CREDITS
packager=Stuart D. Gathman <stuart@bmsi.com> packager=Stuart D. Gathman <stuart@gathman.org>
release=1 release=1
+1 -1
View File
@@ -13,7 +13,7 @@ libs = ["milter"]
libdirs = ["/usr/lib/libmilter"] # needed for Debian libdirs = ["/usr/lib/libmilter"] # needed for Debian
# 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 = "pymilter", version = '0.9.8', setup(name = "pymilter", version = '1.0',
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