"Fossies" - the Fresh Open Source Software Archive 
Member "getmail-5.16/getmailcore/retrievers.py" (31 Oct 2021, 23086 Bytes) of package /linux/misc/getmail-5.16.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "retrievers.py" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
5.15_vs_5.16.
1 #!/usr/bin/env python2
2 '''Classes implementing retrievers (message sources getmail can retrieve mail
3 from).
4
5 Currently implemented:
6
7 SimplePOP3Retriever
8 SimplePOP3SSLRetriever
9 BrokenUIDLPOP3Retriever
10 BrokenUIDLPOP3SSLRetriever
11 MultidropPOP3Retriever
12 MultidropPOP3SSLRetriever
13 MultidropSDPSRetriever
14 SimpleIMAPRetriever -- IMAP, as a protocol, is a FPOS, and it shows.
15 The Python standard library module imaplib leaves much up to
16 the user because of this.
17 SimpleIMAPSSLRetriever - the above, for IMAP-over-SSL.
18 MultidropIMAPRetriever
19 MultidropIMAPSSLRetriever
20 '''
21
22 __all__ = [
23 'SimplePOP3Retriever',
24 'SimplePOP3SSLRetriever',
25 'BrokenUIDLPOP3Retriever',
26 'BrokenUIDLPOP3SSLRetriever',
27 'MultidropPOP3Retriever',
28 'MultidropPOP3SSLRetriever',
29 'MultidropSDPSRetriever',
30 'SimpleIMAPRetriever',
31 'SimpleIMAPSSLRetriever',
32 'MultidropIMAPRetriever',
33 'MultidropIMAPSSLRetriever',
34 ]
35
36 import os
37 import poplib
38 import imaplib
39 import types
40
41 from getmailcore.exceptions import *
42 from getmailcore.constants import *
43 from getmailcore.utilities import *
44 from getmailcore.baseclasses import *
45 from getmailcore._retrieverbases import *
46
47
48 #
49 # Functional classes
50 #
51
52 #######################################
53 class SimplePOP3Retriever(POP3RetrieverBase, POP3initMixIn):
54 '''Retriever class for single-user POP3 mailboxes.
55 '''
56 _confitems = (
57 ConfInstance(name='configparser', required=False),
58 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
59
60 ConfInt(name='timeout', required=False, default=180),
61 ConfString(name='server'),
62 ConfInt(name='port', required=False, default=110),
63 ConfString(name='username'),
64 ConfPassword(name='password', required=False, default=None),
65 ConfTupleOfStrings(name='password_command', required=False, default=()),
66 ConfBool(name='use_apop', required=False, default=False),
67 ConfBool(name='delete_dup_msgids', required=False, default=False),
68 )
69 received_from = None
70 received_with = 'POP3'
71 received_by = localhostname()
72
73 def __str__(self):
74 self.log.trace()
75 return 'SimplePOP3Retriever:%s@%s:%s' % (
76 self.conf.get('username', 'username'),
77 self.conf.get('server', 'server'),
78 self.conf.get('port', 'port')
79 )
80
81 def showconf(self):
82 self.log.trace()
83 self.log.info('SimplePOP3Retriever(%s)' % self._confstring()
84 + os.linesep)
85
86 #######################################
87 class SimplePOP3SSLRetriever(POP3RetrieverBase, POP3SSLinitMixIn):
88 '''Retriever class for single-user POP3-over-SSL mailboxes.
89 '''
90 _confitems = (
91 ConfInstance(name='configparser', required=False),
92 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
93
94 ConfInt(name='timeout', required=False, default=180),
95 ConfString(name='server'),
96 ConfInt(name='port', required=False, default=POP3_ssl_port),
97 ConfString(name='username'),
98 ConfPassword(name='password', required=False, default=None),
99 ConfTupleOfStrings(name='password_command', required=False, default=()),
100 ConfBool(name='use_apop', required=False, default=False),
101 ConfBool(name='delete_dup_msgids', required=False, default=False),
102 ConfFile(name='keyfile', required=False, default=None),
103 ConfFile(name='certfile', required=False, default=None),
104 ConfFile(name='ca_certs', required=False, default=None),
105 ConfTupleOfStrings(name='ssl_fingerprints', required=False, default=()),
106 ConfString(name='ssl_version', required=False, default=None),
107 ConfString(name='ssl_ciphers', required=False, default=None),
108 ConfString(name='ssl_cert_hostname', required=False, default=None),
109 )
110 received_from = None
111 received_with = 'POP3-SSL'
112 received_by = localhostname()
113
114 def __str__(self):
115 self.log.trace()
116 return 'SimplePOP3SSLRetriever:%s@%s:%s' % (
117 self.conf.get('username', 'username'),
118 self.conf.get('server', 'server'),
119 self.conf.get('port', 'port')
120 )
121
122 def showconf(self):
123 self.log.trace()
124 self.log.info('SimplePOP3SSLRetriever(%s)' % self._confstring()
125 + os.linesep)
126
127 #######################################
128 class BrokenUIDLPOP3RetrieverBase(POP3RetrieverBase):
129 '''Retriever base class for single-user POP3 mailboxes on servers that do
130 not properly assign unique IDs to messages. Since with these broken servers
131 we cannot rely on UIDL, we have to use message numbers, which are unique
132 within a POP3 session, but which change across sessions. This class
133 therefore can not be used to leave old mail on the server and download only
134 new mail.
135 '''
136 received_from = None
137 received_by = localhostname()
138
139 def _read_oldmailfile(self):
140 '''Force list of old messages to be empty by making this a no-op, so
141 duplicated IDs are always treated as new messages.'''
142 self.log.trace()
143
144 def write_oldmailfile(self, unused, **kwargs):
145 '''Short-circuit writing the oldmail file.'''
146 self.log.trace()
147
148 def _getmsglist(self):
149 '''Don't rely on UIDL; instead, use just the message number.'''
150 self.log.trace()
151 try:
152 (response, msglist, octets) = self.conn.list()
153 for line in msglist:
154 msgnum = int(line.split()[0])
155 msgsize = int(line.split()[1])
156 self.msgnum_by_msgid[msgnum] = msgnum
157 self.msgid_by_msgnum[msgnum] = msgnum
158 self.msgsizes[msgnum] = msgsize
159 self.sorted_msgnum_msgid = sorted(self.msgid_by_msgnum.items())
160 except poplib.error_proto, o:
161 raise getmailOperationError('POP error (%s)' % o)
162 self.gotmsglist = True
163
164 #######################################
165 class BrokenUIDLPOP3Retriever(BrokenUIDLPOP3RetrieverBase, POP3initMixIn):
166 '''For broken POP3 servers without SSL.
167 '''
168 _confitems = (
169 ConfInstance(name='configparser', required=False),
170 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
171
172 ConfInt(name='timeout', required=False, default=180),
173 ConfString(name='server'),
174 ConfInt(name='port', required=False, default=110),
175 ConfString(name='username'),
176 ConfPassword(name='password', required=False, default=None),
177 ConfTupleOfStrings(name='password_command', required=False, default=()),
178 ConfBool(name='use_apop', required=False, default=False),
179 )
180 received_with = 'POP3'
181
182 def __str__(self):
183 self.log.trace()
184 return 'BrokenUIDLPOP3Retriever:%s@%s:%s' % (
185 self.conf.get('username', 'username'),
186 self.conf.get('server', 'server'),
187 self.conf.get('port', 'port')
188 )
189
190 def showconf(self):
191 self.log.trace()
192 self.log.info('BrokenUIDLPOP3Retriever(%s)' % self._confstring()
193 + os.linesep)
194
195 #######################################
196 class BrokenUIDLPOP3SSLRetriever(BrokenUIDLPOP3RetrieverBase, POP3SSLinitMixIn):
197 '''For broken POP3 servers with SSL.
198 '''
199 _confitems = (
200 ConfInstance(name='configparser', required=False),
201 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
202
203 ConfInt(name='timeout', required=False, default=180),
204 ConfString(name='server'),
205 ConfInt(name='port', required=False, default=POP3_ssl_port),
206 ConfString(name='username'),
207 ConfPassword(name='password', required=False, default=None),
208 ConfTupleOfStrings(name='password_command', required=False, default=()),
209 ConfBool(name='use_apop', required=False, default=False),
210 ConfFile(name='keyfile', required=False, default=None),
211 ConfFile(name='certfile', required=False, default=None),
212 ConfFile(name='ca_certs', required=False, default=None),
213 ConfTupleOfStrings(name='ssl_fingerprints', required=False, default=()),
214 ConfString(name='ssl_version', required=False, default=None),
215 ConfString(name='ssl_ciphers', required=False, default=None),
216 ConfString(name='ssl_cert_hostname', required=False, default=None),
217 )
218 received_with = 'POP3-SSL'
219
220 def __str__(self):
221 self.log.trace()
222 return 'BrokenUIDLPOP3SSLRetriever:%s@%s:%s' % (
223 self.conf.get('username', 'username'),
224 self.conf.get('server', 'server'),
225 self.conf.get('port', 'port')
226 )
227
228 def showconf(self):
229 self.log.trace()
230 self.log.info('BrokenUIDLPOP3SSLRetriever(%s)' % self._confstring()
231 + os.linesep)
232
233 #######################################
234 class MultidropPOP3Retriever(MultidropPOP3RetrieverBase, POP3initMixIn):
235 '''Retriever class for multi-drop POP3 mailboxes.
236 '''
237 _confitems = (
238 ConfInstance(name='configparser', required=False),
239 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
240
241 ConfInt(name='timeout', required=False, default=180),
242 ConfString(name='server'),
243 ConfInt(name='port', required=False, default=110),
244 ConfString(name='username'),
245 ConfPassword(name='password', required=False, default=None),
246 ConfTupleOfStrings(name='password_command', required=False, default=()),
247 ConfBool(name='use_apop', required=False, default=False),
248 ConfString(name='envelope_recipient'),
249 )
250 received_from = None
251 received_with = 'POP3'
252 received_by = localhostname()
253
254 def __str__(self):
255 self.log.trace()
256 return 'MultidropPOP3Retriever:%s@%s:%s' % (
257 self.conf.get('username', 'username'),
258 self.conf.get('server', 'server'),
259 self.conf.get('port', 'port')
260 )
261
262 def showconf(self):
263 self.log.trace()
264 self.log.info('MultidropPOP3Retriever(%s)' % self._confstring()
265 + os.linesep)
266
267 #######################################
268 class MultidropPOP3SSLRetriever(MultidropPOP3RetrieverBase, POP3SSLinitMixIn):
269 '''Retriever class for multi-drop POP3-over-SSL mailboxes.
270 '''
271 _confitems = (
272 ConfInstance(name='configparser', required=False),
273 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
274
275 ConfInt(name='timeout', required=False, default=180),
276 ConfString(name='server'),
277 ConfInt(name='port', required=False, default=POP3_ssl_port),
278 ConfString(name='username'),
279 ConfPassword(name='password', required=False, default=None),
280 ConfTupleOfStrings(name='password_command', required=False, default=()),
281 ConfBool(name='use_apop', required=False, default=False),
282 ConfString(name='envelope_recipient'),
283 ConfFile(name='keyfile', required=False, default=None),
284 ConfFile(name='certfile', required=False, default=None),
285 ConfFile(name='ca_certs', required=False, default=None),
286 ConfTupleOfStrings(name='ssl_fingerprints', required=False, default=()),
287 ConfString(name='ssl_version', required=False, default=None),
288 ConfString(name='ssl_ciphers', required=False, default=None),
289 ConfString(name='ssl_cert_hostname', required=False, default=None),
290 )
291 received_from = None
292 received_with = 'POP3-SSL'
293 received_by = localhostname()
294
295 def __str__(self):
296 self.log.trace()
297 return 'MultidropPOP3SSLRetriever:%s@%s:%s' % (
298 self.conf.get('username', 'username'),
299 self.conf.get('server', 'server'),
300 self.conf.get('port', 'port')
301 )
302
303 def showconf(self):
304 self.log.trace()
305 self.log.info('MultidropPOP3SSLRetriever(%s)' % self._confstring()
306 + os.linesep)
307
308 #######################################
309 class MultidropSDPSRetriever(SimplePOP3Retriever, POP3initMixIn):
310 '''Retriever class for multi-drop SDPS (demon.co.uk) mailboxes.
311
312 Extend POP3 class to include support for Demon's protocol extensions, known
313 as SDPS. A non-standard command (*ENV) is used to retrieve the message
314 envelope. See http://www.demon.net/helpdesk/products/mail/sdps-tech.shtml
315 for details.
316
317 Support originally requested by Paul Clifford for getmail v.2/3.
318 '''
319 _confitems = (
320 ConfInstance(name='configparser', required=False),
321 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
322
323 ConfInt(name='timeout', required=False, default=180),
324 ConfString(name='server'),
325 ConfInt(name='port', required=False, default=110),
326 ConfString(name='username'),
327 ConfPassword(name='password', required=False, default=None),
328 ConfTupleOfStrings(name='password_command', required=False, default=()),
329 # Demon apparently doesn't support APOP
330 ConfBool(name='use_apop', required=False, default=False),
331 )
332
333 received_from = None
334 received_with = 'SDPS'
335 received_by = localhostname()
336
337 def __str__(self):
338 self.log.trace()
339 return 'MultidropSDPSRetriever:%s@%s:%s' % (
340 self.conf.get('username', 'username'),
341 self.conf.get('server', 'server'),
342 self.conf.get('port', 'port')
343 )
344
345 def showconf(self):
346 self.log.trace()
347 self.log.info('MultidropSDPSRetriever(%s)' % self._confstring()
348 + os.linesep)
349
350 def _getmsgbyid(self, msgid):
351 self.log.trace()
352 msg = SimplePOP3Retriever._getmsgbyid(self, msgid)
353
354 # The magic of SDPS is the "*ENV" command. Implement it:
355 try:
356 msgnum = self._getmsgnumbyid(msgid)
357 resp, lines, octets = self.conn._longcmd('*ENV %i' % msgnum)
358 except poplib.error_proto, o:
359 raise getmailConfigurationError(
360 'server does not support *ENV (%s)' % o
361 )
362 if len(lines) < 4:
363 raise getmailOperationError('short *ENV response (%s)' % lines)
364 msg.sender = lines[2]
365 msg.recipient = lines[3]
366 return msg
367
368 #######################################
369 class SimpleIMAPRetriever(IMAPRetrieverBase, IMAPinitMixIn):
370 '''Retriever class for single-user IMAPv4 mailboxes.
371 '''
372 _confitems = (
373 ConfInstance(name='configparser', required=False),
374 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
375
376 ConfInt(name='timeout', required=False, default=180),
377 ConfString(name='server'),
378 ConfInt(name='port', required=False, default=imaplib.IMAP4_PORT),
379 ConfString(name='username'),
380 ConfPassword(name='password', required=False, default=None),
381 ConfTupleOfStrings(name='password_command', required=False, default=()),
382 ConfTupleOfUnicode(name='mailboxes', required=False,
383 default="('INBOX', )", allow_specials=('ALL',)),
384 ConfBool(name='use_peek', required=False, default=True),
385 ConfString(name='move_on_delete', required=False, default=None),
386 ConfBool(name='record_mailbox', required=False, default=True),
387 # imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
388 # .authenticate(), so we can't do this yet (?).
389 ConfBool(name='use_cram_md5', required=False, default=False),
390 ConfBool(name='use_kerberos', required=False, default=False),
391 ConfBool(name='use_xoauth2', required=False, default=False),
392 )
393 received_from = None
394 received_with = 'IMAP4'
395 received_by = localhostname()
396
397 def __str__(self):
398 self.log.trace()
399 return 'SimpleIMAPRetriever:%s@%s:%s' % (
400 self.conf.get('username', 'username'),
401 self.conf.get('server', 'server'),
402 self.conf.get('port', 'port')
403 )
404
405 def showconf(self):
406 self.log.trace()
407 self.log.info('SimpleIMAPRetriever(%s)' % self._confstring()
408 + os.linesep)
409
410 #######################################
411 class SimpleIMAPSSLRetriever(IMAPRetrieverBase, IMAPSSLinitMixIn):
412 '''Retriever class for single-user IMAPv4-over-SSL mailboxes.
413 '''
414 _confitems = (
415 ConfInstance(name='configparser', required=False),
416 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
417
418 # socket.ssl() and socket timeouts were incompatible in Python 2.3;
419 # if you have problems, comment this line out
420 ConfInt(name='timeout', required=False, default=180),
421 ConfString(name='server'),
422 ConfInt(name='port', required=False, default=imaplib.IMAP4_SSL_PORT),
423 ConfString(name='username'),
424 ConfPassword(name='password', required=False, default=None),
425 ConfTupleOfStrings(name='password_command', required=False, default=()),
426 ConfTupleOfUnicode(name='mailboxes', required=False,
427 default="('INBOX', )", allow_specials=('ALL',)),
428 ConfBool(name='use_peek', required=False, default=True),
429 ConfString(name='move_on_delete', required=False, default=None),
430 ConfBool(name='record_mailbox', required=False, default=True),
431 ConfFile(name='keyfile', required=False, default=None),
432 ConfFile(name='certfile', required=False, default=None),
433 ConfFile(name='ca_certs', required=False, default=None),
434 ConfTupleOfStrings(name='ssl_fingerprints', required=False, default=()),
435 ConfString(name='ssl_version', required=False, default=None),
436 ConfString(name='ssl_ciphers', required=False, default=None),
437 # imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
438 # .authenticate(), so we can't do this yet (?).
439 ConfBool(name='use_cram_md5', required=False, default=False),
440 ConfBool(name='use_kerberos', required=False, default=False),
441 ConfBool(name='use_xoauth2', required=False, default=False),
442 ConfString(name='ssl_cert_hostname', required=False, default=None),
443 )
444 received_from = None
445 received_with = 'IMAP4-SSL'
446 received_by = localhostname()
447
448 def __str__(self):
449 self.log.trace()
450 return 'SimpleIMAPSSLRetriever:%s@%s:%s' % (
451 self.conf.get('username', 'username'),
452 self.conf.get('server', 'server'),
453 self.conf.get('port', 'port')
454 )
455
456 def showconf(self):
457 self.log.trace()
458 self.log.info('SimpleIMAPSSLRetriever(%s)' % self._confstring()
459 + os.linesep)
460
461 #######################################
462 class MultidropIMAPRetriever(MultidropIMAPRetrieverBase, IMAPinitMixIn):
463 '''Retriever class for multi-drop IMAPv4 mailboxes.
464 '''
465 _confitems = (
466 ConfInstance(name='configparser', required=False),
467 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
468
469 ConfInt(name='timeout', required=False, default=180),
470 ConfString(name='server'),
471 ConfInt(name='port', required=False, default=imaplib.IMAP4_PORT),
472 ConfString(name='username'),
473 ConfPassword(name='password', required=False, default=None),
474 ConfTupleOfStrings(name='password_command', required=False, default=()),
475 ConfTupleOfUnicode(name='mailboxes', required=False,
476 default="('INBOX', )", allow_specials=('ALL',)),
477 ConfBool(name='use_peek', required=False, default=True),
478 ConfString(name='move_on_delete', required=False, default=None),
479 ConfBool(name='record_mailbox', required=False, default=True),
480 # imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
481 # .authenticate(), so we can't do this yet (?).
482 ConfBool(name='use_cram_md5', required=False, default=False),
483 ConfBool(name='use_kerberos', required=False, default=False),
484 ConfBool(name='use_xoauth2', required=False, default=False),
485 ConfString(name='envelope_recipient'),
486 )
487 received_from = None
488 received_with = 'IMAP4'
489 received_by = localhostname()
490
491 def __str__(self):
492 self.log.trace()
493 return 'MultidropIMAPRetriever:%s@%s:%s' % (
494 self.conf.get('username', 'username'),
495 self.conf.get('server', 'server'),
496 self.conf.get('port', 'port')
497 )
498
499 def showconf(self):
500 self.log.trace()
501 self.log.info('MultidropIMAPRetriever(%s)' % self._confstring()
502 + os.linesep)
503
504 #######################################
505 class MultidropIMAPSSLRetriever(MultidropIMAPRetrieverBase, IMAPSSLinitMixIn):
506 '''Retriever class for multi-drop IMAPv4-over-SSL mailboxes.
507 '''
508 _confitems = (
509 ConfInstance(name='configparser', required=False),
510 ConfDirectory(name='getmaildir', required=False, default='~/.getmail/'),
511
512 # socket.ssl() and socket timeouts were incompatible in Python 2.3;
513 # if you have problems, comment this line out
514 ConfInt(name='timeout', required=False, default=180),
515 ConfString(name='server'),
516 ConfInt(name='port', required=False, default=imaplib.IMAP4_SSL_PORT),
517 ConfString(name='username'),
518 ConfPassword(name='password', required=False, default=None),
519 ConfTupleOfStrings(name='password_command', required=False, default=()),
520 ConfTupleOfUnicode(name='mailboxes', required=False,
521 default="('INBOX', )", allow_specials=('ALL',)),
522 ConfBool(name='use_peek', required=False, default=True),
523 ConfString(name='move_on_delete', required=False, default=None),
524 ConfBool(name='record_mailbox', required=False, default=True),
525 ConfFile(name='keyfile', required=False, default=None),
526 ConfFile(name='certfile', required=False, default=None),
527 ConfFile(name='ca_certs', required=False, default=None),
528 ConfTupleOfStrings(name='ssl_fingerprints', required=False, default=()),
529 ConfString(name='ssl_version', required=False, default=None),
530 ConfString(name='ssl_ciphers', required=False, default=None),
531 # imaplib.IMAP4.login_cram_md5() requires the (unimplemented)
532 # .authenticate(), so we can't do this yet (?).
533 ConfBool(name='use_cram_md5', required=False, default=False),
534 ConfBool(name='use_kerberos', required=False, default=False),
535 ConfBool(name='use_xoauth2', required=False, default=False),
536 ConfString(name='envelope_recipient'),
537 ConfString(name='ssl_cert_hostname', required=False, default=None),
538 )
539 received_from = None
540 received_with = 'IMAP4-SSL'
541 received_by = localhostname()
542
543 def __str__(self):
544 self.log.trace()
545 return 'MultidropIMAPSSLRetriever:%s@%s:%s' % (
546 self.conf.get('username', 'username'),
547 self.conf.get('server', 'server'),
548 self.conf.get('port', 'port')
549 )
550
551 def showconf(self):
552 self.log.trace()
553 self.log.info('MultidropIMAPSSLRetriever(%s)' % self._confstring()
554 + os.linesep)
555