"Fossies" - the Fresh Open Source Software Archive 
Member "getmail-5.16/getmail" (31 Oct 2021, 42103 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.
See also the latest
Fossies "Diffs" side-by-side code changes report for "getmail":
5.15_vs_5.16.
1 #!/usr/bin/env python2
2
3 import sys
4
5 if sys.hexversion < 0x2030300:
6 raise ImportError('getmail version 5 requires Python version 2.3.3 '
7 'or later')
8
9 import os.path
10 import time
11 import ConfigParser
12 import netrc
13 import poplib
14 import imaplib
15 import pprint
16 from optparse import OptionParser, OptionGroup
17 import socket
18 import signal
19 import errno
20
21 # Optional gnome-keyring integration
22 try:
23 import gnomekeyring
24 import glib
25 glib.set_application_name('getmail')
26 # And test to see if it's actually available
27 if not gnomekeyring.is_available():
28 gnomekeyring = None
29 except ImportError:
30 gnomekeyring = None
31
32 options_bool = (
33 'read_all',
34 'delete',
35 'delivered_to',
36 'received',
37 'message_log_verbose',
38 'message_log_syslog',
39 'fingerprint',
40 'use_netrc',
41 )
42 options_int = (
43 'delete_after',
44 'delete_bigger_than',
45 'max_message_size',
46 'max_messages_per_session',
47 'max_bytes_per_session',
48 'verbose',
49 )
50 options_str = (
51 'message_log',
52 'netrc_file',
53 )
54
55 # Unix only
56 try:
57 import syslog
58 except ImportError:
59 pass
60
61 try:
62 from getmailcore import __version__, retrievers, destinations, filters, \
63 logging
64 from getmailcore.exceptions import *
65 from getmailcore.utilities import eval_bool, logfile, format_params, \
66 address_no_brackets, expand_user_vars, get_password, run_command
67 except ImportError, o:
68 sys.stderr.write('ImportError: %s\n' % o)
69 sys.exit(127)
70
71 log = logging.Logger()
72 log.addhandler(sys.stdout, logging.INFO, maxlevel=logging.INFO)
73 log.addhandler(sys.stderr, logging.WARNING)
74
75 defaults = {
76 'getmaildir' : '~/.getmail/',
77 'rcfile' : 'getmailrc',
78
79 'verbose' : 1,
80 'read_all' : True,
81 'delete' : False,
82 'delete_after' : 0,
83 'delete_bigger_than' : 0,
84 'max_message_size' : 0,
85 'max_messages_per_session' : 0,
86 'max_bytes_per_session' : 0,
87 'delivered_to' : True,
88 'received' : True,
89 'message_log' : None,
90 'message_log_verbose' : False,
91 'message_log_syslog' : False,
92 'logfile' : None,
93 'fingerprint' : False,
94 'use_netrc' : False,
95 'netrc_file' : None,
96 }
97
98
99
100
101 #######################################
102 def convert_to_sigint(unused1, unused2):
103 """Catch a SIGTERM and raise a SIGINT so getmail exits normally and does
104 cleanup if killed with default signal.
105 """
106 raise KeyboardInterrupt('from signal')
107
108 signal.signal(signal.SIGTERM, convert_to_sigint)
109
110 #######################################
111 def blurb():
112 log.info('getmail version %s\n' % __version__)
113 log.info('Copyright (C) 1998-2021 Charles Cazabon. Licensed under the '
114 'GNU GPL version 2.\n')
115
116 #######################################
117 def go(configs, idle):
118 """Main code.
119
120 Returns True if all goes well, False if any error condition occurs.
121 """
122 blurb()
123 summary = []
124 errorexit = False
125 idling = False
126
127 if len(configs) > 1 and idle:
128 log.info('more than one config file given with --idle, ignoring\n')
129 idle = False
130
131 for (configfile, retriever, _filters, destination, options) in configs:
132 if options['read_all'] and not options['delete']:
133 if idle:
134 # This is a nonsense combination of options; every time the
135 # server returns from IDLE, all messages will be re-retrieved.
136 log.error('%s: IDLE, read_all, and not delete - bad '
137 'combination, skipping\n'
138 % retriever)
139 continue
140 else:
141 # Slightly less nonsensical, but still weird.
142 log.warning('%s: read_all and not delete -- all messages will '
143 'be retrieved each time getmail is run\n'
144 % retriever)
145
146 oplevel = options['verbose']
147 logverbose = options['message_log_verbose']
148 now = int(time.time())
149 msgs_retrieved = 0
150 bytes_retrieved = 0
151 msgs_skipped = 0
152 if options['message_log_syslog']:
153 syslog.openlog('getmail', 0, syslog.LOG_MAIL)
154 try:
155 if not idling:
156 log.info('%s:\n' % retriever)
157 logline = 'Initializing %s:' % retriever
158 if options['logfile'] and logverbose:
159 options['logfile'].write(logline)
160 if options['message_log_syslog'] and logverbose:
161 syslog.syslog(syslog.LOG_INFO, logline)
162 retriever.initialize(options)
163 destination.retriever_info(retriever)
164
165 for mailbox in retriever.mailboxes:
166 if mailbox:
167 # For POP this is None and uninteresting
168 log.debug(' checking mailbox %s ...\n'
169 % mailbox.encode('utf-8'))
170 try:
171 retriever.select_mailbox(mailbox)
172 except getmailMailboxSelectError, o:
173 errorexit = True
174 log.info(' mailbox %s not selectable (%s) - verify the '
175 'mailbox exists and you have sufficient '
176 'permissions\n' % (mailbox.encode('utf-8'), o))
177 continue
178 nummsgs = len(retriever)
179 fmtlen = len(str(nummsgs))
180 for (msgnum, msgid) in enumerate(retriever):
181 log.debug(' message %s ...\n' % msgid)
182 msgnum += 1
183 retrieve = False
184 reason = 'seen'
185 delete = False
186 timestamp = retriever.oldmail.get(msgid, None)
187 size = retriever.getmsgsize(msgid)
188 info = ('msg %*d/%*d (%d bytes)'
189 % (fmtlen, msgnum, fmtlen, nummsgs, size))
190 logline = '%s msgid %s' % (info, msgid)
191 if options['read_all'] or timestamp is None:
192 retrieve = True
193 if (options['max_message_size']
194 and size > options['max_message_size']):
195 retrieve = False
196 reason = 'oversized'
197 if (options['max_bytes_per_session']
198 and (bytes_retrieved + size)
199 > options['max_bytes_per_session']):
200 retrieve = False
201 reason = 'would surpass max_bytes_per_session'
202 try:
203 if retrieve:
204 try:
205 msg = retriever.getmsg(msgid)
206 except getmailRetrievalError, o:
207 errorexit = True
208 log.error(
209 'Retrieval error: server for %s is broken; '
210 'offered message %s but failed to provide it. '
211 'Please notify the administrator of the '
212 'server. Skipping message...\n'
213 % (retriever, msgid)
214 )
215 continue
216 msgs_retrieved += 1
217 bytes_retrieved += size
218 if oplevel > 1:
219 info += (' from <%s>'
220 % address_no_brackets(msg.sender))
221 if msg.recipient is not None:
222 info += (' to <%s>'
223 % address_no_brackets(msg.recipient))
224 logline += (' from <%s>'
225 % address_no_brackets(msg.sender))
226 if msg.recipient is not None:
227 logline += (' to <%s>'
228 % address_no_brackets(msg.recipient))
229
230 for mail_filter in _filters:
231 log.debug(' passing to filter %s\n'
232 % mail_filter)
233 msg = mail_filter.filter_message(msg, retriever)
234 if msg is None:
235 log.debug(' dropped by filter %s\n'
236 % mail_filter)
237 info += (' dropped by filter %s'
238 % mail_filter)
239 logline += (' dropped by filter %s'
240 % mail_filter)
241 retriever.delivered(msgid)
242 break
243
244 if msg is not None:
245 r = destination.deliver_message(msg,
246 options['delivered_to'], options['received'])
247 log.debug(' delivered to %s\n' % r)
248 info += ' delivered'
249 if oplevel > 1:
250 info += (' to %s' % r)
251 logline += (' delivered to %s' % r)
252 retriever.delivered(msgid)
253 if options['delete']:
254 delete = True
255 else:
256 logline += ' not retrieved (%s)' % reason
257 msgs_skipped += 1
258 log.debug(' not retrieving (timestamp %s)\n'
259 % timestamp)
260 if oplevel > 1:
261 info += ' not retrieved (%s)' % reason
262
263 if (options['delete_after'] and timestamp
264 and (now - timestamp) / 86400
265 >= options['delete_after']):
266 log.debug(
267 ' older than %d days (%s seconds), will delete\n'
268 % (options['delete_after'], (now - timestamp))
269 )
270 delete = True
271
272 if options['delete'] and timestamp:
273 log.debug(' will delete\n')
274 delete = True
275
276 if (options['delete_bigger_than']
277 and size > options['delete_bigger_than']):
278 log.debug(' bigger than %d, will delete\n'
279 % options['delete_bigger_than'])
280 delete = True
281
282 if not retrieve and timestamp is None:
283 # We haven't retrieved this message. Don't delete it.
284 log.debug(' not yet retrieved, not deleting\n')
285 delete = False
286
287 if delete:
288 retriever.delmsg(msgid)
289 log.debug(' deleted\n')
290 info += ', deleted'
291 logline += ', deleted'
292
293 except getmailDeliveryError, o:
294 errorexit = True
295 log.error('Delivery error (%s)\n' % o)
296 info += ', delivery error (%s)' % o
297 if options['logfile']:
298 options['logfile'].write('Delivery error (%s)' % o)
299 if options['message_log_syslog']:
300 syslog.syslog(syslog.LOG_ERR,
301 'Delivery error (%s)' % o)
302
303 except getmailFilterError, o:
304 errorexit = True
305 log.error('Filter error (%s)\n' % o)
306 info += ', filter error (%s)' % o
307 if options['logfile']:
308 options['logfile'].write('Filter error (%s)' % o)
309 if options['message_log_syslog']:
310 syslog.syslog(syslog.LOG_ERR,
311 'Filter error (%s)' % o)
312
313 if (retrieve or delete or oplevel > 1):
314 log.info(' %s\n' % info)
315 if options['logfile'] and (retrieve or delete or logverbose):
316 options['logfile'].write(logline)
317 if options['message_log_syslog'] and (retrieve or delete
318 or logverbose):
319 syslog.syslog(syslog.LOG_INFO, logline)
320
321 if (options['max_messages_per_session']
322 and msgs_retrieved >=
323 options['max_messages_per_session']):
324 log.debug('hit max_messages_per_session (%d), breaking\n'
325 % options['max_messages_per_session'])
326 if oplevel > 1:
327 log.info(' max messages per session (%d)\n'
328 % options['max_messages_per_session'])
329 raise StopIteration('max_messages_per_session %d'
330 % options['max_messages_per_session'])
331
332 except StopIteration:
333 pass
334
335 except KeyboardInterrupt, o:
336 log.warning('%s: user aborted\n' % configfile)
337 if options['logfile']:
338 options['logfile'].write('user aborted')
339
340 except socket.timeout, o:
341 errorexit = True
342 retriever.abort()
343 if type(o) == tuple and len(o) > 1:
344 o = o[1]
345 log.error('%s: timeout (%s)\n' % (configfile, o))
346 if options['logfile']:
347 options['logfile'].write('timeout error (%s)' % o)
348
349 except (poplib.error_proto, imaplib.IMAP4.abort), o:
350 errorexit = True
351 retriever.abort()
352 log.error('%s: protocol error (%s)\n' % (configfile, o))
353 if options['logfile']:
354 options['logfile'].write('protocol error (%s)' % o)
355
356 except socket.gaierror, o:
357 errorexit = True
358 retriever.abort()
359 if type(o) == tuple and len(o) > 1:
360 o = o[1]
361 log.error('%s: error resolving name (%s)\n' % (configfile, o))
362 if options['logfile']:
363 options['logfile'].write('gaierror error (%s)' % o)
364
365 except socket.error, o:
366 errorexit = True
367 retriever.abort()
368 if type(o) == tuple and len(o) > 1:
369 o = o[1]
370 log.error('%s: socket error (%s)\n' % (configfile, o))
371 if options['logfile']:
372 options['logfile'].write('socket error (%s)' % o)
373
374 except getmailCredentialError, o:
375 errorexit = True
376 retriever.abort()
377 log.error('%s: credential/login error (%s)\n' % (configfile, o))
378 if options['logfile']:
379 options['logfile'].write('credential/login error (%s)' % o)
380
381 except getmailLoginRefusedError, o:
382 retriever.abort()
383 log.error('%s: login refused error (%s)\n' % (configfile, o))
384 if options['logfile']:
385 options['logfile'].write('login refused error (%s)' % o)
386
387 except getmailOperationError, o:
388 errorexit = True
389 retriever.abort()
390 log.error('%s: operation error (%s)\n' % (configfile, o))
391 if options['logfile']:
392 options['logfile'].write('getmailOperationError error (%s)' % o)
393 if options['message_log_syslog']:
394 syslog.syslog(syslog.LOG_ERR,
395 'getmailOperationError error (%s)' % o)
396
397 summary.append(
398 (retriever, msgs_retrieved, bytes_retrieved, msgs_skipped)
399 )
400
401 log.info(' %d messages (%d bytes) retrieved, %d skipped\n'
402 % (msgs_retrieved, bytes_retrieved, msgs_skipped))
403 if options['logfile'] and logverbose:
404 options['logfile'].write(
405 ' %d messages (%d bytes) retrieved, %d skipped\n'
406 % (msgs_retrieved, bytes_retrieved, msgs_skipped)
407 )
408 log.debug('retriever %s finished\n' % retriever)
409 try:
410 if idle and not retriever.supports_idle:
411 log.info('--idle given, but retriever does not support IDLE\n')
412 idle = False
413 if idle and sys.version_info < (2, 5, 0):
414 log.info('--idle requires Python 2.5 or higher\n')
415 idle = False
416
417 if idle and not errorexit:
418 # TODO
419 # Okay, so what should really happen here is that when go_idle
420 # returns, getmail should use the *existing* connection to check
421 # for new messages and then call go_idle again once that is
422 # done. The current code layout doesn't lend itself very well to
423 # that since the message download code is coupled with the
424 # connection setup/teardown code.
425 #
426 # Therefore, we do a bit of a hack.
427 # We add the current config back into configs, so that when the
428 # main for loop over configs runs again, it will find the same
429 # config again, and thus download the new messages and then go
430 # back to IDLEing. Since the return value of go_idle changes the
431 # value of idling, a failed connection will cause it to become
432 # False, which will make the main go() loop reconnect, which is
433 # what we want.
434 # Expunge and close the mailbox to prevent the same messages
435 # being pulled again in some configurations.
436 retriever.close_mailbox()
437 try:
438 idling = retriever.go_idle(idle)
439 # Returned from idle
440 retriever.set_new_timestamp()
441 configs.append(configs[0])
442 continue
443 except KeyboardInterrupt, o:
444 # Because configs isn't appended to, this just means we'll
445 # quit, which is presumably what the user wanted
446 # The newline is to clear the ^C shown in terminal
447 log.info('\n')
448 pass
449 except socket.error, o:
450 if o.errno != errno.ECONNRESET:
451 # Something unexpected happened
452 raise
453 #pass
454 # Just exit after a reset connection.
455
456 retriever.quit()
457 except getmailOperationError, o:
458 errorexit = True
459 log.debug('%s: operation error during quit (%s)\n'
460 % (configfile, o))
461 if options['logfile']:
462 options['logfile'].write('%s: operation error during quit (%s)'
463 % (configfile, o))
464
465 if sum([i for (unused, i, unused, unused) in summary]) and oplevel > 1:
466 log.info('Summary:\n')
467 for (retriever, msgs_retrieved, bytes_retrieved, unused) in summary:
468 log.info('Retrieved %d messages (%s bytes) from %s\n'
469 % (msgs_retrieved, bytes_retrieved, retriever))
470
471 return (not errorexit)
472
473
474 #######################################
475 def main():
476 try:
477 parser = OptionParser(version='%%prog %s' % __version__)
478 parser.add_option(
479 '-g', '--getmaildir',
480 dest='getmaildir', action='store', default=defaults['getmaildir'],
481 help='look in DIR for config/data files', metavar='DIR'
482 )
483 parser.add_option(
484 '-r', '--rcfile',
485 dest='rcfile', action='append', default=[],
486 help='load configuration from FILE (may be given multiple times)',
487 metavar='FILE'
488 )
489 parser.add_option(
490 '--dump',
491 dest='dump_config', action='store_true', default=False,
492 help='dump configuration and exit (debugging)'
493 )
494 parser.add_option(
495 '--trace',
496 dest='trace', action='store_true', default=False,
497 help='print extended trace information (extremely verbose)'
498 )
499 parser.add_option(
500 '-i', '--idle',
501 dest='idle', action='store', default='',
502 help='maintain connection and listen for new messages in FOLDER. '
503 'Only applies if a single rc file is given with a connection '
504 'to an IMAP server that supports the IDLE command',
505 metavar='FOLDER'
506 )
507 if gnomekeyring:
508 parser.add_option(
509 '--store-password-in-gnome-keyring',
510 dest='store_gnome_keyring', action='store_true', default=False,
511 help='store the POP/IMAP password in the Gnome keyring'
512 )
513 overrides = OptionGroup(
514 parser, 'Overrides',
515 'The following options override those specified in any '
516 'getmailrc file.'
517 )
518 overrides.add_option(
519 '-v', '--verbose',
520 dest='override_verbose', action='count',
521 help='operate more verbosely (may be given multiple times)'
522 )
523 overrides.add_option(
524 '--fingerprint',
525 dest='override_fingerprint', action='store_true',
526 help='show SSL/TLS fingerprint and connection information'
527 )
528 overrides.add_option(
529 '-q', '--quiet',
530 dest='override_verbose', action='store_const',
531 const=0,
532 help='operate quietly (only report errors)'
533 )
534 overrides.add_option(
535 '-d', '--delete',
536 dest='override_delete', action='store_true',
537 help='delete messages from server after retrieving'
538 )
539 overrides.add_option(
540 '-l', '--dont-delete',
541 dest='override_delete', action='store_false',
542 help='do not delete messages from server after retrieving'
543 )
544 overrides.add_option(
545 '-a', '--all',
546 dest='override_read_all', action='store_true',
547 help='retrieve all messages'
548 )
549 overrides.add_option(
550 '-n', '--new',
551 dest='override_read_all', action='store_false',
552 help='retrieve only unread messages'
553 )
554 parser.add_option_group(overrides)
555
556 (options, args) = parser.parse_args(sys.argv[1:])
557 if args:
558 raise getmailOperationError('unknown argument(s) %s ; try --help'
559 % args)
560
561 if options.trace:
562 log.clearhandlers()
563
564 if not options.rcfile:
565 options.rcfile.append(defaults['rcfile'])
566
567 s = ''
568 for attr in dir(options):
569 if attr.startswith('_'):
570 continue
571 if s:
572 s += ','
573 s += '%s="%s"' % (attr, pprint.pformat(getattr(options, attr)))
574 log.debug('parsed options: %s\n' % s)
575
576 getmaildir_type = 'Default'
577 if options.getmaildir != defaults['getmaildir']:
578 getmaildir_type = 'Specified'
579 getmaildir = expand_user_vars(options.getmaildir)
580 if not os.path.exists(getmaildir):
581 raise getmailOperationError(
582 '%s config/data dir "%s" does not exist - create '
583 'or specify alternate directory with --getmaildir option'
584 % (getmaildir_type, getmaildir)
585 )
586 if not os.path.isdir(getmaildir):
587 raise getmailOperationError(
588 '%s config/data dir "%s" is not a directory - fix '
589 'or specify alternate directory with --getmaildir option'
590 % (getmaildir_type, getmaildir)
591 )
592 if not os.access(getmaildir, os.W_OK):
593 raise getmailOperationError(
594 '%s config/data dir "%s" is not writable - fix permissions '
595 'or specify alternate directory with --getmaildir option'
596 % (getmaildir_type, getmaildir)
597 )
598
599 configs = []
600 for filename in options.rcfile:
601 path = os.path.join(os.path.expanduser(options.getmaildir),
602 filename)
603 log.debug('processing rcfile %s\n' % path)
604 if not os.path.exists(path):
605 raise getmailOperationError('configuration file %s does '
606 'not exist' % path)
607 elif not os.path.isfile(path):
608 raise getmailOperationError('%s is not a file' % path)
609 f = open(path, 'rb')
610 config = {
611 'verbose' : defaults['verbose'],
612 'read_all' : defaults['read_all'],
613 'delete' : defaults['delete'],
614 'delete_after' : defaults['delete_after'],
615 'delete_bigger_than' : defaults['delete_bigger_than'],
616 'max_message_size' : defaults['max_message_size'],
617 'max_messages_per_session' :
618 defaults['max_messages_per_session'],
619 'max_bytes_per_session' :
620 defaults['max_bytes_per_session'],
621 'delivered_to' : defaults['delivered_to'],
622 'received' : defaults['received'],
623 'logfile' : defaults['logfile'],
624 'message_log' : defaults['message_log'],
625 'message_log_verbose' : defaults['message_log_verbose'],
626 'message_log_syslog' : defaults['message_log_syslog'],
627 'fingerprint' : defaults['fingerprint'],
628 'use_netrc' : defaults['use_netrc'],
629 'netrc_file' : defaults['netrc_file'],
630 }
631 # Python's ConfigParser .getboolean() couldn't handle booleans in
632 # the defaults. Submitted a patch; they fixed it a different way.
633 # But for the extant, unfixed versions, an ugly hack....
634 parserdefaults = config.copy()
635 for (key, value) in parserdefaults.items():
636 if type(value) == bool:
637 parserdefaults[key] = str(value)
638
639 try:
640 configparser = ConfigParser.RawConfigParser(parserdefaults)
641 configparser.readfp(f, path)
642 for option in options_bool:
643 log.debug(' looking for option %s ... ' % option)
644 if configparser.has_option('options', option):
645 log.debug('got "%s"'
646 % configparser.get('options', option))
647 try:
648 config[option] = configparser.getboolean(
649 'options', option
650 )
651 log.debug('-> %s' % config[option])
652 except ValueError:
653 raise getmailConfigurationError(
654 'configuration file %s incorrect (option %s '
655 'must be boolean, not %s)'
656 % (path, option,
657 configparser.get('options', option))
658 )
659 else:
660 log.debug('not found')
661 log.debug('\n')
662
663 for option in options_int:
664 log.debug(' looking for option %s ... ' % option)
665 if configparser.has_option('options', option):
666 log.debug(
667 'got "%s"' % configparser.get('options', option)
668 )
669 try:
670 config[option] = configparser.getint('options',
671 option)
672 log.debug('-> %s' % config[option])
673 except ValueError:
674 raise getmailConfigurationError(
675 'configuration file %s incorrect (option %s '
676 'must be integer, not %s)'
677 % (path, option,
678 configparser.get('options', option))
679 )
680 else:
681 log.debug('not found')
682 log.debug('\n')
683
684 # Message log file
685 for option in options_str:
686 log.debug(' looking for option %s ... ' % option)
687 if configparser.has_option('options', option):
688 log.debug('got "%s"'
689 % configparser.get('options', option))
690 config[option] = configparser.get('options', option)
691 log.debug('-> %s' % config[option])
692 else:
693 log.debug('not found')
694 log.debug('\n')
695 if config['message_log']:
696 try:
697 config['logfile'] = logfile(config['message_log'])
698 except IOError, o:
699 raise getmailConfigurationError(
700 'error opening message_log file %s (%s)'
701 % (config['message_log'], o)
702 )
703
704 # see if a netrc file is configured
705 netrc_object = None
706 if config['use_netrc']:
707 netrc_object = netrc.netrc(
708 config['netrc_file']
709 and expand_user_vars(config['netrc_file']))
710
711 # Clear out the ConfigParser defaults before processing further
712 # sections
713 configparser._defaults = {}
714
715 # Retriever
716 log.debug(' getting retriever\n')
717 retriever_type = configparser.get('retriever', 'type')
718 log.debug(' type="%s"\n' % retriever_type)
719 retriever_func = getattr(retrievers, retriever_type)
720 if not callable(retriever_func):
721 raise getmailConfigurationError(
722 'configuration file %s specifies incorrect '
723 'retriever type (%s)'
724 % (path, retriever_type)
725 )
726 retriever_args = {
727 'getmaildir' : options.getmaildir,
728 'configparser' : configparser,
729 }
730 for (name, value) in configparser.items('retriever'):
731 if name in ('type', 'configparser'):
732 continue
733 if name == 'password':
734 log.debug(' parameter %s=*\n' % name)
735 else:
736 log.debug(' parameter %s="%s"\n' % (name, value))
737 retriever_args[name] = value
738 if netrc_object:
739 # add username and password from netrc, as read above
740 netrc_auth = netrc_object.authenticators(
741 retriever_args['server'])
742 if netrc_auth and netrc_auth[0]:
743 retriever_args['username'] = netrc_auth[0]
744 if netrc_auth and netrc_auth[2]:
745 retriever_args['password'] = netrc_auth[2]
746 log.debug(' instantiating retriever %s with args %s\n'
747 % (retriever_type, format_params(retriever_args)))
748 try:
749 retriever = retriever_func(**retriever_args)
750 log.debug(' checking retriever configuration for %s\n'
751 % retriever)
752 retriever.checkconf()
753 except getmailOperationError, o:
754 log.error('Error initializing retriever: %s\n' % o)
755 continue
756
757 # Retriever is okay. Check if user wants us to store the
758 # password in a Gnome keyring for future use.
759 if gnomekeyring and options.store_gnome_keyring:
760 # Need to get the password first, if the user hasn't put
761 # it in the rc file.
762 if retriever.conf.get('password', None) is not None:
763 password = retriever.conf['password']
764 elif retriever.conf.get('password_command', None):
765 # Retrieve from an arbitrary external command
766 command = retriever.conf['password_command'][0]
767 args = retriever.conf['password_command'][1:]
768 (rc, stdout, stderr) = run_command(command, args)
769 if stderr:
770 log.warn(
771 'External password program "%s" wrote to stderr: %s',
772 command, stderr
773 )
774 if rc:
775 # program exited nonzero
776 raise getmailOperationError(
777 'External password program error (exited %d)' % rc
778 )
779 else:
780 password = stdout
781 else:
782 password = get_password(
783 str(retriever), retriever.conf['username'],
784 retriever.conf['server'], retriever.received_with,
785 log
786 )
787
788 gnomekeyring.set_network_password_sync(
789 # keyring=None, user, domain=None, server, object=None,
790 # protocol, authtype=None, port=0
791 None, retriever.conf['username'], None,
792 retriever.conf['server'], None, retriever.received_with,
793 None, 0, password
794 )
795 log.info('Stored password in Gnome keyring. Exiting.\n')
796 raise SystemExit()
797
798 # Destination
799 log.debug(' getting destination\n')
800 destination_type = configparser.get('destination', 'type')
801 log.debug(' type="%s"\n' % destination_type)
802 destination_func = getattr(destinations, destination_type)
803 if not callable(destination_func):
804 raise getmailConfigurationError(
805 'configuration file %s specifies incorrect destination '
806 'type (%s)'
807 % (path, destination_type)
808 )
809 destination_args = {'configparser' : configparser}
810 for (name, value) in configparser.items('destination'):
811 if name in ('type', 'configparser'):
812 continue
813 if name == 'password':
814 log.debug(' parameter %s=*\n' % name)
815 else:
816 log.debug(' parameter %s="%s"\n' % (name, value))
817 destination_args[name] = value
818 log.debug(' instantiating destination %s with args %s\n'
819 % (destination_type, format_params(destination_args)))
820 destination = destination_func(**destination_args)
821
822 # Filters
823 log.debug(' getting filters\n')
824 _filters = []
825 filtersections = [
826 section.lower() for section in configparser.sections()
827 if section.lower().startswith('filter')
828 ]
829 filtersections.sort()
830 for section in filtersections:
831 log.debug(' processing filter section %s\n' % section)
832 filter_type = configparser.get(section, 'type')
833 log.debug(' type="%s"\n' % filter_type)
834 filter_func = getattr(filters, filter_type)
835 if not callable(filter_func):
836 raise getmailConfigurationError(
837 'configuration file %s specifies incorrect filter '
838 'type (%s)'
839 % (path, filter_type)
840 )
841 filter_args = {'configparser' : configparser}
842 for (name, value) in configparser.items(section):
843 if name in ('type', 'configparser'):
844 continue
845 if name == 'password':
846 log.debug(' parameter %s=*\n' % name)
847 else:
848 log.debug(' parameter %s="%s"\n' % (name, value))
849 filter_args[name] = value
850 log.debug(' instantiating filter %s with args %s\n'
851 % (filter_type, format_params(filter_args)))
852 mail_filter = filter_func(**filter_args)
853 _filters.append(mail_filter)
854
855 except ConfigParser.NoSectionError, o:
856 raise getmailConfigurationError(
857 'configuration file %s missing section (%s)' % (path, o)
858 )
859 except ConfigParser.NoOptionError, o:
860 raise getmailConfigurationError(
861 'configuration file %s missing option (%s)' % (path, o)
862 )
863 except (ConfigParser.DuplicateSectionError,
864 ConfigParser.InterpolationError,
865 ConfigParser.MissingSectionHeaderError,
866 ConfigParser.ParsingError), o:
867 raise getmailConfigurationError(
868 'configuration file %s incorrect (%s)' % (path, o)
869 )
870 except getmailConfigurationError, o:
871 raise getmailConfigurationError(
872 'configuration file %s incorrect (%s)' % (path, o)
873 )
874
875 # Apply overrides from commandline
876 for option in ('read_all', 'delete', 'verbose', 'fingerprint'):
877 val = getattr(options, 'override_%s' % option)
878 if val is not None:
879 log.debug('overriding option %s from commandline %s\n'
880 % (option, val))
881 config[option] = val
882
883 if config['verbose'] > 2:
884 config['verbose'] = 2
885
886 if not options.trace and config['verbose'] == 0:
887 log.clearhandlers()
888 log.addhandler(sys.stderr, logging.WARNING)
889
890 configs.append((os.path.basename(filename), retriever, _filters,
891 destination, config.copy()))
892
893 if options.dump_config:
894 # Override any "verbose = 0" in the config file
895 log.clearhandlers()
896 log.addhandler(sys.stdout, logging.INFO, maxlevel=logging.INFO)
897 log.addhandler(sys.stderr, logging.WARNING)
898 blurb()
899 for (filename, retriever, _filters, destination, config) in configs:
900 log.info('getmail configuration:\n')
901 log.info(' getmail version %s\n' % __version__)
902 log.info(' Python version %s\n' % sys.version)
903 log.info(' retriever: ')
904 retriever.showconf()
905 if _filters:
906 for _filter in _filters:
907 log.info(' filter: ')
908 _filter.showconf()
909 log.info(' destination: ')
910 destination.showconf()
911 log.info(' options:\n')
912 names = config.keys()
913 names.sort()
914 for name in names:
915 log.info(' %s : %s\n' % (name, config[name]))
916 log.info('\n')
917 sys.exit()
918
919 # Go!
920 success = go(configs, options.idle)
921 if not success:
922 raise SystemExit(127)
923
924 except KeyboardInterrupt:
925 log.warning('Operation aborted by user (keyboard interrupt)\n')
926 sys.exit(0)
927 except getmailConfigurationError, o:
928 log.error('Configuration error: %s\n' % o)
929 sys.exit(2)
930 except getmailOperationError, o:
931 log.error('Error: %s\n' % o)
932 sys.exit(3)
933 except StandardError, o:
934 log.critical(
935 '\nException: please read docs/BUGS and include the '
936 'following information in any bug report:\n\n'
937 )
938 log.critical(' getmail version %s\n' % __version__)
939 log.critical(' Python version %s\n\n' % sys.version)
940 log.critical('Unhandled exception follows:\n')
941 (exc_type, value, tb) = sys.exc_info()
942 import traceback
943 tblist = (traceback.format_tb(tb, None)
944 + traceback.format_exception_only(exc_type, value))
945 if type(tblist) != list:
946 tblist = [tblist]
947 for line in tblist:
948 log.critical(' %s\n' % line.rstrip())
949 log.critical('\nPlease also include configuration information '
950 'from running getmail\n')
951 log.critical('with your normal options plus "--dump".\n')
952 sys.exit(4)
953
954 #######################################
955 if __name__ == '__main__':
956 main()