diff --git a/Milter/__init__.py b/Milter/__init__.py index 2a5ec4f..f0d5d5a 100755 --- a/Milter/__init__.py +++ b/Milter/__init__.py @@ -259,7 +259,7 @@ class Base(object): ## Defined by subclasses to write log messages. def log(self,*msg): pass ## Called for each connection to the MTA. Called by the - # + # # xxfi_connect callback. # The hostname provided by the local MTA is either # the PTR name or the IP in the form "[1.2.3.4]" if no PTR is available. @@ -296,7 +296,7 @@ class Base(object): @nocallback def hello(self,hostname): return CONTINUE ## Called when the SMTP client says MAIL FROM. Called by the - # + # # xxfi_envfrom callback. # Returning REJECT rejects the message, but not the connection. # The sender is the "envelope" from as defined by @@ -307,7 +307,7 @@ class Base(object): @nocallback def envfrom(self,f,*str): return CONTINUE ## Called when the SMTP client says RCPT TO. Called by the - # + # # xxfi_envrcpt callback. # Returning REJECT rejects the current recipient, not the entire message. # The recipient is the "envelope" recipient as defined by @@ -373,7 +373,7 @@ class Base(object): return p ## Negotiate milter protocol options. Called by the - # + # # xffi_negotiate callback. This is an advanced callback, # do not override unless you know what you are doing. Most # negotiation can be done simply by using the supplied @@ -404,7 +404,7 @@ class Base(object): ## Return the value of an MTA macro. Sendmail macro names # are either single chars (e.g. "j") or multiple chars enclosed # in braces (e.g. "{auth_type}"). Macro names are MTA dependent. - # See + # See # smfi_getsymval for default sendmail macros. # @param sym the macro name def getsymval(self,sym): @@ -416,8 +416,17 @@ class Base(object): # must be doubled, or libmilter will silently ignore the setreply. # Beginning with 0.9.6, we test for that case and throw ValueError to avoid # head scratching. What will really irritate you, however, - # is that if you carefully double any '%', your message will be - # sent - but with the '%' still doubled! + # is that if you carefully double any '%%', your message will be + # sent - but with the '%%' still doubled! + # See + # smfi_setreply for more information. + # @param rcode The three-digit (RFC 821/2821) SMTP reply code as a string. + # rcode cannot be None, and must be a valid 4XX or 5XX reply code. + # @param xcode The extended (RFC 1893/2034) reply code. If xcode is None, + # no extended code is used. Otherwise, xcode must conform to RFC 1893/2034. + # @param msg The text part of the SMTP reply. If msg is None, + # an empty message is used. + # @param ml Optional additional message lines. def setreply(self,rcode,xcode=None,msg=None,*ml): for m in (msg,)+ml: if 1 in [len(s)&1 for s in R.findall(m)]: @@ -440,7 +449,7 @@ class Base(object): # Milter methods which can only be called from eom callback. ## Add a mail header field. - # Calls + # Calls # smfi_addheader. # The Milter.ADDHDRS action flag must be set. # @@ -454,7 +463,7 @@ class Base(object): return self._ctx.addheader(field,value,idx) ## Change the value of a mail header field. - # Calls + # Calls # smfi_chgheader. # The Milter.CHGHDRS action flag must be set. # @@ -468,7 +477,7 @@ class Base(object): return self._ctx.chgheader(field,idx,value) ## Add a recipient to the message. - # Calls + # Calls # smfi_addrcpt. # If no corresponding mail header is added, this is like a Bcc. # The syntax of the recipient is the same as used in the SMTP @@ -488,7 +497,7 @@ class Base(object): raise DisabledAction("ADDRCPT_PAR") return self._ctx.addrcpt(rcpt,params) ## Delete a recipient from the message. - # Calls + # Calls # smfi_delrcpt. # The recipient should match one passed to the envrcpt callback. # The Milter.DELRCPT action flag must be set. @@ -501,7 +510,7 @@ class Base(object): return self._ctx.delrcpt(rcpt) ## Replace the message body. - # Calls + # Calls # smfi_replacebody. # The entire message body must be replaced. # Call repeatedly with blocks of data until the entire body is transferred. @@ -515,7 +524,7 @@ class Base(object): return self._ctx.replacebody(body) ## Change the SMTP envelope sender address. - # Calls + # Calls # smfi_chgfrom. # The syntax of the sender is that same as used in the SMTP # MAIL FROM command (and as delivered to the envfrom callback), @@ -532,7 +541,7 @@ class Base(object): return self._ctx.chgfrom(sender,params) ## Quarantine the message. - # Calls + # Calls # smfi_quarantine. # When quarantined, a message goes into the mailq as if to be delivered, # but delivery is deferred until the message is unquarantined. @@ -546,7 +555,7 @@ class Base(object): return self._ctx.quarantine(reason) ## Tell the MTA to wait a bit longer. - # Calls + # Calls # smfi_progress. # Resets timeouts in the MTA that detect a "hung" milter. def progress(self): diff --git a/doc/mainpage.py b/doc/mainpage.py index f8d31b8..e6f5f63 100644 --- a/doc/mainpage.py +++ b/doc/mainpage.py @@ -1,7 +1,7 @@ ## @mainpage Writing Milters in Python # # At the lowest level, the milter module provides a thin wrapper -# around the sendmail +# around the sendmail # libmilter API. This API lets you register callbacks for a number of # events in the process of sendmail receiving a message via SMTP. These # events include the initial connection from a MTA, the envelope sender and @@ -37,10 +37,10 @@ # @section threading # # The libmilter library which pymilter wraps -# handles +# handles # all signals itself, and expects to be called from a single main thread. # It handles SIGTERM, SIGHUP, and SIGINT, mapping the first two to -# smfi_stop +# smfi_stop # and the last to an internal ABORT. # # If you use python threads or threading modules, then signal handling gets diff --git a/doc/milter.py b/doc/milter.py index c35d991..37b1897 100644 --- a/doc/milter.py +++ b/doc/milter.py @@ -20,41 +20,47 @@ # and converts function callbacks to instance method invocations. # class milterContext(object): - ## Calls smfi_getsymval. + ## Calls smfi_getsymval. def getsymval(self,sym): pass - ## Calls + ## Calls # smfi_setreply or - # + # # smfi_setmlreply. # @param rcode SMTP response code # @param xcode extended SMTP response code # @param msg one or more message lines. If the MTA does not support # multiline messages, only the first is used. def setreply(self,rcode,xcode,*msg): pass - ## Calls smfi_addheader. + ## Calls smfi_addheader. def addheader(self,name,value,idx=-1): pass - ## Calls smfi_chgheader. + ## Calls smfi_chgheader. def chgheader(self,name,idx,value): pass - ## Calls smfi_addrcpt. + ## Calls smfi_addrcpt. def addrcpt(self,rcpt,params=None): pass - ## Calls smfi_delrcpt. + ## Calls smfi_delrcpt. def delrcpt(self,rcpt): pass - ## Calls smfi_replacebody. + ## Calls smfi_replacebody. def replacebody(self,data): pass ## Attach a Python object to this connection context. # @return the old value or None def setpriv(self,priv): pass ## Return the Python object attached to this connection context. def getpriv(self): pass - ## Calls smfi_quarantine. + ## Calls smfi_quarantine. def quarantine(self,reason): pass - ## Calls smfi_progress. + ## Calls smfi_progress. def progress(self): pass - ## Calls smfi_chgfrom. + ## Calls smfi_chgfrom. def chgfrom(self,sender,param=None): pass ## Tell the MTA which macro values we are interested in for a given stage. # Of interest only when you need to squeeze a few more bytes of bandwidth. - def setsmlist(self,stage,macrolist): pass + # It may only be called from the negotiate callback. + # The protocol stages are + # M_CONNECT, M_HELO, M_ENVFROM, M_ENVRCPT, M_DATA, M_EOM, M_EOH. + # Calls smfi_setsymlist. + # @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 class error(Exception): pass @@ -91,40 +97,50 @@ def set_exception_policy(code): pass # in the future (perhaps keeping the set functions for compatibility). # @param name the milter name by which the MTA finds us # @param negotiate the -# +# # xxfi_negotiate callback, called to negotiate supported # actions, callbacks, and protocol steps. # @param unknown the -# +# # xxfi_unknown callback, called when for SMTP commands # not recognized by the MTA. (Extend SMTP in your milter!) # @param data the -# +# # xxfi_data callback, called when the DATA # SMTP command is received. 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 +# smfi_opensocket. 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 ## Transfer control to libmilter. -# Calls +# Calls # smfi_main. def main(): pass ## Set the libmilter debugging level. -# smfi_setdbg -# sets the milter library's internal debugging level to a new level +# smfi_setdbg +# 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 # greater (more positive) the level the more detailed the debugging. Six is the # current, highest, useful value. Must be called before calling main(). def setdbg(lev): pass ## Set timeout for MTA communication. -# Calls +# Calls # smfi_settimeout. Must be called before calling main(). def settimeout(secs): pass ## Set socket backlog. -# Calls +# Calls # smfi_setbacklog. Must be called before calling main(). def setbacklog(n): pass diff --git a/makefile b/makefile index 008d236..67f8529 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,8 @@ web: doxygen - rsync -ravK doc/html/ spidey2.bmsi.com:/Public/pymilter + test -L doc/html/milter_api || ln -sf /usr/share/doc/sendmail-devel-* doc/html/milter_api + rsync -ravKk doc/html/ spidey2.bmsi.com:/Public/pymilter + cd doc/html; zip -r ../../doc . VERSION=0.9.6 CVSTAG=pymilter-0_9_6 diff --git a/milter-template.py b/milter-template.py index 77f2c40..48c90bd 100644 --- a/milter-template.py +++ b/milter-template.py @@ -1,6 +1,6 @@ ## 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 +# based on Sendmail's milter API # This code is open-source on the same terms as Python. ## Milter calls methods of your class at milter events.