--- /dev/null
+'''
+restore-mail-inject.py - Tool to inject mails via IMAP
+
+Copyright (c) 2012 Intra2net AG
+'''
+
+import os
+import re
+
+MAIL_FILENAME = re.compile("^[0-9]+\.$")
+
+class FileIterator:
+ """This class iterates through the e-mail files."""
+
+ # class attributes
+ # mailbox database?
+ mboxdb = None
+ # mailboxes created during file traversal
+ created_mailboxes = None
+ # mailboxes to update during file traversal
+ acl_mailboxes = None
+
+ def __init__(self, mboxlist = ""):
+ """Creates a connection and a user session."""
+ self.mboxdb = []
+ if(mboxlist != ""):
+ try:
+ acl_file = open(mboxlist, 'r')
+ self.mboxdb = self._mbox_read(acl_file)
+ acl_file.close()
+ except IOError:
+ print("Could not open mboxlist file %s." % mboxlist)
+ mboxlist = ""
+ return
+
+ def __del__(self):
+ """Closes the connection and the user session."""
+ return
+
+ def _mbox_read(self, acl_file):
+ "Reads something."
+ #
+ return
+
+ def _message_read(self, filename):
+ """Retrieves a message from the message file."""
+ try:
+ with open(filename, "r") as msgfile:
+ message = msgfile.read()
+ except:
+ print("Could not open the e-mail file %s.", filename)
+ return message
+
+ 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)."""
+ # reset created mailboxes and mailboxes for acl update
+ self.created_mailboxes = []
+ self.acl_mailboxes = []
+ #print("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)
+ 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)
+ else:
+ if(MAIL_FILENAME.match(subpath)):
+ print("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)
+ 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))
+ # 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))
+ # mark mailboxes that need acl update
+ self.acl_mailboxes.append(mailpath)
+ return
+ #
+ #
+ #
\ No newline at end of file
--- /dev/null
+'''
+restore-mail-inject.py - Tool to inject mails via IMAP
+
+Copyright (c) 2012 Intra2net AG
+'''
+
+import imaplib
+import re
+
+MAILBOX_RESP = re.compile(r'\((?P<flags>.*?)\) "(?P<delimiter>.*)" (?P<name>.*)')
+UIDVAL_RESP = re.compile(r'(?P<name>.*) \(UIDVALIDITY (?P<uidval>.*)\)')
+
+class MailIterator:
+ """This class communicates with the e-mail server."""
+
+ # class attributes
+ # IMAP4_SSL for connection with an IMAP server
+ 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."""
+ # authentication
+ try:
+ self.mail_con = imaplib.IMAP4_SSL(server)
+ self.mail_con.login(username, password)
+ print("Logged in as %s." % username)
+ except:
+ self.logged_in = False
+ print("Could not log in as user " + username + ".")
+ raise UserWarning
+ self.logged_in = True
+
+ # prepare mailboxes
+ _result, mailboxes = self.mail_con.list()
+ self.mailboxes = []
+ for mailbox in mailboxes:
+ mailbox = MAILBOX_RESP.match(mailbox.decode('iso-8859-1')).groups()
+ self.mailboxes.append(mailbox)
+ self.mailboxes = sorted(self.mailboxes, key=lambda box: box[2], reverse=True)
+ return
+
+ def __del__(self):
+ """Closes the connection and the user session."""
+ if(self.logged_in):
+ try:
+ self.mail_con.close()
+ self.mail_con.logout()
+ except:
+ pass
+
+ def clear_inbox_acls(self, user):
+ """Resets the inbox acls for each user."""
+ try:
+ hashref = self.mail_con.getacl("INBOX")
+ except:
+ print("Could not get the acls of INBOX.")
+ print(hashref)
+ for acluser in hashref:
+ if(acluser != user):
+ try:
+ #print(self.mail_con.setacl("INBOX", acluser, ""))
+ print("Reset acls on INBOX for user %s" % acluser)
+ except:
+ print("Could not reset acls on INBOX for user %s" % acluser)
+ return
+
+ def add_acls(self, mailbox, config):
+ """Add acls to mailbox."""
+
+ # change encoding to internal cyrus format
+ mailbox = mailbox.replace(".", "^")
+ mailbox = mailbox.replace("/", ".")
+
+ return
+
+ def delete_mailboxes(self, deleted_mailbox):
+ """Delete specified mailbox or empty inbox."""
+ for mailbox in self.mailboxes:
+ pattern = '^\"?' + deleted_mailbox
+ # if INBOX it cannot be deleted so add delimiter
+ if (deleted_mailbox == "INBOX"):
+ pattern += mailbox[1]
+ if(re.compile(pattern).match(mailbox[2])):
+ result, data = self.mail_con.delete(mailbox[2])
+ if(result == "OK"):
+ print("Deleted mailbox %s" % mailbox[2])
+ else:
+ print("Could not delete folder %s: %s" % (mailbox[2], data[0]))
+ return
+
+ def create_mailbox(self, mailbox):
+ """Create new mailbox to inject messages."""
+ if(mailbox != "INBOX"):
+ result, data = self.mail_con.create(mailbox)
+ if(result == "OK"):
+ print("Creating mailbox %s" % mailbox)
+ else:
+ print("Could not create mailbox %s: %s" % (mailbox, data[0]))
+ return
+
+ def inject_message(self, message, mailbox, internal_date):
+ """Inject a message into a mailbox."""
+
+ #$imap->append_file($folder, $full_path, undef, "\\Seen", true)
+ try:
+ result, data = self.mail_con.append(mailbox, "\\Seen",
+ internal_date, message)
+ print("Appending message to mailbox %s" % mailbox)
+ except:
+ raise UserWarning("Could not append the e-mail." % message)
+ return
\ No newline at end of file
--- /dev/null
+'''
+restore-mail-inject.py - Tool to inject mails via IMAP
+
+Copyright (c) 2012 Intra2net AG
+'''
+
+import argparse
+from mail_iterator import MailIterator
+from file_iterator import FileIterator
+
+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." %
+ (args.user, args.folder, args.srcdir))
+
+ # connect
+ try:
+ session = MailIterator("gwt-intranator.m.i2n", "mit.punkt", "mit.punkt")
+ #session = MailIterator("/var/imap/socket/imap", "cyrus", "geheim")
+ storage = FileIterator(args.mboxlist)
+ except UserWarning:
+ print("Couldn't connect to IMAP server.")
+ return
+
+ # delete olf IMAP folders if no append requested
+ if(not args.append):
+ session.delete_mailboxes(args.folder)
+ if(args.folder == "INBOX"):
+ session.clear_inbox_acls(args.user)
+
+ # inject emails
+ path_generator = storage.load_mails(args.srcdir, args.folder)
+ for message, mailbox, date_modified in path_generator:
+ for new_mailbox in storage.created_mailboxes:
+ session.create_mailbox(new_mailbox)
+ for acl_mailbox in storage.acl_mailboxes:
+ session.add_acls(acl_mailbox, args)
+ session.inject_message(message, mailbox, date_modified)
+ # add acls after all subfolders or their acls will be derived from parent folder
+
+ print("Finished injecting mails.")
+
+ return
+
+def configure_args():
+ """Configure arguments and return them."""
+ # parse arguments
+ parser = argparse.ArgumentParser(description="Tool to inject mails via IMAP.")
+ parser.add_argument('-u', '--username', dest='user', action='store',
+ required=True, help='user to store mails to')
+ parser.add_argument('-f', '--foldername', dest='folder', action='store',
+ default="INBOX", help='folder to store mails to - if not specified we overwrite INBOX')
+ parser.add_argument('-s', '--sourcedir', dest='srcdir', action='store',
+ required=True, help='folder to read mail from')
+ parser.add_argument('-m', '--mboxlist', dest='mboxlist', action='store',
+ default="", help='mboxlist file (flat file format) to read the ACLs from')
+ parser.add_argument('-o', '--ouser', dest='ouser', action='store',
+ default="", help='name of the original user (=username if not specified)')
+ parser.add_argument('-a', '--append', dest='append', action='store_true',
+ default=False, help="append mails, don't delete anything")
+ args = parser.parse_args()
+
+ if (args.folder != "INBOX"):
+ args.folder = "INBOX/" + args.folder
+ if (args.ouser == ""):
+ args.ouser = args.user
+
+ return args
+
+
+if(__name__ == "__main__"):
+ main()