File and console logging added for exception handling and information
[imap-restore-mail] / file_iterator.py
... / ...
CommitLineData
1'''
2restore-mail-inject.py - Tool to inject mails via IMAP
3
4Copyright (c) 2012 Intra2net AG
5'''
6
7import sys, os
8import re
9import logging
10
11MAIL_FILENAME = re.compile("^[0-9]+\.$")
12MBOXFILE_LINE = re.compile("^(.*?)\t(?:\d )?default[\t ](.*)$")
13ACL_STRING = re.compile("^(.*?)[\t ](.*?)\t(.*)$")
14
15class FileIterator:
16 """This class iterates through the e-mail files."""
17
18 # class attributes
19 # mailboxes created during file traversal
20 created_mailboxes = None
21 # mailboxes to update during file traversal
22 acl_mailboxes = None
23
24 def __init__(self):
25 """Creates a connection and a user session."""
26 self.created_mailboxes = []
27 self.acl_mailboxes = []
28 return
29
30 def __del__(self):
31 """Closes the connection and the user session."""
32 return
33
34 def _message_read(self, filename):
35 """Retrieves a message from the message file."""
36 try:
37 with open(filename, "r") as msgfile:
38 message = msgfile.read()
39 except IOError:
40 logging.warning("Could not open the e-mail file %s", filename)
41 raise
42 return message
43
44 def load_mailbox_list(self, mboxlistfile = ""):
45 mboxdb = {}
46 if mboxlistfile != "":
47 try:
48 with open(mboxlistfile, 'r') as acl_file:
49 for line in acl_file:
50 acls = {}
51 linedata = MBOXFILE_LINE.match(line).groups()
52 #!!! test this condition
53 if len(linedata) == 0:
54 logging.warning("Illegal line in mailbox list dump: %s" % line)
55 continue
56 key = linedata[0]
57 aclstr = linedata[1]
58
59 # loop through acl rights string and build dictionary of users and rights
60 while(aclstr != ""):
61 acldata = ACL_STRING.match(aclstr).groups()
62 if len(acldata) == 0:
63 logging.error("Illegal acl string in mailbox list dump: %s" % line)
64 continue
65 aclstr = acldata[2]
66 acls[acldata[0]]=acldata[1]
67
68 mboxdb[key] = acls
69 except IOError:
70 logging.warning("Could not open mboxlist file %s" % mboxlistfile)
71 return mboxdb
72
73 def load_mails(self, filepath, mailpath):
74 """Loads all e-mails from file hierarchy.
75 This recursive generator always returns a tuple of
76 the next found (e-mail, mailbox to store, internaldate)."""
77 logging.debug("Entered directory %s -> %s" % (filepath, mailpath))
78 try:
79 filepath = os.path.abspath(filepath)
80 os.chdir(filepath)
81 except OSError:
82 logging.warning("Can't open the directory %s" % filepath)
83 return
84 # mark mailboxes that should be created
85 self.created_mailboxes.append(mailpath)
86 subpaths = os.listdir(filepath)
87 for subpath in subpaths:
88 if subpath == "." or subpath == "..":
89 continue
90 new_filepath = filepath + "/" + subpath
91 if (os.path.isfile(new_filepath)):
92 if os.path.getsize(new_filepath) == 0:
93 logging.info("Skipping empty file %s" % subpath)
94 else:
95 if MAIL_FILENAME.match(subpath):
96 logging.info("Injecting file %s" % subpath)
97 try:
98 message = self._message_read(new_filepath)
99 # suggest file modification date for internaldate
100 yield (message, mailpath, os.path.getmtime(new_filepath))
101 except IOError:
102 logging.warning("Could not retrieve mail from the file %s" % new_filepath)
103 else:
104 if os.path.isdir(new_filepath):
105 # cyrus ^ vs . storage replacement
106 subpath = subpath.replace("^", ".")
107 new_mailpath = mailpath + "/" + subpath
108 logging.debug("Inserting mails from directory %s into mailbox %s" % (new_filepath, new_mailpath))
109 # load_mails($mboxdbref, $origuser, $targetuser)
110 rcrs_generator = self.load_mails(new_filepath, new_mailpath)
111 # you enter the generator in the for loop
112 for rcr in rcrs_generator:
113 yield rcr
114 logging.debug("Done with directory %s and mailbox %s" % (new_filepath, new_mailpath))
115 # mark mailboxes that need acl update
116 self.acl_mailboxes.append(mailpath)
117 return