Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v9 / lib / python2.4 / poplib.py
CommitLineData
920dae64
AT
1"""A POP3 client class.
2
3Based on the J. Myers POP3 draft, Jan. 96
4"""
5
6# Author: David Ascher <david_ascher@brown.edu>
7# [heavily stealing from nntplib.py]
8# Updated: Piers Lauder <piers@cs.su.oz.au> [Jul '97]
9# String method conversion and test jig improvements by ESR, February 2001.
10# Added the POP3_SSL class. Methods loosely based on IMAP_SSL. Hector Urtubia <urtubia@mrbook.org> Aug 2003
11
12# Example (see the test function at the end of this file)
13
14# Imports
15
16import re, socket
17
18__all__ = ["POP3","error_proto","POP3_SSL"]
19
20# Exception raised when an error or invalid response is received:
21
22class error_proto(Exception): pass
23
24# Standard Port
25POP3_PORT = 110
26
27# POP SSL PORT
28POP3_SSL_PORT = 995
29
30# Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
31CR = '\r'
32LF = '\n'
33CRLF = CR+LF
34
35
36class POP3:
37
38 """This class supports both the minimal and optional command sets.
39 Arguments can be strings or integers (where appropriate)
40 (e.g.: retr(1) and retr('1') both work equally well.
41
42 Minimal Command Set:
43 USER name user(name)
44 PASS string pass_(string)
45 STAT stat()
46 LIST [msg] list(msg = None)
47 RETR msg retr(msg)
48 DELE msg dele(msg)
49 NOOP noop()
50 RSET rset()
51 QUIT quit()
52
53 Optional Commands (some servers support these):
54 RPOP name rpop(name)
55 APOP name digest apop(name, digest)
56 TOP msg n top(msg, n)
57 UIDL [msg] uidl(msg = None)
58
59 Raises one exception: 'error_proto'.
60
61 Instantiate with:
62 POP3(hostname, port=110)
63
64 NB: the POP protocol locks the mailbox from user
65 authorization until QUIT, so be sure to get in, suck
66 the messages, and quit, each time you access the
67 mailbox.
68
69 POP is a line-based protocol, which means large mail
70 messages consume lots of python cycles reading them
71 line-by-line.
72
73 If it's available on your mail server, use IMAP4
74 instead, it doesn't suffer from the two problems
75 above.
76 """
77
78
79 def __init__(self, host, port = POP3_PORT):
80 self.host = host
81 self.port = port
82 msg = "getaddrinfo returns an empty list"
83 self.sock = None
84 for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
85 af, socktype, proto, canonname, sa = res
86 try:
87 self.sock = socket.socket(af, socktype, proto)
88 self.sock.connect(sa)
89 except socket.error, msg:
90 if self.sock:
91 self.sock.close()
92 self.sock = None
93 continue
94 break
95 if not self.sock:
96 raise socket.error, msg
97 self.file = self.sock.makefile('rb')
98 self._debugging = 0
99 self.welcome = self._getresp()
100
101
102 def _putline(self, line):
103 if self._debugging > 1: print '*put*', repr(line)
104 self.sock.sendall('%s%s' % (line, CRLF))
105
106
107 # Internal: send one command to the server (through _putline())
108
109 def _putcmd(self, line):
110 if self._debugging: print '*cmd*', repr(line)
111 self._putline(line)
112
113
114 # Internal: return one line from the server, stripping CRLF.
115 # This is where all the CPU time of this module is consumed.
116 # Raise error_proto('-ERR EOF') if the connection is closed.
117
118 def _getline(self):
119 line = self.file.readline()
120 if self._debugging > 1: print '*get*', repr(line)
121 if not line: raise error_proto('-ERR EOF')
122 octets = len(line)
123 # server can send any combination of CR & LF
124 # however, 'readline()' returns lines ending in LF
125 # so only possibilities are ...LF, ...CRLF, CR...LF
126 if line[-2:] == CRLF:
127 return line[:-2], octets
128 if line[0] == CR:
129 return line[1:-1], octets
130 return line[:-1], octets
131
132
133 # Internal: get a response from the server.
134 # Raise 'error_proto' if the response doesn't start with '+'.
135
136 def _getresp(self):
137 resp, o = self._getline()
138 if self._debugging > 1: print '*resp*', repr(resp)
139 c = resp[:1]
140 if c != '+':
141 raise error_proto(resp)
142 return resp
143
144
145 # Internal: get a response plus following text from the server.
146
147 def _getlongresp(self):
148 resp = self._getresp()
149 list = []; octets = 0
150 line, o = self._getline()
151 while line != '.':
152 if line[:2] == '..':
153 o = o-1
154 line = line[1:]
155 octets = octets + o
156 list.append(line)
157 line, o = self._getline()
158 return resp, list, octets
159
160
161 # Internal: send a command and get the response
162
163 def _shortcmd(self, line):
164 self._putcmd(line)
165 return self._getresp()
166
167
168 # Internal: send a command and get the response plus following text
169
170 def _longcmd(self, line):
171 self._putcmd(line)
172 return self._getlongresp()
173
174
175 # These can be useful:
176
177 def getwelcome(self):
178 return self.welcome
179
180
181 def set_debuglevel(self, level):
182 self._debugging = level
183
184
185 # Here are all the POP commands:
186
187 def user(self, user):
188 """Send user name, return response
189
190 (should indicate password required).
191 """
192 return self._shortcmd('USER %s' % user)
193
194
195 def pass_(self, pswd):
196 """Send password, return response
197
198 (response includes message count, mailbox size).
199
200 NB: mailbox is locked by server from here to 'quit()'
201 """
202 return self._shortcmd('PASS %s' % pswd)
203
204
205 def stat(self):
206 """Get mailbox status.
207
208 Result is tuple of 2 ints (message count, mailbox size)
209 """
210 retval = self._shortcmd('STAT')
211 rets = retval.split()
212 if self._debugging: print '*stat*', repr(rets)
213 numMessages = int(rets[1])
214 sizeMessages = int(rets[2])
215 return (numMessages, sizeMessages)
216
217
218 def list(self, which=None):
219 """Request listing, return result.
220
221 Result without a message number argument is in form
222 ['response', ['mesg_num octets', ...], octets].
223
224 Result when a message number argument is given is a
225 single response: the "scan listing" for that message.
226 """
227 if which is not None:
228 return self._shortcmd('LIST %s' % which)
229 return self._longcmd('LIST')
230
231
232 def retr(self, which):
233 """Retrieve whole message number 'which'.
234
235 Result is in form ['response', ['line', ...], octets].
236 """
237 return self._longcmd('RETR %s' % which)
238
239
240 def dele(self, which):
241 """Delete message number 'which'.
242
243 Result is 'response'.
244 """
245 return self._shortcmd('DELE %s' % which)
246
247
248 def noop(self):
249 """Does nothing.
250
251 One supposes the response indicates the server is alive.
252 """
253 return self._shortcmd('NOOP')
254
255
256 def rset(self):
257 """Not sure what this does."""
258 return self._shortcmd('RSET')
259
260
261 def quit(self):
262 """Signoff: commit changes on server, unlock mailbox, close connection."""
263 try:
264 resp = self._shortcmd('QUIT')
265 except error_proto, val:
266 resp = val
267 self.file.close()
268 self.sock.close()
269 del self.file, self.sock
270 return resp
271
272 #__del__ = quit
273
274
275 # optional commands:
276
277 def rpop(self, user):
278 """Not sure what this does."""
279 return self._shortcmd('RPOP %s' % user)
280
281
282 timestamp = re.compile(r'\+OK.*(<[^>]+>)')
283
284 def apop(self, user, secret):
285 """Authorisation
286
287 - only possible if server has supplied a timestamp in initial greeting.
288
289 Args:
290 user - mailbox user;
291 secret - secret shared between client and server.
292
293 NB: mailbox is locked by server from here to 'quit()'
294 """
295 m = self.timestamp.match(self.welcome)
296 if not m:
297 raise error_proto('-ERR APOP not supported by server')
298 import md5
299 digest = md5.new(m.group(1)+secret).digest()
300 digest = ''.join(map(lambda x:'%02x'%ord(x), digest))
301 return self._shortcmd('APOP %s %s' % (user, digest))
302
303
304 def top(self, which, howmuch):
305 """Retrieve message header of message number 'which'
306 and first 'howmuch' lines of message body.
307
308 Result is in form ['response', ['line', ...], octets].
309 """
310 return self._longcmd('TOP %s %s' % (which, howmuch))
311
312
313 def uidl(self, which=None):
314 """Return message digest (unique id) list.
315
316 If 'which', result contains unique id for that message
317 in the form 'response mesgnum uid', otherwise result is
318 the list ['response', ['mesgnum uid', ...], octets]
319 """
320 if which is not None:
321 return self._shortcmd('UIDL %s' % which)
322 return self._longcmd('UIDL')
323
324class POP3_SSL(POP3):
325 """POP3 client class over SSL connection
326
327 Instantiate with: POP3_SSL(hostname, port=995, keyfile=None, certfile=None)
328
329 hostname - the hostname of the pop3 over ssl server
330 port - port number
331 keyfile - PEM formatted file that countains your private key
332 certfile - PEM formatted certificate chain file
333
334 See the methods of the parent class POP3 for more documentation.
335 """
336
337 def __init__(self, host, port = POP3_SSL_PORT, keyfile = None, certfile = None):
338 self.host = host
339 self.port = port
340 self.keyfile = keyfile
341 self.certfile = certfile
342 self.buffer = ""
343 msg = "getaddrinfo returns an empty list"
344 self.sock = None
345 for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
346 af, socktype, proto, canonname, sa = res
347 try:
348 self.sock = socket.socket(af, socktype, proto)
349 self.sock.connect(sa)
350 except socket.error, msg:
351 if self.sock:
352 self.sock.close()
353 self.sock = None
354 continue
355 break
356 if not self.sock:
357 raise socket.error, msg
358 self.file = self.sock.makefile('rb')
359 self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
360 self._debugging = 0
361 self.welcome = self._getresp()
362
363 def _fillBuffer(self):
364 localbuf = self.sslobj.read()
365 if len(localbuf) == 0:
366 raise error_proto('-ERR EOF')
367 self.buffer += localbuf
368
369 def _getline(self):
370 line = ""
371 renewline = re.compile(r'.*?\n')
372 match = renewline.match(self.buffer)
373 while not match:
374 self._fillBuffer()
375 match = renewline.match(self.buffer)
376 line = match.group(0)
377 self.buffer = renewline.sub('' ,self.buffer, 1)
378 if self._debugging > 1: print '*get*', repr(line)
379
380 octets = len(line)
381 if line[-2:] == CRLF:
382 return line[:-2], octets
383 if line[0] == CR:
384 return line[1:-1], octets
385 return line[:-1], octets
386
387 def _putline(self, line):
388 if self._debugging > 1: print '*put*', repr(line)
389 line += CRLF
390 bytes = len(line)
391 while bytes > 0:
392 sent = self.sslobj.write(line)
393 if sent == bytes:
394 break # avoid copy
395 line = line[sent:]
396 bytes = bytes - sent
397
398 def quit(self):
399 """Signoff: commit changes on server, unlock mailbox, close connection."""
400 try:
401 resp = self._shortcmd('QUIT')
402 except error_proto, val:
403 resp = val
404 self.sock.close()
405 del self.sslobj, self.sock
406 return resp
407
408
409if __name__ == "__main__":
410 import sys
411 a = POP3(sys.argv[1])
412 print a.getwelcome()
413 a.user(sys.argv[2])
414 a.pass_(sys.argv[3])
415 a.list()
416 (numMsgs, totalSize) = a.stat()
417 for i in range(1, numMsgs + 1):
418 (header, msg, octets) = a.retr(i)
419 print "Message %d:" % i
420 for line in msg:
421 print ' ' + line
422 print '-----------------------'
423 a.quit()