Modules now in 'src' folder, COPYING and README added
[imap-restore-mail] / src / imap_restore_mail.py
1 '''
2 restore-mail-inject.py - Tool to inject mails via IMAP
3
4 Copyright (c) 2012 Intra2net AG
5 Author: Plamen Dimitrov and Thomas Jarosch
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 import logging
18 import argparse
19 from mail_iterator import MailIterator
20 from file_iterator import FileIterator
21 from warnings_handler import WarningsHandler
22
23 # logging settings
24 LOG_FILENAME = "restore_mail_inject.log"
25 LOG_FILE_LEVEL = logging.DEBUG
26 LOG_SHELL_LEVEL = logging.INFO
27 LOG_UNCLEAN_EXIT_LEVEL = logging.WARNING
28
29 def main():
30     """Main function."""
31
32     # prepare configuration
33     args = configure_args()
34     warnings_handler = prepare_logger()
35     logging.info("The module restore_mail_inject.py started with user %s, folder %s and source %s.",
36           args.user, args.folder, args.srcdir)
37
38     # connect to unix socket or server
39     if(args.unix_socket_disabled):
40         session = MailIterator(args.user)
41     else:
42         session = MailIterator(args.user)
43         #session = MailIterator("/var/imap/socket/imap", "cyrus", "geheim")
44     storage = FileIterator()
45
46     # retrieve mailbox list from the mailbox list file
47     mailbox_list = storage.load_mailbox_list(args.mboxlistfile)
48
49     # delete olf IMAP folders if no append requested
50     if not args.append:
51         session.delete_mailboxes(args.folder)
52         if args.folder == "INBOX":
53             session.clear_inbox_acls(args.user)
54
55     # inject emails
56     path_generator = storage.load_mails(args.srcdir, args.folder)
57     for message, mailbox, date_modified in path_generator:
58
59         # mailboxes marked for creating and acl update
60         # add acls after all subfolders or their acls will be derived from parent folder
61         for new_mailbox in storage.created_mailboxes:
62             session.create_mailbox(new_mailbox)
63         for acl_mailbox in storage.acl_mailboxes:
64             session.add_acls(acl_mailbox, mailbox_list, args.ouser, args.user)
65         storage.created_mailboxes = []
66         storage.acl_mailboxes = []
67
68         session.inject_message(message, mailbox, date_modified)
69
70     # last iteration mailboxes in case root mailbox has no e-mails for injection
71     for new_mailbox in storage.created_mailboxes:
72         session.create_mailbox(new_mailbox)
73     for acl_mailbox in storage.acl_mailboxes:
74         session.add_acls(acl_mailbox, mailbox_list, args.ouser, args.user)
75
76     logging.info("Finished injecting mails. Exiting with code %s.", warnings_handler.detected_problems)
77     return warnings_handler.detected_problems
78
79 def configure_args():
80     """Configure arguments and return them."""
81
82     # parse arguments
83     parser = argparse.ArgumentParser(description="Tool to inject mails via IMAP.")
84     parser.add_argument('-u', '--username', dest='user', action='store',
85                         required=True, help='user to store mails to')
86     parser.add_argument('-f', '--foldername', dest='folder', action='store',
87                         default="INBOX", help='folder to store mails to - if not specified we overwrite INBOX')
88     parser.add_argument('-s', '--sourcedir', dest='srcdir', action='store',
89                         required=True, help='folder to read mail from')
90     parser.add_argument('-m', '--mboxlistfile', dest='mboxlistfile', action='store',
91                         default="", help='mboxlist file (flat file format) to read the ACLs from')
92     parser.add_argument('-o', '--ouser', dest='ouser', action='store',
93                         default="", help='name of the original user (=username if not specified)')
94     parser.add_argument('-a', '--append', dest='append', action='store_true',
95                         default=False, help="append mails, don't delete anything")
96     parser.add_argument('-n', '--normal', dest='unix_socket_disabled', action='store_true',
97                         default=False, help='disable unix socket usage for the IMAP connection')
98     args = parser.parse_args()
99
100     if (args.folder != "INBOX"):
101         args.folder = "INBOX/" + args.folder
102     if (args.ouser == ""):
103         args.ouser = args.user
104
105     return args
106
107 def prepare_logger():
108     """Sets up the logging functionality"""
109
110     # reset the log
111     with open(LOG_FILENAME, 'w'):
112         pass
113
114     # add basic configuration
115     logging.basicConfig(filename=LOG_FILENAME,
116                         format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
117                         level=LOG_FILE_LEVEL)
118
119     # add a handler for a console output
120     default_logger = logging.getLogger('')
121     console = logging.StreamHandler()
122     console.setLevel(LOG_SHELL_LEVEL)
123     formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
124     console.setFormatter(formatter)
125     default_logger.addHandler(console)
126
127     # add a handler for warnings counting
128     warnings_handler = WarningsHandler()
129     warnings_handler.setLevel(LOG_UNCLEAN_EXIT_LEVEL)
130     default_logger.addHandler(warnings_handler)
131
132     return warnings_handler
133
134 if __name__ == "__main__":
135     main()