Commit | Line | Data |
---|---|---|
c9da760a PD |
1 | ''' |
2 | fix_imap_internaldate.py - Fix the INTERNALDATE field on IMAP servers | |
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 | Add '-t' argument when running the module for a test mode. | |
18 | For a detailed list of each message with a date conflict change | |
19 | the 'log_level' in the configuration file from '30' to '20'. | |
20 | ''' | |
21 | ||
22 | import sys | |
23 | import csv | |
24 | import logging | |
25 | import configparser | |
26 | from date_interpreter import DateInterpreter | |
27 | from mail_iterator import MailIterator | |
28 | ||
29 | def main(): | |
30 | """Iterates through csv list of users and their mailboxes""" | |
31 | if (len(sys.argv) > 1 and sys.argv[1]=="-t"): | |
32 | test_mode = 1 | |
33 | else: | |
34 | test_mode = 0 | |
35 | ||
36 | config = load_configuration() | |
37 | logging.basicConfig(filename='mailscript.log', | |
38 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', | |
39 | level=config.getint('basic_settings', 'log_level')) | |
40 | ||
41 | date_interp = DateInterpreter() | |
42 | user_reader = csv.DictReader(open("userdata.csv", "r"), delimiter=',') | |
43 | ||
44 | server = config.get('basic_settings', 'imap_server') | |
45 | tolerance = config.getint('basic_settings', 'tolerance') | |
46 | total_per_box = {} | |
47 | ||
48 | for user in user_reader: | |
49 | try: | |
50 | session = MailIterator(server, user['username'], user['password']) | |
51 | except UserWarning as ex: | |
52 | logging.error(ex) | |
53 | continue | |
54 | for mailbox in session: | |
55 | try: | |
56 | #print(".") | |
57 | mail_ids = session.fetch_messages() | |
58 | except UserWarning as ex: | |
59 | logging.error(ex) | |
60 | continue | |
61 | for mid in mail_ids: | |
62 | try: | |
63 | fetched_internal_date = session.fetch_internal_date(mid) | |
64 | internal_date = date_interp.extract_internal_date(fetched_internal_date) | |
65 | fetched_received_date = session.fetch_received_date(mid) | |
66 | received_date = date_interp.extract_received_date(fetched_received_date) | |
67 | if(received_date==""): | |
68 | logging.warning("No received date could be found in message uid: %s - mailbox: %s - user: %s.\n", | |
69 | mid.decode("utf-8"), mailbox.strip('"'), user['username']) | |
70 | continue | |
71 | except UserWarning as ex: | |
72 | logging.error(ex) | |
73 | continue | |
74 | if(date_interp.compare_dates(received_date, internal_date, tolerance)): | |
75 | #print(received_date, internal_date) | |
76 | if(test_mode==0): | |
77 | try: | |
78 | session.update_message(mid, mailbox, received_date) | |
79 | except UserWarning as ex: | |
80 | logging.error(ex) | |
81 | continue | |
82 | else: | |
83 | logging.info("Date conflict found in message uid: %s - mailbox: %s - user: %s.\nInternal date %s is different from received date %s from RECEIVED header:\n%s.", | |
84 | mid.decode("utf-8"), mailbox.strip('"'), user['username'], | |
85 | internal_date.strftime("%d %b %Y %H:%M:%S"), | |
86 | received_date.strftime("%d %b %Y %H:%M:%S"), | |
87 | fetched_received_date[0][1].decode("utf-8").split("Received:")[1]) | |
88 | #count total emails for every user and mailbox | |
89 | mixed_key = user['username']+'|'+mailbox.strip('"') | |
90 | total_per_box[mixed_key] = 1 + total_per_box.get(mixed_key, 0) | |
91 | total_per_user = 0 | |
92 | for warning in total_per_box: | |
93 | total_per_user += total_per_box[warning] | |
94 | logging.warning("Total date conflicts to be corrected in a mailbox %s are %s.", | |
95 | warning.split('|')[1], total_per_box[warning]) | |
96 | logging.warning("Total date conflicts to be corrected for user %s are %s.\n", | |
97 | user['username'], total_per_user) | |
98 | ||
99 | def load_configuration(): | |
100 | """Loads the script configuration from a file or creates such.""" | |
101 | config = configparser.RawConfigParser() | |
102 | try: | |
103 | config.read('confscript.cfg') | |
104 | except IOError: | |
105 | config.add_section('basic_settings') | |
106 | config.set('basic_settings', 'log_level', logging.DEBUG) | |
107 | #config.set('Basic settings', 'bool', 'true') | |
108 | with open('confscript.cfg', 'w') as configfile: | |
109 | config.write(configfile) | |
110 | return config | |
111 | ||
112 | if(__name__ == "__main__"): | |
113 | main() |