Connection error handling and some formatting
[imap-restore-mail] / mail_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 imaplib
8 import re
9
10 MAILBOX_RESP = re.compile(r'\((?P<flags>.*?)\) "(?P<delimiter>.*)" (?P<name>.*)')
11 UIDVAL_RESP = re.compile(r'(?P<name>.*) \(UIDVALIDITY (?P<uidval>.*)\)')
12 ACLS_RESP = re.compile(r'(?P<name>.*) \(UIDVALIDITY (?P<uidval>.*)\)')
13
14 class MailIterator:
15     """This class communicates with the e-mail server."""
16
17     # class attributes
18     # IMAP4_SSL for connection with an IMAP server
19     mail_con = None
20     # list of tuples (uidvalidity, mailboxname) for the retrieved mailboxes
21     mailboxes = None
22     # logged in status
23     logged_in = None
24
25     def __init__(self, server, username, password):
26         """Creates a connection and a user session."""
27         
28         # connect to server
29         try:
30             self.mail_con = imaplib.IMAP4_SSL(server)
31             print("Connected to %s." % server)
32         except Exception as ex:
33             raise UserWarning("Could not connect to host %s: %s" % (server, ex))
34
35         # log in
36         try:
37             self.mail_con.login(username, password)
38             self.logged_in = True
39             print("Logged in as %s." % username)
40         except:
41             self.logged_in = False
42             raise UserWarning("Could not log in as user " + username)
43             
44         # list mailboxes
45         try:
46             _result, mailboxes = self.mail_con.list()
47         except (self.mail_con.error):
48             raise UserWarning("Could not retrieve mailboxes for user " + username)
49         self.mailboxes = []
50         for mailbox in mailboxes:
51             mailbox = MAILBOX_RESP.match(mailbox.decode('iso-8859-1')).groups()
52             self.mailboxes.append(mailbox)
53         self.mailboxes = sorted(self.mailboxes, key=lambda box: box[2], reverse=True)
54         
55         return
56
57     def __del__(self):
58         """Closes the connection and the user session."""
59         #if self.logged_in:
60         #    self.mail_con.close()
61         #    self.mail_con.logout()
62
63     def clear_inbox_acls(self, user):
64         """Resets the inbox acls for a given user."""
65         try:
66             _result, inbox_acls = self.mail_con.getacl("INBOX")
67         except:
68             print("Could not get the acls of INBOX.")
69         inbox_acls = inbox_acls[0].split(' ')[1:]
70         for acl_user in inbox_acls:
71             if acl_user != user:
72                 try:
73                     self.mail_con.setacl("INBOX", acl_user, "")
74                     print("Reset acls on INBOX for user %s" % acl_user)
75                 except:
76                     print("Could not reset acls on INBOX for user %s" % acl_user)
77         return
78
79     def add_acls(self, mailbox, mailbox_list, original_user, target_user):
80         """Add acls to mailbox."""
81
82         # change encoding to internal cyrus format and make folder absolute
83         mailbox = mailbox.replace("INBOX/", "user/" + original_user + "/")
84         mailbox = mailbox.replace(".", "^")
85         mailbox = mailbox.replace("/", ".")
86
87         # find folder to set all acls
88         try:
89             mbox_acls = mailbox_list[mailbox]
90         except KeyError:
91             # no rights for the mailbox were found
92             return
93         for acl_user in mbox_acls:
94             if acl_user != target_user and acl_user != original_user:
95                 try:
96                     self.mail_con.setacl(mailbox, acl_user, mbox_acls[acl_user])
97                     print("Set acls %s for user %s on mailbox %s." % (mbox_acls[acl_user], acl_user, mailbox))
98                 except:
99                     print("Could not set acls %s for user %s on mailbox %s." % (mbox_acls[acl_user], acl_user, mailbox))    
100
101         return
102
103     def delete_mailboxes(self, deleted_mailbox):
104         """Delete specified mailbox or empty inbox."""
105         for mailbox in self.mailboxes:
106             pattern = '^\"?' + deleted_mailbox
107             # if INBOX it cannot be deleted so add delimiter
108             if (deleted_mailbox == "INBOX"):
109                 pattern += mailbox[1]
110             if re.compile(pattern).match(mailbox[2]):
111                 result, data = self.mail_con.delete(mailbox[2])
112                 if result == "OK":
113                     print("Deleted mailbox %s" % mailbox[2])
114                 else:
115                     print("Could not delete folder %s: %s" % (mailbox[2], data[0]))         
116         return
117
118     def create_mailbox(self, mailbox):
119         """Create new mailbox to inject messages."""
120         if mailbox != "INBOX":
121             result, data = self.mail_con.create(mailbox)
122             if result == "OK":
123                 print("Creating mailbox %s" % mailbox)
124             else:
125                 print("Could not create mailbox %s: %s" % (mailbox, data[0]))
126         return
127
128     def inject_message(self, message, mailbox, internal_date):
129         """Inject a message into a mailbox."""
130         result, data = self.mail_con.append(mailbox, "\\Seen", internal_date, message)
131         if result == "OK":
132             print("Appending message to mailbox %s" % mailbox)
133         else:
134             print("Could not append the e-mail %s: %s" % (message, data[0]))
135         return