\doxysection{milter-\/template.\+py}

\begin{DoxyCodeInclude}{0}
\DoxyCodeLine{1 }
\DoxyCodeLine{5 }
\DoxyCodeLine{6 }
\DoxyCodeLine{9 }
\DoxyCodeLine{10 \textcolor{keyword}{from} \_\_future\_\_ \textcolor{keyword}{import} print\_function}
\DoxyCodeLine{11 \textcolor{keyword}{import} Milter}
\DoxyCodeLine{12 \textcolor{keywordflow}{try}:}
\DoxyCodeLine{13   \textcolor{keyword}{from} StringIO \textcolor{keyword}{import} StringIO}
\DoxyCodeLine{14 \textcolor{keywordflow}{except}:}
\DoxyCodeLine{15   \textcolor{keyword}{from} io \textcolor{keyword}{import} StringIO}
\DoxyCodeLine{16 \textcolor{keyword}{import} time}
\DoxyCodeLine{17 \textcolor{keyword}{import} email}
\DoxyCodeLine{18 \textcolor{keyword}{import} sys}
\DoxyCodeLine{19 \textcolor{keyword}{from} socket \textcolor{keyword}{import} AF\_INET, AF\_INET6}
\DoxyCodeLine{20 \textcolor{keyword}{from} Milter.utils \textcolor{keyword}{import} parse\_addr}
\DoxyCodeLine{21 \textcolor{keywordflow}{if} \textcolor{keyword}{True}:}
\DoxyCodeLine{22   \textcolor{keyword}{from} multiprocessing \textcolor{keyword}{import} Process \textcolor{keyword}{as} Thread, Queue}
\DoxyCodeLine{23 \textcolor{keywordflow}{else}:}
\DoxyCodeLine{24   \textcolor{keyword}{from} threading \textcolor{keyword}{import} Thread}
\DoxyCodeLine{25   \textcolor{keyword}{from} Queue \textcolor{keyword}{import} Queue}
\DoxyCodeLine{26 }
\DoxyCodeLine{27 logq = Queue(maxsize=4)}
\DoxyCodeLine{28 }
\DoxyCodeLine{29 \textcolor{keyword}{class }myMilter(Milter.Base):}
\DoxyCodeLine{30 }
\DoxyCodeLine{31   \textcolor{keyword}{def }\_\_init\_\_(self):  \textcolor{comment}{\# A new instance with each new connection.}}
\DoxyCodeLine{32     self.id = Milter.uniqueID()  \textcolor{comment}{\# Integer incremented with each call.}}
\DoxyCodeLine{33 }
\DoxyCodeLine{34   \textcolor{comment}{\# each connection runs in its own thread and has its own myMilter}}
\DoxyCodeLine{35   \textcolor{comment}{\# instance.  Python code must be thread safe.  This is trivial if only stuff}}
\DoxyCodeLine{36   \textcolor{comment}{\# in myMilter instances is referenced.}}
\DoxyCodeLine{37   @Milter.noreply}
\DoxyCodeLine{38   \textcolor{keyword}{def }connect(self, IPname, family, hostaddr):}
\DoxyCodeLine{39     \textcolor{comment}{\# (self, 'ip068.subnet71.example.com', AF\_INET, ('215.183.71.68', 4720) )}}
\DoxyCodeLine{40     \textcolor{comment}{\# (self, 'ip6.mxout.example.com', AF\_INET6,}}
\DoxyCodeLine{41     \textcolor{comment}{\#   ('3ffe:80e8:d8::1', 4720, 1, 0) )}}
\DoxyCodeLine{42     self.IP = hostaddr[0]}
\DoxyCodeLine{43     self.port = hostaddr[1]}
\DoxyCodeLine{44     \textcolor{keywordflow}{if} family == AF\_INET6:}
\DoxyCodeLine{45       self.flow = hostaddr[2]}
\DoxyCodeLine{46       self.scope = hostaddr[3]}
\DoxyCodeLine{47     \textcolor{keywordflow}{else}:}
\DoxyCodeLine{48       self.flow = \textcolor{keywordtype}{None}}
\DoxyCodeLine{49       self.scope = \textcolor{keywordtype}{None}}
\DoxyCodeLine{50     self.IPname = IPname  \textcolor{comment}{\# Name from a reverse IP lookup}}
\DoxyCodeLine{51     self.H = \textcolor{keywordtype}{None}}
\DoxyCodeLine{52     self.fp = \textcolor{keywordtype}{None}}
\DoxyCodeLine{53     self.receiver = self.getsymval(\textcolor{stringliteral}{'j'})}
\DoxyCodeLine{54     self.log(\textcolor{stringliteral}{"connect from \%s at \%s"} \% (IPname, hostaddr) )}
\DoxyCodeLine{55     }
\DoxyCodeLine{56     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{57 }
\DoxyCodeLine{58 }
\DoxyCodeLine{59   }
\DoxyCodeLine{60   \textcolor{keyword}{def }hello(self, heloname):}
\DoxyCodeLine{61     \textcolor{comment}{\# (self, 'mailout17.dallas.texas.example.com')}}
\DoxyCodeLine{62     self.H = heloname}
\DoxyCodeLine{63     self.log(\textcolor{stringliteral}{"HELO \%s"} \% heloname)}
\DoxyCodeLine{64     \textcolor{keywordflow}{if} heloname.find(\textcolor{stringliteral}{'.'}) < 0:  \textcolor{comment}{\# illegal helo name}}
\DoxyCodeLine{65       \textcolor{comment}{\# NOTE: example only -\/ too many real braindead clients to reject on this}}
\DoxyCodeLine{66       self.setreply(\textcolor{stringliteral}{'550'},\textcolor{stringliteral}{'5.7.1'},\textcolor{stringliteral}{'Sheesh people!  Use a proper helo name!'})}
\DoxyCodeLine{67       \textcolor{keywordflow}{return} Milter.REJECT}
\DoxyCodeLine{68       }
\DoxyCodeLine{69     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{70 }
\DoxyCodeLine{71   }
\DoxyCodeLine{72   \textcolor{keyword}{def }envfrom(self, mailfrom, *str):}
\DoxyCodeLine{73     self.F = mailfrom}
\DoxyCodeLine{74     self.R = []  \textcolor{comment}{\# list of recipients}}
\DoxyCodeLine{75     self.fromparms = Milter.dictfromlist(str)        \textcolor{comment}{\# ESMTP parms}}
\DoxyCodeLine{76     self.user = self.getsymval(\textcolor{stringliteral}{'\{auth\_authen\}'}) \textcolor{comment}{\# authenticated user}}
\DoxyCodeLine{77     self.log(\textcolor{stringliteral}{"mail from:"}, mailfrom, *str)}
\DoxyCodeLine{78     \textcolor{comment}{\# NOTE: self.fp is only an *internal* copy of message data.  You}}
\DoxyCodeLine{79     \textcolor{comment}{\# must use addheader, chgheader, replacebody to change the message}}
\DoxyCodeLine{80     \textcolor{comment}{\# on the MTA.}}
\DoxyCodeLine{81     self.fp = StringIO()}
\DoxyCodeLine{82     self.canon\_from = \textcolor{stringliteral}{'@'}.join(parse\_addr(mailfrom))}
\DoxyCodeLine{83     self.fp.write(\textcolor{stringliteral}{'From \%s \%s\(\backslash\)n'} \% (self.canon\_from,time.ctime()))}
\DoxyCodeLine{84     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{85 }
\DoxyCodeLine{86 }
\DoxyCodeLine{87   }
\DoxyCodeLine{88   @Milter.noreply}
\DoxyCodeLine{89   \textcolor{keyword}{def }envrcpt(self, to, *str):}
\DoxyCodeLine{90     rcptinfo = to,Milter.dictfromlist(str)}
\DoxyCodeLine{91     self.R.append(rcptinfo)}
\DoxyCodeLine{92     }
\DoxyCodeLine{93     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{94 }
\DoxyCodeLine{95 }
\DoxyCodeLine{96   @Milter.noreply}
\DoxyCodeLine{97   \textcolor{keyword}{def }header(self, name, hval):}
\DoxyCodeLine{98     self.fp.write(\textcolor{stringliteral}{"\%s: \%s\(\backslash\)n"} \% (name,hval))     \textcolor{comment}{\# add header to buffer}}
\DoxyCodeLine{99     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{100 }
\DoxyCodeLine{101   @Milter.noreply}
\DoxyCodeLine{102   \textcolor{keyword}{def }eoh(self):}
\DoxyCodeLine{103     self.fp.write(\textcolor{stringliteral}{"\(\backslash\)n"})                         \textcolor{comment}{\# terminate headers}}
\DoxyCodeLine{104     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{105 }
\DoxyCodeLine{106   @Milter.noreply}
\DoxyCodeLine{107   \textcolor{keyword}{def }body(self, chunk):}
\DoxyCodeLine{108     self.fp.write(chunk)}
\DoxyCodeLine{109     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{110 }
\DoxyCodeLine{111   \textcolor{keyword}{def }eom(self):}
\DoxyCodeLine{112     self.fp.seek(0)}
\DoxyCodeLine{113     msg = email.message\_from\_file(self.fp)}
\DoxyCodeLine{114     \textcolor{comment}{\# many milter functions can only be called from eom()}}
\DoxyCodeLine{115     \textcolor{comment}{\# example of adding a Bcc:}}
\DoxyCodeLine{116     self.addrcpt(\textcolor{stringliteral}{'<\%s>'} \% \textcolor{stringliteral}{'spy@example.com'})}
\DoxyCodeLine{117     \textcolor{keywordflow}{return} Milter.ACCEPT}
\DoxyCodeLine{118 }
\DoxyCodeLine{119   \textcolor{keyword}{def }close(self):}
\DoxyCodeLine{120     \textcolor{comment}{\# always called, even when abort is called.  Clean up}}
\DoxyCodeLine{121     \textcolor{comment}{\# any external resources here.}}
\DoxyCodeLine{122     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{123 }
\DoxyCodeLine{124   \textcolor{keyword}{def }abort(self):}
\DoxyCodeLine{125     \textcolor{comment}{\# client disconnected prematurely}}
\DoxyCodeLine{126     \textcolor{keywordflow}{return} Milter.CONTINUE}
\DoxyCodeLine{127 }
\DoxyCodeLine{128   }
\DoxyCodeLine{129 }
\DoxyCodeLine{130   \textcolor{keyword}{def }log(self,*msg):}
\DoxyCodeLine{131     logq.put((msg,self.id,time.time()))}
\DoxyCodeLine{132 }
\DoxyCodeLine{133 \textcolor{keyword}{def }background():}
\DoxyCodeLine{134   \textcolor{keywordflow}{while} \textcolor{keyword}{True}:}
\DoxyCodeLine{135     t = logq.get()}
\DoxyCodeLine{136     \textcolor{keywordflow}{if} \textcolor{keywordflow}{not} t: \textcolor{keywordflow}{break}}
\DoxyCodeLine{137     msg,id,ts = t}
\DoxyCodeLine{138     print(\textcolor{stringliteral}{"\%s [\%d]"} \% (time.strftime(\textcolor{stringliteral}{'\%Y\%b\%d \%H:\%M:\%S'},time.localtime(ts)),id),}
\DoxyCodeLine{139         end=\textcolor{keywordtype}{None})}
\DoxyCodeLine{140     \textcolor{comment}{\# 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...}}
\DoxyCodeLine{141     \textcolor{keywordflow}{for} i \textcolor{keywordflow}{in} msg: print(i,end=\textcolor{keywordtype}{None})}
\DoxyCodeLine{142     print()}
\DoxyCodeLine{143     sys.stdout.flush()}
\DoxyCodeLine{144 }
\DoxyCodeLine{145 }
\DoxyCodeLine{146     }
\DoxyCodeLine{147 \textcolor{keyword}{def }main():}
\DoxyCodeLine{148   bt = Thread(target=background)}
\DoxyCodeLine{149   bt.start()}
\DoxyCodeLine{150   socketname = \textcolor{stringliteral}{"/home/stuart/pythonsock"}}
\DoxyCodeLine{151   timeout = 600}
\DoxyCodeLine{152   \textcolor{comment}{\# Register to have the Milter factory create instances of your class:}}
\DoxyCodeLine{153   Milter.factory = myMilter}
\DoxyCodeLine{154   flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS}
\DoxyCodeLine{155   flags += Milter.ADDRCPT}
\DoxyCodeLine{156   flags += Milter.DELRCPT}
\DoxyCodeLine{157   Milter.set\_flags(flags)       \textcolor{comment}{\# tell Sendmail which features we use}}
\DoxyCodeLine{158   print(\textcolor{stringliteral}{"\%s milter startup"} \% time.strftime(\textcolor{stringliteral}{'\%Y\%b\%d \%H:\%M:\%S'}))}
\DoxyCodeLine{159   sys.stdout.flush()}
\DoxyCodeLine{160   Milter.runmilter(\textcolor{stringliteral}{"pythonfilter"},socketname,timeout)}
\DoxyCodeLine{161   logq.put(\textcolor{keywordtype}{None})}
\DoxyCodeLine{162   bt.join()}
\DoxyCodeLine{163   print(\textcolor{stringliteral}{"\%s bms milter shutdown"} \% time.strftime(\textcolor{stringliteral}{'\%Y\%b\%d \%H:\%M:\%S'}))}
\DoxyCodeLine{164 }
\DoxyCodeLine{165 \textcolor{keywordflow}{if} \_\_name\_\_ == \textcolor{stringliteral}{"\_\_main\_\_"}:}
\DoxyCodeLine{166   main()}
\end{DoxyCodeInclude}
 