File and console logging added for exception handling and information
authorPlamen Dimitrov <plamen.dimitrov@intra2net.com>
Mon, 9 Jul 2012 09:35:29 +0000 (11:35 +0200)
committerPlamen Dimitrov <plamen.dimitrov@intra2net.com>
Mon, 9 Jul 2012 09:35:29 +0000 (11:35 +0200)
file_iterator.py
mail_iterator.py
restore_mail_inject.py

index 5c3512d..b597928 100644 (file)
@@ -6,6 +6,7 @@ Copyright (c) 2012 Intra2net AG
 
 import sys, os
 import re
+import logging
 
 MAIL_FILENAME = re.compile("^[0-9]+\.$")
 MBOXFILE_LINE = re.compile("^(.*?)\t(?:\d )?default[\t ](.*)$")
@@ -35,8 +36,9 @@ class FileIterator:
         try:
             with open(filename, "r") as msgfile:
                 message = msgfile.read()
-        except:
-            print("Could not open the e-mail file %s.", filename)
+        except IOError:
+            logging.warning("Could not open the e-mail file %s", filename)
+            raise
         return message
 
     def load_mailbox_list(self, mboxlistfile = ""):
@@ -49,8 +51,8 @@ class FileIterator:
                         linedata = MBOXFILE_LINE.match(line).groups()
                         #!!! test this condition
                         if len(linedata) == 0:
-                            print("Illegal line in mailbox list dump: %s" % line)
-                            sys.exit()
+                            logging.warning("Illegal line in mailbox list dump: %s" % line)
+                            continue
                         key = linedata[0]
                         aclstr = linedata[1]
                         
@@ -58,60 +60,58 @@ class FileIterator:
                         while(aclstr != ""):
                             acldata = ACL_STRING.match(aclstr).groups()
                             if len(acldata) == 0:
-                                print("Illegal line in mailbox list dump: %s" % line)
-                                sys.exit()                               
+                                logging.error("Illegal acl string in mailbox list dump: %s" % line)
+                                continue
                             aclstr = acldata[2]
                             acls[acldata[0]]=acldata[1]
 
                         mboxdb[key] = acls
-
             except IOError:
-                print("Could not open mboxlist file %s." % mboxlistfile)
+                logging.warning("Could not open mboxlist file %s" % mboxlistfile)
         return mboxdb
 
     def load_mails(self, filepath, mailpath):
         """Loads all e-mails from file hierarchy.
         This recursive generator always returns a tuple of
         the next found (e-mail, mailbox to store, internaldate)."""
-        #print("Entered directory %s -> %s." % (filepath, mailpath))
+        logging.debug("Entered directory %s -> %s" % (filepath, mailpath))
         try:
             filepath = os.path.abspath(filepath)
             os.chdir(filepath)
         except OSError:
-            print("Can't open the directory %s." % filepath)
+            logging.warning("Can't open the directory %s" % filepath)
             return
         # mark mailboxes that should be created
         self.created_mailboxes.append(mailpath)
         subpaths = os.listdir(filepath)
         for subpath in subpaths:
-            #print("Now checking subpath %s in %s" % (subpath, filepath))
             if subpath == "." or subpath == "..":
                 continue
             new_filepath = filepath + "/" + subpath
             if (os.path.isfile(new_filepath)):
                 if os.path.getsize(new_filepath) == 0:
-                    print("Skipping empty file %s." % subpath)
+                    logging.info("Skipping empty file %s" % subpath)
                 else:
                     if MAIL_FILENAME.match(subpath):
-                        #print("Injecting file %s." % subpath)
+                        logging.info("Injecting file %s" % subpath)
                         try:
                             message = self._message_read(new_filepath)
                             # suggest file modification date for internaldate
                             yield (message, mailpath, os.path.getmtime(new_filepath))
-                        except:
-                            print("Could not retrieve mail from file: %s" % new_filepath)                
+                        except IOError:
+                            logging.warning("Could not retrieve mail from the file %s" % new_filepath)
             else:
                 if os.path.isdir(new_filepath):
                     # cyrus ^ vs . storage replacement
                     subpath = subpath.replace("^", ".")
                     new_mailpath = mailpath + "/" + subpath
-                    #print("Inserting mails from directory %s into mailbox %s." % (new_filepath, new_mailpath))
+                    logging.debug("Inserting mails from directory %s into mailbox %s" % (new_filepath, new_mailpath))
                     # load_mails($mboxdbref, $origuser, $targetuser)
                     rcrs_generator = self.load_mails(new_filepath, new_mailpath)
                     # you enter the generator in the for loop
                     for rcr in rcrs_generator:
                         yield rcr
-                    #print("Done with directory %s and mailbox %s." % (new_filepath, new_mailpath))
+                    logging.debug("Done with directory %s and mailbox %s" % (new_filepath, new_mailpath))
         # mark mailboxes that need acl update
         self.acl_mailboxes.append(mailpath)
         return
\ No newline at end of file
index fa1de73..518a8d1 100644 (file)
@@ -4,8 +4,10 @@ restore-mail-inject.py - Tool to inject mails via IMAP
 Copyright (c) 2012 Intra2net AG
 '''
 
+import sys
 import socket, imaplib
 import re
+import logging
 
 MAILBOX_RESP = re.compile(r'\((?P<flags>.*?)\) "(?P<delimiter>.*)" (?P<name>.*)')
 UIDVAL_RESP = re.compile(r'(?P<name>.*) \(UIDVALIDITY (?P<uidval>.*)\)')
@@ -33,26 +35,27 @@ class MailIterator:
             imap_socket.connect("/var/imap/socket/imap")
             self.mail_con.sock = imap_socket
             self.mail_con.file = self.mail_con.sock.makefile('rb')
-            print("Connected to mail server.")
-        except Exception as ex:
-            #raise UserWarning("Could not connect to host: %s" % (ex))
-            raise
+            logging.info("Connected to mail server.")
+        except (self.mail_con.error, socket.error) as ex:
+            logging.error("Could not connect to host: %s" % (ex))
+            sys.exit()
 
         # log in
         try:
             self.mail_con.login("cyrus", "geheim")
             self.logged_in = True
             #self.mail_con.proxyauth(username)
-            print("Logged in as %s." % username)
-        except:
+            logging.info("Logged in as %s." % username)
+        except self.mail_con.error as ex:
             self.logged_in = False
-            raise UserWarning("Could not log in as user " + username)
+            logging.error("Could not log in as user %s: %s" % (username, ex))
+            sys.exit()
 
         # list mailboxes
         try:
             _result, mailboxes = self.mail_con.list()
-        except (self.mail_con.error):
-            raise UserWarning("Could not retrieve mailboxes for user " + username)
+        except self.mail_con.error as ex:
+            logging.warning("Could not retrieve mailboxes for user %s: %s" % (username, ex))
         self.mailboxes = []
         for mailbox in mailboxes:
             mailbox = MAILBOX_RESP.match(mailbox.decode('iso-8859-1')).groups()
@@ -71,17 +74,18 @@ class MailIterator:
         """Resets the inbox acls for a given user."""
         try:
             _result, inbox_acls = self.mail_con.getacl("INBOX")
-        except:
-            print("Could not get the acls of INBOX.")
+        except self.mail_con.error as ex:
+            logging.warning("Could not get the acls of INBOX: %s" % ex)
+            return
         inbox_acls = ACLS_RESP.findall(inbox_acls[0][6:])
-        #print(inbox_acls)
+        logging.debug("Retrieved acls from INBOX are %s" % inbox_acls)
         for acl_ref in inbox_acls:
             if acl_ref[0] != user:
                 try:
-                    self.mail_con.setacl("INBOX", acl_ref[0], "")
-                    print("Reset acls on INBOX for user %s" % acl_ref[0])
-                except:
-                    print("Could not reset acls on INBOX for user %s" % acl_ref[0])
+                    self.mail_con.deleteacl("INBOX", acl_ref[0])
+                    logging.debug("Reset acls on INBOX for user %s" % acl_ref[0].decode('iso-8859-1'))
+                except self.mail_con.error as ex:
+                    logging.warning("Could not reset acls on INBOX for user %s: %s" % (acl_ref[0], ex))
         return
 
     def add_acls(self, mailbox, mailbox_list, original_user, target_user):
@@ -102,9 +106,9 @@ class MailIterator:
             if acl_user != target_user and acl_user != original_user:
                 try:
                     self.mail_con.setacl(mailbox, acl_user, mbox_acls[acl_user])
-                    print("Set acls %s for user %s on mailbox %s." % (mbox_acls[acl_user], acl_user, mailbox))
-                except:
-                    print("Could not set acls %s for user %s on mailbox %s." % (mbox_acls[acl_user], acl_user, mailbox))    
+                    logging.debug("Set acls %s for user %s on mailbox %s" % (mbox_acls[acl_user], acl_user, mailbox))
+                except self.mail_con.error as ex:
+                    logging.warning("Could not set acls %s for user %s on mailbox %s: %s" % (mbox_acls[acl_user], acl_user, mailbox, ex))    
 
         return
 
@@ -118,9 +122,9 @@ class MailIterator:
             if re.compile(pattern).match(mailbox[2]):
                 result, data = self.mail_con.delete(mailbox[2])
                 if result == "OK":
-                    print("Deleted mailbox %s" % mailbox[2])
+                    logging.debug("Deleted mailbox %s" % mailbox[2])
                 else:
-                    print("Could not delete folder %s: %s" % (mailbox[2], data[0]))         
+                    logging.warning("Could not delete mailbox %s: %s" % (mailbox[2], data[0]))         
         return
 
     def create_mailbox(self, mailbox):
@@ -128,16 +132,16 @@ class MailIterator:
         if mailbox != "INBOX":
             result, data = self.mail_con.create(mailbox)
             if result == "OK":
-                print("Creating mailbox %s" % mailbox)
+                logging.debug("Creating mailbox %s" % mailbox)
             else:
-                print("Could not create mailbox %s: %s" % (mailbox, data[0]))
+                logging.warning("Could not create mailbox %s: %s" % (mailbox, data[0]))
         return
 
     def inject_message(self, message, mailbox, internal_date):
         """Inject a message into a mailbox."""
         result, data = self.mail_con.append(mailbox, "\\Seen", internal_date, message.encode())
         if result == "OK":
-            print("Appending message to mailbox %s" % mailbox)
+            logging.debug("Appending message to mailbox %s" % mailbox)
         else:
-            print("Could not append the e-mail %s: %s" % (message, data[0]))
+            logging.warning("Could not append the e-mail %s: %s" % (message, data[0]))
         return
\ No newline at end of file
index 791e380..c67e6ed 100644 (file)
@@ -8,27 +8,28 @@ This program relies on the following assumptions:
 - INBOX maps to user/[username]
 - internal encoding of . etc. as of cyrus 2.2
 '''
-
+import logging
 import argparse
 from mail_iterator import MailIterator
 from file_iterator import FileIterator
 
+LOG_FILENAME = "restore_mail_inject.log"
+LOG_FILE_LEVEL = logging.DEBUG
+LOG_SHELL_LEVEL = logging.INFO
+
 def main():
     """Main function."""
 
     # prepare configuration
     args = configure_args()
-    print("The module restore_mail_inject.py started with user %s, folder %s and source %s." %
+    prepare_logger()
+    logging.info("The module restore_mail_inject.py started with user %s, folder %s and source %s." %
           (args.user, args.folder, args.srcdir))
 
     # connect
-    try:
-        session = MailIterator(args.user)
-        #session = MailIterator("/var/imap/socket/imap", "cyrus", "geheim")
-        storage = FileIterator()
-    except UserWarning as ex:
-        print(ex)
-        return
+    session = MailIterator(args.user)
+    #session = MailIterator("/var/imap/socket/imap", "cyrus", "geheim")
+    storage = FileIterator()
 
     # retrieve mailbox list from the mailbox list file
     mailbox_list = storage.load_mailbox_list(args.mboxlistfile)
@@ -42,26 +43,25 @@ def main():
     # inject emails
     path_generator = storage.load_mails(args.srcdir, args.folder)
     for message, mailbox, date_modified in path_generator:
-        
+
         # mailboxes marked for creating and acl update
         # add acls after all subfolders or their acls will be derived from parent folder
-        #print(storage.created_mailboxes, storage.acl_mailboxes)
         for new_mailbox in storage.created_mailboxes:
             session.create_mailbox(new_mailbox)
         for acl_mailbox in storage.acl_mailboxes:
             session.add_acls(acl_mailbox, mailbox_list, args.ouser, args.user)
         storage.created_mailboxes = []
         storage.acl_mailboxes = []
-        
+
         session.inject_message(message, mailbox, date_modified)
-    
+
     # last iteration mailboxes in case root mailbox has no e-mails for injection
     for new_mailbox in storage.created_mailboxes:
         session.create_mailbox(new_mailbox)
     for acl_mailbox in storage.acl_mailboxes:
         session.add_acls(acl_mailbox, mailbox_list, args.ouser, args.user)
-    
-    print("Finished injecting mails. Exiting.")
+
+    logging.info("Finished injecting mails. Exiting.")
     return
 
 def configure_args():
@@ -89,6 +89,25 @@ def configure_args():
 
     return args
 
+def prepare_logger():
+    """Sets up the logging functionality"""
+
+    # reset the log
+    with open(LOG_FILENAME, 'w'):
+        pass
+
+    # add basic configuration
+    logging.basicConfig(filename=LOG_FILENAME,
+                        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+                        level=LOG_FILE_LEVEL)
+
+    # add a handler for a console output
+    console = logging.StreamHandler()
+    console.setLevel(LOG_SHELL_LEVEL)
+    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+    console.setFormatter(formatter)
+    logging.getLogger('').addHandler(console)
+    return
 
 if __name__ == "__main__":
     main()