5c3512d085a74bb3395b27ebef9f53c4b4349b13
[imap-restore-mail] / file_iterator.py
1 '''
2 restore-mail-inject.py - Tool to inject mails via IMAP
3
4 Copyright (c) 2012 Intra2net AG
5 '''
6
7 import sys, os
8 import re
9
10 MAIL_FILENAME = re.compile("^[0-9]+\.$")
11 MBOXFILE_LINE = re.compile("^(.*?)\t(?:\d )?default[\t ](.*)$")
12 ACL_STRING = re.compile("^(.*?)[\t ](.*?)\t(.*)$")
13
14 class FileIterator:
15     """This class iterates through the e-mail files."""
16
17     # class attributes
18     # mailboxes created during file traversal
19     created_mailboxes = None
20     # mailboxes to update during file traversal
21     acl_mailboxes = None
22
23     def __init__(self):
24         """Creates a connection and a user session."""
25         self.created_mailboxes = []
26         self.acl_mailboxes = []
27         return
28
29     def __del__(self):
30         """Closes the connection and the user session."""
31         return
32
33     def _message_read(self, filename):
34         """Retrieves a message from the message file."""
35         try:
36             with open(filename, "r") as msgfile:
37                 message = msgfile.read()
38         except:
39             print("Could not open the e-mail file %s.", filename)
40         return message
41
42     def load_mailbox_list(self, mboxlistfile = ""):
43         mboxdb = {}
44         if mboxlistfile != "":
45             try:
46                 with open(mboxlistfile, 'r') as acl_file:
47                     for line in acl_file:
48                         acls = {}
49                         linedata = MBOXFILE_LINE.match(line).groups()
50                         #!!! test this condition
51                         if len(linedata) == 0:
52                             print("Illegal line in mailbox list dump: %s" % line)
53                             sys.exit()
54                         key = linedata[0]
55                         aclstr = linedata[1]
56                         
57                         # loop through acl rights string and build dictionary of users and rights
58                         while(aclstr != ""):
59                             acldata = ACL_STRING.match(aclstr).groups()
60                             if len(acldata) == 0:
61                                 print("Illegal line in mailbox list dump: %s" % line)
62                                 sys.exit()                               
63                             aclstr = acldata[2]
64                             acls[acldata[0]]=acldata[1]
65
66                         mboxdb[key] = acls
67
68             except IOError:
69                 print("Could not open mboxlist file %s." % mboxlistfile)
70         return mboxdb
71
72     def load_mails(self, filepath, mailpath):
73         """Loads all e-mails from file hierarchy.
74         This recursive generator always returns a tuple of
75         the next found (e-mail, mailbox to store, internaldate)."""
76         #print("Entered directory %s -> %s." % (filepath, mailpath))
77         try:
78             filepath = os.path.abspath(filepath)
79             os.chdir(filepath)
80         except OSError:
81             print("Can't open the directory %s." % filepath)
82             return
83         # mark mailboxes that should be created
84         self.created_mailboxes.append(mailpath)
85         subpaths = os.listdir(filepath)
86         for subpath in subpaths:
87             #print("Now checking subpath %s in %s" % (subpath, filepath))
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                     print("Skipping empty file %s." % subpath)
94                 else:
95                     if MAIL_FILENAME.match(subpath):
96                         #print("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:
102                             print("Could not retrieve mail from 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                     #print("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                     #print("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