def __init__(self, socket, config): PpyMilter.__init__(self) self.socket = socket self.config = config self.CanAddHeaders() self.CanChangeBody() self.CanChangeHeaders() self.logger = logging.getLogger('fuglu.miltersession') self.__milter_dispatcher = PpyMilterDispatcher(self) self.recipients = [] self.from_address = None (handle, tempfilename) = tempfile.mkstemp(prefix='fuglu', dir=self.config.get( 'main', 'tempdir')) self.tempfilename = tempfilename self.tempfile = os.fdopen(handle, 'w+b') self.currentmilterdata = None self.answer = self.Continue() self.helo = None self.ip = None self.rdns = None
class MilterSession(PpyMilter): def __init__(self, socket, config): PpyMilter.__init__(self) self.socket = socket self.config = config self.CanAddHeaders() self.CanChangeBody() self.CanChangeHeaders() self.logger = logging.getLogger('fuglu.miltersession') self.__milter_dispatcher = PpyMilterDispatcher(self) self.recipients = [] self.from_address = None (handle, tempfilename) = tempfile.mkstemp(prefix='fuglu', dir=self.config.get( 'main', 'tempdir')) self.tempfilename = tempfilename self.tempfile = os.fdopen(handle, 'w+b') self.currentmilterdata = None self.answer = self.Continue() self.helo = None self.ip = None self.rdns = None def OnConnect(self, cmd, hostname, family, port, address): if family not in ('4', '6'): # we don't handle unix socket return self.Continue() if hostname is None or hostname == '[%s]' % address: hostname = 'unknown' self.rdns = hostname self.addr = address return self.Continue() def OnHelo(self, cmd, helo): self.helo = helo return self.Continue() def OnRcptTo(self, cmd, rcpt_to, esmtp_info): self.recipients.append(rcpt_to) return self.Continue() def OnMailFrom(self, cmd, mail_from, args): self.from_address = mail_from return self.Continue() def OnHeader(self, cmd, header, value): self.tempfile.write("%s: %s\n" % (header, value)) return self.Continue() def OnEndHeaders(self, cmd): self.tempfile.write("\n") return self.Continue() def OnBody(self, cmd, data): self.tempfile.write(data) return self.Continue() def OnEndBody(self, cmd): return self.answer def OnResetState(self): self.recipients = None self.tempfile = None self.tempfilename = None def _read_milter_command(self): lenbuf = [] lenread = 0 while lenread < MILTER_LEN_BYTES: pdat = self.socket.recv(MILTER_LEN_BYTES - lenread) lenbuf.append(pdat) lenread += len(pdat) dat = b"".join(lenbuf) # self.logger.info(dat) # self.logger.info(len(dat)) packetlen = int(struct.unpack('!I', dat)[0]) inbuf = [] read = 0 while read < packetlen: partial_data = self.socket.recv(packetlen - read) inbuf.append(partial_data) read += len(partial_data) data = b"".join(inbuf) return data def finish(self): """we assume to be at SMFIC_BODYEOB""" try: while True: if self.currentmilterdata != None: data = self.currentmilterdata self.currentmilterdata = None else: data = self._read_milter_command() try: response = self.__milter_dispatcher.Dispatch(data) if type(response) == list: for r in response: self.__send_response(r) elif response: self.__send_response(response) except PpyMilterCloseConnection as e: #logging.info('Closing connection ("%s")', str(e)) break except Exception as e: # TODO: here we get broken pipe if we're not using self.Continue(), but the milter client seems happy # so, silently discarding this exception for now pass def getincomingmail(self): try: while True: data = self._read_milter_command() self.currentmilterdata = data (cmd, args) = (data[0], data[1:]) if cmd == SMFIC_BODYEOB: self.tempfile.close() return True try: response = self.__milter_dispatcher.Dispatch(data) if type(response) == list: for r in response: self.__send_response(r) elif response: self.__send_response(response) except PpyMilterCloseConnection as e: #logging.info('Closing connection ("%s")', str(e)) break except Exception as e: exc = traceback.format_exc() self.logger.error('Exception in MilterSession: %s %s' % (e, exc)) return False return False def __send_response(self, response): """Send data down the milter socket. Args: response: the data to send """ self.socket.send(struct.pack('!I', len(response))) self.socket.send(force_bString(response))