Main function refactored and connection failure exception handling added
authorPlamen Dimitrov <plamen.dimitrov@intra2net.com>
Wed, 27 Jun 2012 14:47:36 +0000 (16:47 +0200)
committerPlamen Dimitrov <plamen.dimitrov@intra2net.com>
Thu, 28 Jun 2012 09:16:46 +0000 (11:16 +0200)
README
fix_imap_internaldate.py
mail_iterator.py

diff --git a/README b/README
index 5dd4f23..347da3b 100644 (file)
--- a/README
+++ b/README
@@ -20,10 +20,18 @@ An alternative approach would be to interpret the "Date:" header.
 Prerequisites:
 Python version 3 or later
 
+Necessary files:
+- userdata.csv: Contains information necessary for the user session with format:
+               username,password
+               testuser1,testpass1
+               testuser2,testpass2
 
-*** TO DOCUMENT ***
-- How to invoke
-necessary files
-- Invocation on Windows
+Produced files:
+- confscript.cfg: Configuration of the script - created on first run.
+- message_cache.dat: Cache file used for performance improvements
+- fix_imap_internaldate.log: Log file that resets with the script.
+- conflict_stats.txt: Final report on statistics about detected date conflicts and missing dates.
+
+Invocation on Windows requires and results in the same files.
 
 For more information please contact opensource@intra2net.com
index 06f39e0..bcf6dc2 100644 (file)
@@ -15,7 +15,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 '''
 
-import sys
 import csv
 import argparse, configparser
 import logging
@@ -24,34 +23,76 @@ from mail_iterator import MailIterator
 from caching_data import CachingData
 
 def main():
-    """Iterates through csv list of users and synchronize their messages"""
+    """Interprets command arguments and initializes configuration and logger.
+        Then begins mail synchronization."""
 
+    # parse arguments
     parser = argparse.ArgumentParser(description="Fix the INTERNALDATE field on IMAP servers. "
                                                 "Small tool to fix the IMAP internaldate "
                                                 "in case it's too much off compared to the last date "
                                                 "stored in the received lines.")
     parser.add_argument('-u', '--update', dest='test_mode', action='store_false',
                         default=True, help='update all e-mails and exit test mode')
-    args = parser.parse_args()
 
     # config and logging setup
     config = load_configuration()
     prepare_logger(config)
-
-    date_parser = MailDateParser()
-    caching_data = CachingData()
-    logging.warning("Cache version %s loaded.", caching_data.version)
+    args = parser.parse_args()
     if(args.test_mode):
         logging.info("Testing mode initiated. No message will be modified on the server.")
     else:
         logging.info("Update mode initiated. Messages will be modified.")
-    user_reader = csv.DictReader(open("userdata.csv", "r"), delimiter=',')
 
-    # server name is stored in the config
+    # proceed to main functionality
+    synchronize_csv(config, args.test_mode)
+
+    return
+
+def load_configuration():
+    """Loads the script configuration from a file or creates such."""
+    config = configparser.RawConfigParser()    
+    success = config.read('confscript.cfg')
+    if(len(success)==0):
+        config.add_section('basic_settings')
+        config.set('basic_settings', 'file_log_level', logging.INFO)
+        config.set('basic_settings', 'console_log_level', logging.INFO)
+        config.set('basic_settings', 'imap_server', 'imap.company.com')
+        config.set('basic_settings', 'tolerance', 30)
+        with open('confscript.cfg', 'w') as configfile:
+            config.write(configfile)
+    return config
+
+def prepare_logger(config):
+    """Sets up the logging functionality"""
+    
+    # reset the log
+    with open('fix_imap_internaldate.log', 'w'):
+        pass
+    
+    # add basic configuration
+    logging.basicConfig(filename='fix_imap_internaldate.log',
+                        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+                        level=config.getint('basic_settings', 'file_log_level'))
+    
+    # add a handler for a console output
+    console = logging.StreamHandler()
+    console.setLevel(config.getint('basic_settings', 'console_log_level'))
+    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+    console.setFormatter(formatter)
+    logging.getLogger('').addHandler(console)
+    return
+
+def synchronize_csv(config, test_mode):
+    """Iterates through csv list of users and synchronizes their messages."""
+
+    # initialize loop permanent data
+    caching_data = CachingData()  
+    date_parser = MailDateParser()
     server = config.get('basic_settings', 'imap_server')
-    # tolerance is now in seconds
     tolerance = config.getint('basic_settings', 'tolerance') * 60
 
+    # iterate through the users in the csv data
+    user_reader = csv.DictReader(open("userdata.csv", "r"), delimiter=',')
     for user in user_reader:
         try:
             session = MailIterator(server, user['username'], user['password'])
@@ -87,7 +128,7 @@ def main():
                                     internal_date.strftime("%d %b %Y %H:%M:%S"),
                                     received_date.strftime("%d %b %Y %H:%M:%S"),
                                     fetched_received_date.split("Received:")[1])
-                    if(args.test_mode==0):
+                    if(test_mode==0):
                         try:
                             session.update_message(mid, box.name, received_date)
                         except UserWarning as ex:
@@ -98,48 +139,12 @@ def main():
                     box.date_conflicts += 1
 
             # if all messages were successfully fixed confirm caching
-            if(not args.test_mode):
+            if(not test_mode):
                 box.confirm_change()
-
+    
         # final report on date conflicts
         caching_data.report_conflicts()
-
-def load_configuration():
-    """Loads the script configuration from a file or creates such."""
-    config = configparser.RawConfigParser()    
-    success = config.read('confscript.cfg')
-    if(len(success)==0):
-        config.add_section('basic_settings')
-        config.set('basic_settings', 'file_log_level', logging.INFO)
-        config.set('basic_settings', 'console_log_level', logging.INFO)
-        config.set('basic_settings', 'imap_server', 'imap.company.com')
-        config.set('basic_settings', 'tolerance', 30)
-        #config.set('Basic settings', 'bool', 'true')
-        with open('confscript.cfg', 'w') as configfile:
-            config.write(configfile)
-    return config
-
-def prepare_logger(config):
-    """Sets up the logging functionality"""
-    
-    # reset the log
-    with open('fix_imap_internaldate.log', 'w'):
-        pass
-    
-    # add basic configuration
-    logging.basicConfig(filename='fix_imap_internaldate.log',
-                        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
-                        level=config.getint('basic_settings', 'file_log_level'))
-    
-    # add a handler for a console output
-    console = logging.StreamHandler()
-    console.setLevel(config.getint('basic_settings', 'console_log_level'))
-    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
-    console.setFormatter(formatter)
-    logging.getLogger('').addHandler(console)
     return
 
-
-
 if(__name__ == "__main__"):
     main()
index e4da7d4..a17ab6c 100644 (file)
@@ -31,21 +31,28 @@ class MailIterator:
     mail_con = None
     # list of tuples (uidvalidity, mailboxname) for the retrieved mailboxes
     mailboxes = None
+    # logged in status
+    logged_in = None
 
     def __init__(self, server, username, password):
         """Creates a connection and a user session."""
-        self.mail_con = imaplib.IMAP4_SSL(server)
-        result, data = self.mail_con.login(username, password)
-        if(result!="OK"):
-            raise UserWarning("Could not log in as user " + username + ". " + data)
+        try:
+            self.mail_con = imaplib.IMAP4_SSL(server)
+            self.mail_con.login(username, password)
+            logging.info("Logged in as %s.", username)
+        except:
+            self.logged_in = False
+            raise UserWarning("Could not log in as user " + username + ".")
+        self.logged_in = True
         result, self.mailboxes = self.mail_con.list()
         if(result!="OK"):
             raise UserWarning("Could not retrieve mailboxes for user " + username + ".")
 
     def __del__(self):
         """Closes the connection and the user session."""
-        self.mail_con.close()
-        self.mail_con.logout()
+        if(self.logged_in):
+            self.mail_con.close()
+            self.mail_con.logout()
 
     def __iter__(self):
         """Iterates through all mailboxes, returns (uidval,name)."""