Improve logging to show skipped mailboxes
[imap-mark-seen] / src / imap_mark_seen.py
1 '''
2 imap_mark_seen.py - Tool to mark all e-mails as seen
3
4 Copyright (c) 2012 Intra2net AG
5 Author: Plamen Dimitrov
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 '''
17 import logging, re
18 import argparse, getpass
19 from mail_iterator import MailIterator
20 from warnings_handler import WarningsHandler
21
22 # logging settings
23 LOG_FILENAME = "imap_mark_seen.log"
24 LOG_FILE_LEVEL = logging.DEBUG
25 LOG_SHELL_LEVEL = logging.INFO
26 LOG_UNCLEAN_EXIT_LEVEL = logging.WARNING
27
28 def main():
29     """Main function."""
30
31     # prepare configuration
32     args = configure_args()
33     warnings_handler = prepare_logger()
34     logging.info("Marking messages as seen for user \"%s\" in folder \"%s\"", args.user, args.folder)
35     psw = getpass.getpass()
36
37     # prepare simple mail iterator and iterate throug mailboxes
38     session = MailIterator(args.server, args.user, psw, args.skip_shared_folders)
39     total_messages = 0
40     for mailbox in session:
41         delimiter = re.escape(mailbox[1])
42         pattern = '^\"?INBOX' + delimiter + re.escape(args.folder) + "[\"?$|" + delimiter + "]"
43         if args.folder != "all folders" and re.compile(pattern).match(mailbox[2]) == None:
44             logging.info("Skipping mailbox %s", mailbox[2])
45             continue
46         try:
47             mail_ids = session.fetch_messages()
48         except UserWarning as ex:
49             logging.error(ex)
50             continue
51         try:
52             if len(mail_ids) > 0:
53                 mail_id_range = min(mail_ids, key=int).decode('iso-8859-1') + ':' + max(mail_ids, key=int).decode('iso-8859-1')
54                 session.set_seen_messages(mailbox, mail_id_range)
55                 total_messages += len(mail_ids)
56             else:
57                 logging.info("Skipping empty mailbox %s", mailbox[2])
58         except UserWarning as ex:
59             logging.error(ex)
60
61     logging.info("Finished marking up to %s messages as seen", total_messages)
62     logging.info("Exiting with code %s", warnings_handler.detected_problems)
63     return int(warnings_handler.detected_problems > 0)
64
65 def configure_args():
66     """Configure arguments and return them."""
67
68     # parse arguments
69     parser = argparse.ArgumentParser(description="Tool to mark messages as seen.")
70     parser.add_argument('-u', '--user', dest='user', action='store',
71                         required=True, help='mark all messages as seen for a single user')
72     parser.add_argument('-f', '--folder', dest='folder', action='store',
73                         default="all folders", help='only mark given folder as seen')
74     parser.add_argument('-s', '--server', dest='server', action='store',
75                         default="localhost", help='imap server name with default localhost')    
76     parser.add_argument('-r', '--shared', dest='skip_shared_folders', action='store_false',
77                         default=True, help='skip shared folders flag')    
78     args = parser.parse_args()
79
80     return args
81
82 def prepare_logger():
83     """Sets up the logging functionality"""
84
85     # reset the log
86     with open(LOG_FILENAME, 'w'):
87         pass
88
89     # add basic configuration
90     logging.basicConfig(filename=LOG_FILENAME,
91                         format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
92                         level=LOG_FILE_LEVEL)
93
94     # add a handler for a console output
95     default_logger = logging.getLogger('')
96     console = logging.StreamHandler()
97     console.setLevel(LOG_SHELL_LEVEL)
98     formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
99     console.setFormatter(formatter)
100     default_logger.addHandler(console)
101
102     # add a handler for warnings counting
103     warnings_handler = WarningsHandler()
104     warnings_handler.setLevel(LOG_UNCLEAN_EXIT_LEVEL)
105     default_logger.addHandler(warnings_handler)
106
107     return warnings_handler
108
109 if __name__ == "__main__":
110     main()