Fix crash introduced in the last refactoring
[imap-fix-internaldate] / fix_imap_internaldate.py
CommitLineData
c9da760a
PD
1'''
2fix_imap_internaldate.py - Fix the INTERNALDATE field on IMAP servers
3
4Copyright (c) 2012 Intra2net AG
5Author: Plamen Dimitrov
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
c9da760a
PD
16'''
17
18import sys
19import csv
8fe4e3ff
PD
20import argparse, configparser
21import logging
8a9d4c89 22from mail_date_parser import MailDateParser
c9da760a 23from mail_iterator import MailIterator
8301e589 24from caching_data import CachingData
c9da760a
PD
25
26def main():
27 """Iterates through csv list of users and their mailboxes"""
8fe4e3ff
PD
28
29 """parser = argparse.ArgumentParser(description='Fix the INTERNALDATE field on IMAP servers.')
30 parser.add_argument('--h', metavar='N', type=int, nargs='+',
31 help='an integer for the accumulator')
32 parser.add_argument('--u', dest='accumulate', type=bool,
33 const=sum, default=max,
34 help='sum the integers (default: find the max)')
35 args = parser.parse_args()
36 print(args.accumulate(args.integers))"""
37
7a1d4c35
PD
38 if(len(sys.argv) > 1):
39 if(sys.argv[1]=="--h"):
40 print("The default mode of the script is test mode."
41 "Add '--u' argument to exit to modify messages."
42 "For a detailed list of each message with a date conflict change"
43 "change the 'log_level' in the configuration file from '30' to '20'.")
44 return
45 if(sys.argv[1]=="--u"):
46 test_mode = False
c9da760a 47 else:
7a1d4c35 48 test_mode = True
c9da760a 49
8fe4e3ff 50 # config and logging setup
c9da760a 51 config = load_configuration()
8fe4e3ff 52 prepare_logger(config)
c9da760a 53
8a9d4c89 54 date_parser = MailDateParser()
7a1d4c35 55 caching_data = CachingData()
8fe4e3ff 56 logging.warning("Cache version %s loaded.", caching_data.version)
c9da760a 57 user_reader = csv.DictReader(open("userdata.csv", "r"), delimiter=',')
8fe4e3ff
PD
58
59 # server name is stored in the config
c9da760a 60 server = config.get('basic_settings', 'imap_server')
8fe4e3ff
PD
61 # tolerance is now in seconds
62 tolerance = config.getint('basic_settings', 'tolerance') * 60
c9da760a
PD
63
64 for user in user_reader:
65 try:
66 session = MailIterator(server, user['username'], user['password'])
67 except UserWarning as ex:
68 logging.error(ex)
69 continue
70 for mailbox in session:
71 try:
7a1d4c35 72 box = caching_data.retrieve_cached_mailbox(mailbox[0], mailbox[1], user['username'])
c9da760a 73 mail_ids = session.fetch_messages()
7a1d4c35 74 new_ids = box.synchronize(mail_ids)
6f2bc406 75 logging.info("%s new messages out of %s found in %s.", len(new_ids), len(mail_ids), box.name)
c9da760a
PD
76 except UserWarning as ex:
77 logging.error(ex)
78 continue
8301e589 79 for mid in new_ids:
c9da760a
PD
80 try:
81 fetched_internal_date = session.fetch_internal_date(mid)
8a9d4c89 82 internal_date = date_parser.extract_internal_date(fetched_internal_date)
c9da760a 83 fetched_received_date = session.fetch_received_date(mid)
8a9d4c89 84 received_date = date_parser.extract_received_date(fetched_received_date)
c9da760a 85 if(received_date==""):
d5ccfbec 86 logging.debug("No received date could be found in message uid: %s - mailbox: %s - user: %s.",
8a9d4c89 87 mid.decode('iso-8859-1'), box.name, box.owner)
7a1d4c35 88 box.no_received_field += 1
c9da760a
PD
89 continue
90 except UserWarning as ex:
91 logging.error(ex)
92 continue
8a9d4c89 93 if(date_parser.compare_dates(received_date, internal_date, tolerance)):
c9da760a
PD
94 #print(received_date, internal_date)
95 if(test_mode==0):
96 try:
7a1d4c35 97 session.update_message(mid, box.name, received_date)
c9da760a
PD
98 except UserWarning as ex:
99 logging.error(ex)
100 continue
101 else:
6f2bc406 102 logging.warning("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.",
8a9d4c89 103 mid.decode('iso-8859-1'), box.name, box.owner,
c9da760a
PD
104 internal_date.strftime("%d %b %Y %H:%M:%S"),
105 received_date.strftime("%d %b %Y %H:%M:%S"),
f7bf6cb2 106 fetched_received_date.split("Received:")[1])
8301e589 107 # count total emails for every user and mailbox
7a1d4c35 108 box.date_conflicts += 1
8301e589 109 # if all messages were successfully fixed confirm caching
7a1d4c35
PD
110 if(not test_mode):
111 box.confirm_change()
8fe4e3ff 112
8301e589 113 # final report on date conflicts
7a1d4c35 114 caching_data.report_date_conflicts()
c9da760a
PD
115
116def load_configuration():
117 """Loads the script configuration from a file or creates such."""
118 config = configparser.RawConfigParser()
8fe4e3ff
PD
119 success = config.read('confscript.cfg')
120 if(len(success)==0):
c9da760a 121 config.add_section('basic_settings')
8fe4e3ff
PD
122 config.set('basic_settings', 'file_log_level', logging.INFO)
123 config.set('basic_settings', 'console_log_level', logging.INFO)
124 config.set('basic_settings', 'imap_server', 'imap.company.com')
125 config.set('basic_settings', 'tolerance', 30)
c9da760a
PD
126 #config.set('Basic settings', 'bool', 'true')
127 with open('confscript.cfg', 'w') as configfile:
128 config.write(configfile)
129 return config
130
8fe4e3ff
PD
131def prepare_logger(config):
132 """Sets up the logging functionality"""
133
134 # reset the log
135 with open('fix_imap_internaldate.log', 'w'):
136 pass
137
138 # add basic configuration
139 logging.basicConfig(filename='fix_imap_internaldate.log',
140 format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
141 level=config.getint('basic_settings', 'file_log_level'))
142
143 # add a handler for a console output
144 console = logging.StreamHandler()
145 console.setLevel(config.getint('basic_settings', 'console_log_level'))
146 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
147 console.setFormatter(formatter)
148 logging.getLogger('').addHandler(console)
149 return
150
c9da760a
PD
151if(__name__ == "__main__"):
152 main()