summaryrefslogtreecommitdiff
path: root/qmqp.py
blob: bc5d194e99ef6d6dc9b43cbced0e170a022f783d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/python

# This module that implements sending mail via QMQP. See
#
#   	http://cr.yp.to/proto/qmqp.html
#
# for a description of the protocol.
#
# This module was written by Jaakko Niemi <liiwi@lonesom.pp.fi> for
# Enemies of Carlotta. It is licensed the same way as Enemies of Carlotta:
# GPL version 2.

import socket, string

class QMQPException(Exception):
    '''Base class for all exceptions raised by this module.'''

class QMQPTemporaryError(QMQPException):
    '''Class for temporary errors'''
    def __init__(self, msg):
        self.msg = msg
        
    def __str__(self):
        return "QMQP-Server said: %s" % self.msg
        
class QMQPPermanentError(QMQPException):
    '''Class for permanent errors'''
    def __init__(self, msg):
        self.msg = msg
        
    def __str__(self):
        return "QMQP-Server said: %s" % self.msg

class QMQPConnectionError(QMQPException):
    '''Class for connection errors'''
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return "Error was: %s" % self.msg

class QMQP:
    '''I handle qmqp connection to a server'''

    file = None

    def __init__(self, host = 'localhost'):
        '''Start'''
        if host:
            resp = self.connect(host)

    def encode(self, stringi):
	    ret = '%d:%s,' % (len(stringi), stringi) 
	    return ret

    def decode(self, stringi):
	    stringi = string.split(stringi, ':', 1)
	    stringi[1] = string.rstrip(stringi[1], ',')
	    if len(stringi[1]) is not int(stringi[0]):
		    print 'malformed netstring encounterd'
 	    return stringi[1]

    def connect(self, host = 'localhost'):
        for sres in socket.getaddrinfo(host, 628, 0, socket.SOCK_STREAM):
            af, socktype, proto, canonname, sa = sres
            try:
                self.sock = socket.socket(af, socktype, proto)
                self.sock.connect(sa)
            except socket.error:
                print 'connect failed'
                if self.sock:
                    self.sock.close()
                self.sock = None
                continue
            break
        if not self.sock:
            raise socket.error
        return 0
        
    def send(self, stringi):
        if self.sock:
            try:
                self.sock.sendall(stringi)
            except socket.error, err:
                self.sock.close()
                raise QMQPConnectionError, err
        else:
            print 'not connected'

    def getreply(self):
        if self.file is None:
            self.file = self.sock.makefile('rb')
        while 1:
            line = self.file.readline()
            if line == '':
                self.sock.close()
                print 'ERORORR'
	    break
        line = self.decode(line)
        return line

    def quit(self):
        self.sock.close()

    def sendmail(self, from_addr, to_addrs, msg):
	    recipients = ''
	    msg = self.encode(msg)
	    from_addr = self.encode(from_addr)

# I don't understand why len(to_addrs) <= 1 needs to be handled differently.
# Anyway, it doesn't seem to work with Postfix. --liw
#	    if len(to_addrs) > 1:
#		    for t in to_addrs:
#			    recipients = recipients + self.encode(t)
#	    else:
#		    recipients = self.encode(to_addrs[0])

	    for t in to_addrs:
		    recipients = recipients + self.encode(t)
	    output = self.encode(msg + from_addr + recipients)
	    self.send(output)
	    ret = self.getreply()
	    if ret[0] == 'K':
		    return ret[1:]
	    if ret[0] == 'Z':
		    raise QMQPTemporaryError, ret[1:]
	    if ret[0] == 'D':
		    raise QMQPPermanentError, ret[1:]

if __name__ == '__main__':
    a = QMQP()
    maili = 'asfasdfsfdasfasd'
    envelope_sender = 'liw@liw.iki.fi'
    recips = [ 'liw@liw.iki.fi' ]    
    retcode = a.sendmail(envelope_sender, recips, maili)
    print retcode
    a.quit()