3 # This module that implements sending mail via QMQP. See
 
   5 #       http://cr.yp.to/proto/qmqp.html
 
   7 # for a description of the protocol.
 
   9 # This module was written by Jaakko Niemi <liiwi@lonesom.pp.fi> for
 
  10 # Enemies of Carlotta. It is licensed the same way as Enemies of Carlotta:
 
  15 class QMQPException(Exception):
 
  16     '''Base class for all exceptions raised by this module.'''
 
  18 class QMQPTemporaryError(QMQPException):
 
  19     '''Class for temporary errors'''
 
  20     def __init__(self, msg):
 
  24         return "QMQP-Server said: %s" % self.msg
 
  26 class QMQPPermanentError(QMQPException):
 
  27     '''Class for permanent errors'''
 
  28     def __init__(self, msg):
 
  32         return "QMQP-Server said: %s" % self.msg
 
  34 class QMQPConnectionError(QMQPException):
 
  35     '''Class for connection errors'''
 
  36     def __init__(self, msg):
 
  40         return "Error was: %s" % self.msg
 
  43     '''I handle qmqp connection to a server'''
 
  47     def __init__(self, host = 'localhost'):
 
  50             resp = self.connect(host)
 
  52     def encode(self, stringi):
 
  53             ret = '%d:%s,' % (len(stringi), stringi) 
 
  56     def decode(self, stringi):
 
  57             stringi = string.split(stringi, ':', 1)
 
  58             stringi[1] = string.rstrip(stringi[1], ',')
 
  59             if len(stringi[1]) is not int(stringi[0]):
 
  60                     print 'malformed netstring encounterd'
 
  63     def connect(self, host = 'localhost'):
 
  64         for sres in socket.getaddrinfo(host, 628, 0, socket.SOCK_STREAM):
 
  65             af, socktype, proto, canonname, sa = sres
 
  67                 self.sock = socket.socket(af, socktype, proto)
 
  70                 print 'connect failed'
 
  80     def send(self, stringi):
 
  83                 self.sock.sendall(stringi)
 
  84             except socket.error, err:
 
  86                 raise QMQPConnectionError, err
 
  92             self.file = self.sock.makefile('rb')
 
  94             line = self.file.readline()
 
  99         line = self.decode(line)
 
 105     def sendmail(self, from_addr, to_addrs, msg):
 
 107             msg = self.encode(msg)
 
 108             from_addr = self.encode(from_addr)
 
 110 # I don't understand why len(to_addrs) <= 1 needs to be handled differently.
 
 111 # Anyway, it doesn't seem to work with Postfix. --liw
 
 112 #           if len(to_addrs) > 1:
 
 114 #                           recipients = recipients + self.encode(t)
 
 116 #                   recipients = self.encode(to_addrs[0])
 
 119                     recipients = recipients + self.encode(t)
 
 120             output = self.encode(msg + from_addr + recipients)
 
 122             ret = self.getreply()
 
 126                     raise QMQPTemporaryError, ret[1:]
 
 128                     raise QMQPPermanentError, ret[1:]
 
 130 if __name__ == '__main__':
 
 132     maili = 'asfasdfsfdasfasd'
 
 133     envelope_sender = 'liw@liw.iki.fi'
 
 134     recips = [ 'liw@liw.iki.fi' ]    
 
 135     retcode = a.sendmail(envelope_sender, recips, maili)