OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.test.test_postfix -*- | |
2 # | |
3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
4 # See LICENSE for details. | |
5 | |
6 # | |
7 | |
8 """Postfix mail transport agent related protocols.""" | |
9 | |
10 import sys | |
11 | |
12 # Twisted imports | |
13 from twisted.protocols import basic | |
14 from twisted.protocols import policies | |
15 from twisted.internet import protocol, defer | |
16 from twisted.python import log | |
17 import UserDict | |
18 import urllib | |
19 | |
20 # urllib's quote functions just happen to match | |
21 # the postfix semantics. | |
22 | |
23 def quote(s): | |
24 return urllib.quote(s) | |
25 | |
26 def unquote(s): | |
27 return urllib.unquote(s) | |
28 | |
29 class PostfixTCPMapServer(basic.LineReceiver, policies.TimeoutMixin): | |
30 """Postfix mail transport agent TCP map protocol implementation. | |
31 | |
32 Receive requests for data matching given key via lineReceived, | |
33 asks it's factory for the data with self.factory.get(key), and | |
34 returns the data to the requester. None means no entry found. | |
35 | |
36 You can use postfix's postmap to test the map service:: | |
37 | |
38 /usr/sbin/postmap -q KEY tcp:localhost:4242 | |
39 | |
40 """ | |
41 | |
42 timeout = 600 | |
43 delimiter = '\n' | |
44 | |
45 def connectionMade(self): | |
46 self.setTimeout(self.timeout) | |
47 | |
48 def sendCode(self, code, message=''): | |
49 "Send an SMTP-like code with a message." | |
50 self.sendLine('%3.3d %s' % (code, message or '')) | |
51 | |
52 def lineReceived(self, line): | |
53 self.resetTimeout() | |
54 try: | |
55 request, params = line.split(None, 1) | |
56 except ValueError: | |
57 request = line | |
58 params = None | |
59 try: | |
60 f = getattr(self, 'do_' + request) | |
61 except AttributeError: | |
62 self.sendCode(400, 'unknown command') | |
63 else: | |
64 try: | |
65 f(params) | |
66 except: | |
67 self.sendCode(400, 'Command %r failed: %s.' % (request, sys.exc_
info()[1])) | |
68 | |
69 def do_get(self, key): | |
70 if key is None: | |
71 self.sendCode(400, 'Command %r takes 1 parameters.' % 'get') | |
72 else: | |
73 d = defer.maybeDeferred(self.factory.get, key) | |
74 d.addCallbacks(self._cbGot, self._cbNot) | |
75 d.addErrback(log.err) | |
76 | |
77 def _cbNot(self, fail): | |
78 self.sendCode(400, fail.getErrorMessage()) | |
79 | |
80 def _cbGot(self, value): | |
81 if value is None: | |
82 self.sendCode(500) | |
83 else: | |
84 self.sendCode(200, quote(value)) | |
85 | |
86 def do_put(self, keyAndValue): | |
87 if keyAndValue is None: | |
88 self.sendCode(400, 'Command %r takes 2 parameters.' % 'put') | |
89 else: | |
90 try: | |
91 key, value = keyAndValue.split(None, 1) | |
92 except ValueError: | |
93 self.sendCode(400, 'Command %r takes 2 parameters.' % 'put') | |
94 else: | |
95 self.sendCode(500, 'put is not implemented yet.') | |
96 | |
97 | |
98 class PostfixTCPMapDictServerFactory(protocol.ServerFactory, | |
99 UserDict.UserDict): | |
100 """An in-memory dictionary factory for PostfixTCPMapServer.""" | |
101 | |
102 protocol = PostfixTCPMapServer | |
103 | |
104 class PostfixTCPMapDeferringDictServerFactory(protocol.ServerFactory): | |
105 """An in-memory dictionary factory for PostfixTCPMapServer.""" | |
106 | |
107 protocol = PostfixTCPMapServer | |
108 | |
109 def __init__(self, data=None): | |
110 self.data = {} | |
111 if data is not None: | |
112 self.data.update(data) | |
113 | |
114 def get(self, key): | |
115 return defer.succeed(self.data.get(key)) | |
116 | |
117 if __name__ == '__main__': | |
118 """Test app for PostfixTCPMapServer. Call with parameters | |
119 KEY1=VAL1 KEY2=VAL2 ...""" | |
120 from twisted.internet import reactor | |
121 log.startLogging(sys.stdout) | |
122 d = {} | |
123 for arg in sys.argv[1:]: | |
124 try: | |
125 k,v = arg.split('=', 1) | |
126 except ValueError: | |
127 k = arg | |
128 v = '' | |
129 d[k]=v | |
130 f=PostfixTCPMapDictServerFactory(d) | |
131 port = reactor.listenTCP(4242, f, interface='127.0.0.1') | |
132 reactor.run() | |
OLD | NEW |