comparison src/plugins/plugin_misc_maildir.py @ 257:012c38b56cdd

plugin IMAP, plugin Maildir: profile management - IMAP Login/pass is now checked against profile name/jabber pass - Mailboxes are now per-profile - flags are now checked without case sensitiveness
author Goffi <goffi@goffi.org>
date Tue, 18 Jan 2011 00:57:26 +0100
parents 55b750017b71
children 11f71187d5e4
comparison
equal deleted inserted replaced
256:f5181f6dd98f 257:012c38b56cdd
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 3
4 """ 4 """
5 SAT plugin for managing imap server 5 SàT plugin for managing Maildir type mail boxes
6 Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) 6 Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org)
7 7
8 This program is free software: you can redistribute it and/or modify 8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or 10 the Free Software Foundation, either version 3 of the License, or
31 from email.charset import Charset 31 from email.charset import Charset
32 import os,os.path 32 import os,os.path
33 from cStringIO import StringIO 33 from cStringIO import StringIO
34 from twisted.internet import reactor 34 from twisted.internet import reactor
35 import pdb 35 import pdb
36 from sat.exceptions import *
36 37
37 38
38 from zope.interface import implements 39 from zope.interface import implements
39 40
40 41
59 def __init__(self, host): 60 def __init__(self, host):
60 info(_("Plugin Maildir initialization")) 61 info(_("Plugin Maildir initialization"))
61 self.host = host 62 self.host = host
62 63
63 self.__observed={} 64 self.__observed={}
64 self.__mailboxes={} 65 pList=host.memory.getProfilesList #shorter :)
65 self.data=host.memory.getPrivate("MAILDIR_data") or {"INBOX":{"cur_idx":0}} 66 self.__mailboxes=dict(zip(pList(),len(pList())*[{}]))
67 self.data=host.memory.getPrivate("MAILDIR_data") or dict(zip(pList(),len(pList())*[{"INBOX":{"cur_idx":0}}])) #Create empty box for each profile
66 #a value in the dictionnary for a mailbox is a dictionnary with the following value 68 #a value in the dictionnary for a mailbox is a dictionnary with the following value
67 # - cur_idx: value of the current unique integer increment (UID) 69 # - cur_idx: value of the current unique integer increment (UID)
68 # - message_id (as returned by MaildirMailbox): a tuple of (UID, [flag1, flag2, ...]) 70 # - message_id (as returned by MaildirMailbox): a tuple of (UID, [flag1, flag2, ...])
69 71
70 #the trigger 72 #the trigger
72 74
73 def __del__(self): 75 def __del__(self):
74 debug('Destroying MaildirBox') 76 debug('Destroying MaildirBox')
75 self.host.memory.setPrivate('MAILDIR_data',self.data) 77 self.host.memory.setPrivate('MAILDIR_data',self.data)
76 78
77 def accessMessageBox(self, boxname, observer=None): 79 def accessMessageBox(self, boxname, observer=None, profile_key='@DEFAULT@'):
78 """Create and return a MailboxUser instance 80 """Create and return a MailboxUser instance
79 @param boxname: name of the box 81 @param boxname: name of the box
80 @param observer: method to call when a NewMessage arrive""" 82 @param observer: method to call when a NewMessage arrive"""
81 if not self.__mailboxes.has_key(boxname): 83 profile = self.host.memory.getProfileName(profile_key)
82 self.__mailboxes[boxname]=MailboxUser(self, boxname, observer) 84 if not profile:
85 raise ProfileUnknownError
86 if not self.__mailboxes[profile].has_key(boxname):
87 self.__mailboxes[profile][boxname]=MailboxUser(self, boxname, observer, profile=profile)
83 else: 88 else:
84 if observer: 89 if observer:
85 self.addObserver(observer, boxname) 90 self.addObserver(observer, profile, boxname)
86 return self.__mailboxes[boxname] 91 return self.__mailboxes[profile][boxname]
87 92
88 def _removeBoxAccess(self, boxname, mailboxUser): 93 def _getProfilePath(self, profile):
94 """Return a unique path for profile's mailbox
95 The path must be unique, usable as a dir name, and bijectional"""
96 return profile.replace('/','_').replace('..','_') #FIXME: this is too naive to work well, must be improved
97
98 def _removeBoxAccess(self, boxname, mailboxUser, profile):
89 """Remove a reference to a box 99 """Remove a reference to a box
90 @param name: name of the box 100 @param name: name of the box
91 @param mailboxUser: MailboxUser instance""" 101 @param mailboxUser: MailboxUser instance"""
92 if not self.__mailboxes.has_key(boxname): 102 if not self.__mailboxes.has_key(boxname):
93 err_msg=_("Trying to remove an mailboxUser not referenced") 103 err_msg=_("Trying to remove an mailboxUser not referenced")
94 error(_("INTERNAL ERROR: ") + err_msg) 104 error(_("INTERNAL ERROR: ") + err_msg)
95 raise MaildirError(err_msg) 105 raise MaildirError(err_msg)
96 assert self.__mailboxes[boxname]==mailboxUser 106 assert self.__mailboxes[profile][boxname]==mailboxUser
97 del __mailboxes[boxname] 107 del __mailboxes[profile][boxname]
98 108
99 def _checkBoxReference(self, boxname): 109 def _checkBoxReference(self, boxname, profile):
100 """Check if there is a reference on a box, and return it 110 """Check if there is a reference on a box, and return it
101 @param boxname: name of the box to check 111 @param boxname: name of the box to check
102 @return: MailboxUser instance or None""" 112 @return: MailboxUser instance or None"""
103 if self.__mailboxes.has_key(boxname): 113 if self.__mailboxes.has_key(profile):
104 return self.__mailboxes[boxname] 114 if self.__mailboxes[profile].has_key(boxname):
105 115 return self.__mailboxes[profile][boxname]
106 def __getBoxData(self, boxname): 116
117 def __getBoxData(self, boxname, profile):
107 """Return the date of a box""" 118 """Return the date of a box"""
108 try: 119 try:
109 return self.data[boxname] #the boxname MUST exist in the data 120 return self.data[profile][boxname] #the boxname MUST exist in the data
110 except KeyError: 121 except KeyError:
111 err_msg=_("Boxname doesn't exist in internal data") 122 err_msg=_("Boxname doesn't exist in internal data")
112 error(_("INTERNAL ERROR: ") + err_msg) 123 error(_("INTERNAL ERROR: ") + err_msg)
113 raise MaildirError(err_msg) 124 raise MaildirError(err_msg)
114 125
115 def getUid(self, boxname, message_id): 126 def getUid(self, boxname, message_id, profile):
116 """Return an unique integer, always ascending, for a message 127 """Return an unique integer, always ascending, for a message
117 This is mainly needed for the IMAP protocol 128 This is mainly needed for the IMAP protocol
118 @param boxname: name of the box where the message is 129 @param boxname: name of the box where the message is
119 @param message_id: unique id of the message as given by MaildirMailbox 130 @param message_id: unique id of the message as given by MaildirMailbox
120 @return: Integer UID""" 131 @return: Integer UID"""
121 box_data = self.__getBoxData(boxname) 132 box_data = self.__getBoxData(boxname, profile)
122 if box_data.has_key(message_id): 133 if box_data.has_key(message_id):
123 ret = box_data[message_id][0] 134 ret = box_data[message_id][0]
124 else: 135 else:
125 box_data['cur_idx']+=1 136 box_data['cur_idx']+=1
126 box_data[message_id]=[box_data['cur_idx'],[]] 137 box_data[message_id]=[box_data['cur_idx'],[]]
127 ret = box_data[message_id] 138 ret = box_data[message_id]
128 self.host.memory.setPrivate('MAILDIR_data',self.data) 139 self.host.memory.setPrivate('MAILDIR_data',self.data)
129 return ret 140 return ret
130 141
131 def getNextUid(self, boxname): 142 def getNextUid(self, boxname, profile):
132 """Return next unique integer that will generated 143 """Return next unique integer that will generated
133 This is mainly needed for the IMAP protocol 144 This is mainly needed for the IMAP protocol
134 @param boxname: name of the box where the message is 145 @param boxname: name of the box where the message is
135 @return: Integer UID""" 146 @return: Integer UID"""
136 box_data = self.__getBoxData(boxname) 147 box_data = self.__getBoxData(boxname, profile)
137 return box_data['cur_idx']+1 148 return box_data['cur_idx']+1
138 149
139 def getNextExistingUid(self, boxname, uid): 150 def getNextExistingUid(self, boxname, uid, profile):
140 """Give the next uid of existing message 151 """Give the next uid of existing message
141 @param boxname: name of the box where the message is 152 @param boxname: name of the box where the message is
142 @param uid: uid to start from 153 @param uid: uid to start from
143 @return: uid or None if the is no more message""" 154 @return: uid or None if the is no more message"""
144 box_data = self.__getBoxData(boxname) 155 box_data = self.__getBoxData(boxname, profile)
145 idx=uid+1 156 idx=uid+1
146 while self.getIdFromUid(boxname, idx) == None: #TODO: this is highly inefficient because getIdfromUid is inefficient, fix this 157 while self.getIdFromUid(boxname, idx, profile) == None: #TODO: this is highly inefficient because getIdfromUid is inefficient, fix this
147 idx+=1 158 idx+=1
148 if idx>box_data['cur_idx']: 159 if idx>box_data['cur_idx']:
149 return None 160 return None
150 return idx 161 return idx
151 162
152 def getMaxUid(self, boxname): 163 def getMaxUid(self, boxname, profile):
153 """Give the max existing uid 164 """Give the max existing uid
154 @param boxname: name of the box where the message is 165 @param boxname: name of the box where the message is
155 @return: uid""" 166 @return: uid"""
156 box_data = self.__getBoxData(boxname) 167 box_data = self.__getBoxData(boxname, profile)
157 return box_data['cur_idx'] 168 return box_data['cur_idx']
158 169
159 def getIdFromUid(self, boxname, message_uid): 170 def getIdFromUid(self, boxname, message_uid, profile):
160 """Return the message unique id from it's integer UID 171 """Return the message unique id from it's integer UID
161 @param boxname: name of the box where the message is 172 @param boxname: name of the box where the message is
162 @param message_uid: unique integer identifier 173 @param message_uid: unique integer identifier
163 @return: unique id of the message as given by MaildirMailbox or None if not found""" 174 @return: unique id of the message as given by MaildirMailbox or None if not found"""
164 box_data = self.__getBoxData(boxname) 175 box_data = self.__getBoxData(boxname, profile)
165 for message_id in box_data.keys(): #TODO: this is highly inefficient on big mailbox, must be replaced in the future 176 for message_id in box_data.keys(): #TODO: this is highly inefficient on big mailbox, must be replaced in the future
166 if message_id == 'cur_idx': 177 if message_id == 'cur_idx':
167 continue 178 continue
168 if box_data[message_id][0] == message_uid: 179 if box_data[message_id][0] == message_uid:
169 return message_id 180 return message_id
170 return None 181 return None
171 182
172 def getFlags(self, boxname, mess_id): 183 def getFlags(self, boxname, mess_id, profile):
173 """Return the messages flags 184 """Return the messages flags
174 @param boxname: name of the box where the message is 185 @param boxname: name of the box where the message is
175 @param message_idx: message id as given by MaildirMailbox 186 @param message_idx: message id as given by MaildirMailbox
176 @return: list of strings""" 187 @return: list of strings"""
177 box_data = self.__getBoxData(boxname) 188 box_data = self.__getBoxData(boxname, profile)
178 if not box_data.has_key(mess_id): 189 if not box_data.has_key(mess_id):
179 raise MailboxException("Trying to get flags from an unexisting message") 190 raise MailboxException("Trying to get flags from an unexisting message")
180 return box_data[mess_id][1] 191 return box_data[mess_id][1]
181 192
182 def setFlags(self, boxname, mess_id, flags): 193 def setFlags(self, boxname, mess_id, flags, profile):
183 """Change the flags of the message 194 """Change the flags of the message
184 @param boxname: name of the box where the message is 195 @param boxname: name of the box where the message is
185 @param message_idx: message id as given by MaildirMailbox 196 @param message_idx: message id as given by MaildirMailbox
186 @param flags: list of strings 197 @param flags: list of strings
187 """ 198 """
188 box_data = self.__getBoxData(boxname) 199 box_data = self.__getBoxData(boxname, profile)
189 assert(type(flags)==list) 200 assert(type(flags)==list)
201 flags=[flag.upper() for flag in flags] #we store every flag UPPERCASE
190 if not box_data.has_key(mess_id): 202 if not box_data.has_key(mess_id):
191 raise MailboxException("Trying to set flags for an unexisting message") 203 raise MailboxException("Trying to set flags for an unexisting message")
192 box_data[mess_id][1]=flags 204 box_data[mess_id][1]=flags
193 self.host.memory.setPrivate('MAILDIR_data',self.data) 205 self.host.memory.setPrivate('MAILDIR_data',self.data)
194 206
195 def getMessageIdsWithFlag(self, boxname, flag): 207 def getMessageIdsWithFlag(self, boxname, flag, profile):
196 """Return ids of messages where a flag is set 208 """Return ids of messages where a flag is set
197 @param boxname: name of the box where the message is 209 @param boxname: name of the box where the message is
198 @param flag: flag to check 210 @param flag: flag to check
199 @return: list of id (as given by MaildirMailbox)""" 211 @return: list of id (as given by MaildirMailbox)"""
200 box_data = self.__getBoxData(boxname) 212 box_data = self.__getBoxData(boxname, profile)
201 assert(isinstance(flag,basestring)) 213 assert(isinstance(flag,basestring))
214 flag=flag.upper()
202 result = [] 215 result = []
203 for key in box_data: 216 for key in box_data:
204 if key=='cur_idx': 217 if key=='cur_idx':
205 continue 218 continue
206 if flag in box_data[key][1]: 219 if flag in box_data[key][1]:
207 result.append(key) 220 result.append(key)
208 return result 221 return result
209 222
210 def purgeDeleted(self, boxname): 223 def purgeDeleted(self, boxname, profile):
211 """Remove data for messages with flag "\\Deleted" 224 """Remove data for messages with flag "\\Deleted"
212 @param boxname: name of the box where the message is 225 @param boxname: name of the box where the message is
213 """ 226 """
214 box_data = self.__getBoxData(boxname) 227 box_data = self.__getBoxData(boxname, profile)
215 for mess_id in self.getMessageIdsWithFlag(boxname,"\\Deleted"): 228 for mess_id in self.getMessageIdsWithFlag(boxname,"\\Deleted", profile):
216 del(box_data[mess_id]) 229 del(box_data[mess_id])
217 self.host.memory.setPrivate('MAILDIR_data',self.data) 230 self.host.memory.setPrivate('MAILDIR_data',self.data)
218 231
219 def cleanTable(self, boxname, existant_id): 232 def cleanTable(self, boxname, existant_id, profile):
220 """Remove mails which no longuer exist from the table 233 """Remove mails which no longuer exist from the table
221 @param boxname: name of the box to clean 234 @param boxname: name of the box to clean
222 @param existant_id: list of id which actually exist""" 235 @param existant_id: list of id which actually exist"""
223 box_data = self.__getBoxData(boxname) 236 box_data = self.__getBoxData(boxname, profile)
224 to_remove=[] 237 to_remove=[]
225 for key in box_data: 238 for key in box_data:
226 if key not in existant_id and key!="cur_idx": 239 if key not in existant_id and key!="cur_idx":
227 to_remove.append(key) 240 to_remove.append(key)
228 for key in to_remove: 241 for key in to_remove:
229 del box_data[key] 242 del box_data[key]
230 243
231 244
232 def MessageReceivedTrigger(self, message): 245 def MessageReceivedTrigger(self, message, profile):
233 """This trigger catch normal message and put the in the Maildir box. 246 """This trigger catch normal message and put the in the Maildir box.
234 If the message is not of "normal" type, do nothing 247 If the message is not of "normal" type, do nothing
235 @param message: message xmlstrem 248 @param message: message xmlstrem
236 @return: False if it's a normal message, True else""" 249 @return: False if it's a normal message, True else"""
237 for e in message.elements(): 250 for e in message.elements():
238 if e.name == "body": 251 if e.name == "body":
239 type = message['type'] if message.hasAttribute('type') else 'chat' #FIXME: check specs 252 type = message['type'] if message.hasAttribute('type') else 'chat' #FIXME: check specs
240 if message['type'] != 'normal': 253 if message['type'] != 'normal':
241 return True 254 return True
242 self.accessMessageBox("INBOX").addMessage(message) 255 self.accessMessageBox("INBOX", profile_key=profile).addMessage(message)
243 return False 256 return False
244 257
245 def addObserver(self, callback, boxname, signal="NEW_MESSAGE"): 258 def addObserver(self, callback, profile, boxname, signal="NEW_MESSAGE"):
246 """Add an observer for maildir box changes 259 """Add an observer for maildir box changes
247 @param callback: method to call when the the box is updated 260 @param callback: method to call when the the box is updated
248 @param boxname: name of the box to observe 261 @param boxname: name of the box to observe
249 @param signal: which signal is observed by the caller""" 262 @param signal: which signal is observed by the caller"""
250 if not self.__observed.has_key(boxname): 263 if not self.__observed.has_key((profile,boxname)):
251 self.__observed[boxname]={} 264 self.__observed[(profile,boxname)]={}
252 if not self.__observed[boxname].has_key(signal): 265 if not self.__observed[(profile,boxname)].has_key(signal):
253 self.__observed[boxname][signal]=set() 266 self.__observed[(profile,boxname)][signal]=set()
254 self.__observed[boxname][signal].add(callback) 267 self.__observed[(profile,boxname)][signal].add(callback)
255 268
256 def removeObserver(self, callback, boxname, signal="NEW_MESSAGE"): 269 def removeObserver(self, callback, profile, boxname, signal="NEW_MESSAGE"):
257 """Remove an observer of maildir box changes 270 """Remove an observer of maildir box changes
258 @param callback: method to remove from obervers 271 @param callback: method to remove from obervers
259 @param boxname: name of the box which was observed 272 @param boxname: name of the box which was observed
260 @param signal: which signal was observed by the caller""" 273 @param signal: which signal was observed by the caller"""
261 if not self.__observed.has_key(boxname): 274 if not self.__observed.has_key((profile,boxname)):
262 err_msg=_("Trying to remove an observer for an inexistant mailbox") 275 err_msg=_("Trying to remove an observer for an inexistant mailbox")
263 error(_("INTERNAL ERROR: ") + err_msg) 276 error(_("INTERNAL ERROR: ") + err_msg)
264 raise MaildirError(err_msg) 277 raise MaildirError(err_msg)
265 if not self.__observed[boxname].has_key(signal): 278 if not self.__observed[(profile,boxname)].has_key(signal):
266 err_msg=_("Trying to remove an inexistant observer, no observer for this signal") 279 err_msg=_("Trying to remove an inexistant observer, no observer for this signal")
267 error(_("INTERNAL ERROR: ") + err_msg) 280 error(_("INTERNAL ERROR: ") + err_msg)
268 raise MaildirError(err_msg) 281 raise MaildirError(err_msg)
269 if not callback in self.__observed[boxname][signal]: 282 if not callback in self.__observed[(profile,boxname)][signal]:
270 err_msg=_("Trying to remove an inexistant observer") 283 err_msg=_("Trying to remove an inexistant observer")
271 error(_("INTERNAL ERROR: ") + err_msg) 284 error(_("INTERNAL ERROR: ") + err_msg)
272 raise MaildirError(err_msg) 285 raise MaildirError(err_msg)
273 self.__observed[boxname][signal].remove(callback) 286 self.__observed[(profile,boxname)][signal].remove(callback)
274 287
275 def emitSignal(self, boxname, signal_name): 288 def emitSignal(self, profile, boxname, signal_name):
276 """Emit the signal to observer""" 289 """Emit the signal to observer"""
277 debug('emitSignal %s %s' %(boxname, signal_name)) 290 debug('emitSignal %s %s %s' %(profile, boxname, signal_name))
278 try: 291 try:
279 for observer_cb in self.__observed[boxname][signal_name]: 292 for observer_cb in self.__observed[(profile, boxname)][signal_name]:
280 observer_cb() 293 observer_cb()
281 except KeyError: 294 except KeyError:
282 pass 295 pass
283 296
284 297
302 mail.set_payload(e.children[0].encode('utf-8')) 315 mail.set_payload(e.children[0].encode('utf-8'))
303 elif e.name == "subject": 316 elif e.name == "subject":
304 mail['Subject'] = e.children[0].encode('utf-8') 317 mail['Subject'] = e.children[0].encode('utf-8')
305 return mail.as_string() 318 return mail.as_string()
306 319
307 def __init__(self, _maildir, name, observer=None): 320 def __init__(self, _maildir, name, observer=None, profile="@NONE@"):
308 """@param _maildir: the main MaildirBox instance 321 """@param _maildir: the main MaildirBox instance
309 @param name: name of the mailbox 322 @param name: name of the mailbox
323 @param profile: real profile (ie not a profile_key)
310 THIS OBJECT MUST NOT BE USED DIRECTLY: use MaildirBox.accessMessageBox instead""" 324 THIS OBJECT MUST NOT BE USED DIRECTLY: use MaildirBox.accessMessageBox instead"""
311 if _maildir._checkBoxReference(self): 325 if _maildir._checkBoxReference(name, profile):
312 error ("INTERNAL ERROR: MailboxUser MUST NOT be instancied directly") 326 error ("INTERNAL ERROR: MailboxUser MUST NOT be instancied directly")
313 raise MailboxException('double MailboxUser instanciation') 327 raise MailboxException('double MailboxUser instanciation')
314 if name!="INBOX": 328 if name!="INBOX":
315 raise NotImplementedError 329 raise NotImplementedError
316 self.name=name 330 self.name=name
331 self.profile=profile
317 self.maildir=_maildir 332 self.maildir=_maildir
318 mailbox_path = os.path.expanduser(os.path.join(self.maildir.host.get_const('local_dir'), MAILDIR_PATH)) 333 profile_path = self.maildir._getProfilePath(profile)
334 full_profile_path = os.path.join(os.path.expanduser(self.maildir.host.get_const('local_dir')),profile_path)
335 if not os.path.exists(full_profile_path):
336 os.makedirs(full_profile_path,0700)
337 mailbox_path = os.path.join(full_profile_path, MAILDIR_PATH)
319 self.mailbox_path=mailbox_path 338 self.mailbox_path=mailbox_path
320 self.mailbox = maildir.MaildirMailbox(mailbox_path) 339 self.mailbox = maildir.MaildirMailbox(mailbox_path)
321 self.observer=observer 340 self.observer=observer
322 self.__uid_table_update() 341 self.__uid_table_update()
323 342
324
325 if observer: 343 if observer:
326 debug("adding observer for %s" % name) 344 debug("adding observer for %s (%s)" % (name,profile))
327 self.maildir.addObserver(observer, name, "NEW_MESSAGE") 345 self.maildir.addObserver(observer, profile, name, "NEW_MESSAGE")
328 346
329 def __uid_table_update(self): 347 def __uid_table_update(self):
330 existant_id=[] 348 existant_id=[]
331 for mess_idx in range (self.getMessageCount()): 349 for mess_idx in range (self.getMessageCount()):
332 #we update the uid table 350 #we update the uid table
333 existant_id.append(self.getId(mess_idx)) 351 existant_id.append(self.getId(mess_idx))
334 self.getUid(mess_idx) 352 self.getUid(mess_idx)
335 self.maildir.cleanTable(self.name, existant_id) 353 self.maildir.cleanTable(self.name, existant_id, profile=self.profile)
336 354
337 355
338 def __del__(self): 356 def __del__(self):
339 if observer: 357 if observer:
340 debug("removing observer for %s" % self.name) 358 debug("removing observer for %s" % self.name)
341 self._maildir.removeObserver(observer, self.name, "NEW_MESSAGE") 359 self._maildir.removeObserver(observer, self.name, "NEW_MESSAGE")
342 self._maildir._removeBoxAccess(self.name, self) 360 self.maildir._removeBoxAccess(self.name, self, profile=self.profile)
343 361
344 def addMessage(self, message): 362 def addMessage(self, message):
345 """Add a message to the box 363 """Add a message to the box
346 @param message: XMPP XML message""" 364 @param message: XMPP XML message"""
347 self.mailbox.appendMessage(self.xmppMessage2mail(message)).addCallback(self.emitSignal, "NEW_MESSAGE") 365 self.mailbox.appendMessage(self.xmppMessage2mail(message)).addCallback(self.emitSignal, "NEW_MESSAGE")
348 366
349 def emitSignal(self, ignore, signal): 367 def emitSignal(self, ignore, signal):
350 """Emit the signal to the observers""" 368 """Emit the signal to the observers"""
351 self.getUid(self.getMessageCount()-1) #we make an uid for the last message added 369 if signal=="NEW_MESSAGE":
352 self.maildir.emitSignal(self.name, signal) 370 self.getUid(self.getMessageCount()-1) #XXX: we make an uid for the last message added
371 self.maildir.emitSignal(self.profile, self.name, signal)
353 372
354 def getId(self, mess_idx): 373 def getId(self, mess_idx):
355 """Return the Unique ID of the message 374 """Return the Unique ID of the message
356 @mess_idx: message index""" 375 @mess_idx: message index"""
357 return self.mailbox.getUidl(mess_idx) 376 return self.mailbox.getUidl(mess_idx)
358 377
359 def getUid(self, mess_idx): 378 def getUid(self, mess_idx):
360 """Return a unique interger id for the message, always ascending""" 379 """Return a unique interger id for the message, always ascending"""
361 mess_id=self.getId(mess_idx) 380 mess_id=self.getId(mess_idx)
362 return self.maildir.getUid(self.name,mess_id) 381 return self.maildir.getUid(self.name,mess_id, profile=self.profile)
363 382
364 def getNextUid(self): 383 def getNextUid(self):
365 return self.maildir.getNextUid(self.name) 384 return self.maildir.getNextUid(self.name, profile=self.profile)
366 385
367 def getNextExistingUid(self, uid): 386 def getNextExistingUid(self, uid):
368 return self.maildir.getNextExistingUid(self.name, uid) 387 return self.maildir.getNextExistingUid(self.name, uid, profile=self.profile)
369 388
370 def getMaxUid(self): 389 def getMaxUid(self):
371 return self.maildir.getMaxUid(self.name) 390 return self.maildir.getMaxUid(self.name, profile=self.profile)
372 391
373 def getMessageCount(self): 392 def getMessageCount(self):
374 """Return number of mails present in this box""" 393 """Return number of mails present in this box"""
375 return len(self.mailbox.list) 394 return len(self.mailbox.list)
376 395
410 def getFlags(self, mess_idx): 429 def getFlags(self, mess_idx):
411 """Return the flags of the message 430 """Return the flags of the message
412 @param mess_idx: message index 431 @param mess_idx: message index
413 @return: list of strings""" 432 @return: list of strings"""
414 id = self.getId(mess_idx) 433 id = self.getId(mess_idx)
415 return self.maildir.getFlags(self.name, id) 434 return self.maildir.getFlags(self.name, id, profile=self.profile)
416 435
417 def getFlagsUid(self, mess_uid): 436 def getFlagsUid(self, mess_uid):
418 """Return the flags of the message 437 """Return the flags of the message
419 @param mess_uid: message unique identifier 438 @param mess_uid: message unique identifier
420 @return: list of strings""" 439 @return: list of strings"""
421 id = self.maildir.getIdFromUid(self.name,mess_uid) 440 id = self.maildir.getIdFromUid(self.name,mess_uid, profile=self.profile)
422 return self.maildir.getFlags(self.name, id) 441 return self.maildir.getFlags(self.name, id, profile=self.profile)
423 442
424 def setFlags(self, mess_idx, flags): 443 def setFlags(self, mess_idx, flags):
425 """Change the flags of the message 444 """Change the flags of the message
426 @param mess_idx: message index 445 @param mess_idx: message index
427 @param flags: list of strings 446 @param flags: list of strings
428 """ 447 """
429 id = self.getId(mess_idx) 448 id = self.getId(mess_idx)
430 return self.maildir.setFlags(self.name, id, flags) 449 self.maildir.setFlags(self.name, id, flags, profile=self.profile)
431 450
432 def setFlagsUid(self, mess_uid, flags): 451 def setFlagsUid(self, mess_uid, flags):
433 """Change the flags of the message 452 """Change the flags of the message
434 @param mess_uid: message unique identifier 453 @param mess_uid: message unique identifier
435 @param flags: list of strings 454 @param flags: list of strings
436 """ 455 """
437 id = self.maildir.getIdFromUid(self.name,mess_uid) 456 id = self.maildir.getIdFromUid(self.name,mess_uid, profile=self.profile)
438 return self.maildir.setFlags(self.name, id, flags) 457 return self.maildir.setFlags(self.name, id, flags, profile=self.profile)
439 458
440 def getMessageIdsWithFlag(self, flag): 459 def getMessageIdsWithFlag(self, flag):
441 """Return ids of messages where a flag is set 460 """Return ids of messages where a flag is set
442 @param flag: flag to check 461 @param flag: flag to check
443 @return: list of id (as given by MaildirMailbox)""" 462 @return: list of id (as given by MaildirMailbox)"""
444 return self.maildir.getMessageIdsWithFlag(self.name,flag) 463 return self.maildir.getMessageIdsWithFlag(self.name,flag, profile=self.profile)
445 464
446 def removeDeleted(self): 465 def removeDeleted(self):
447 """Actually delete message flagged "\\Deleted" 466 """Actually delete message flagged "\\Deleted"
448 Also purge the internal data of these messages 467 Also purge the internal data of these messages
449 """ 468 """
450 for mess_id in self.getMessageIdsWithFlag("\\Deleted"): 469 for mess_id in self.getMessageIdsWithFlag("\\Deleted"):
451 print ("Deleting %s", mess_id) 470 print ("Deleting %s", mess_id)
452 self.mailbox.deleteMessage(self.getIdxFromId(mess_id)) 471 self.mailbox.deleteMessage(self.getIdxFromId(mess_id))
453 self.mailbox = maildir.MaildirMailbox(self.mailbox_path) #We need to reparse the dir to have coherent indexing 472 self.mailbox = maildir.MaildirMailbox(self.mailbox_path) #We need to reparse the dir to have coherent indexing
454 self.maildir.purgeDeleted(self.name) 473 self.maildir.purgeDeleted(self.name, profile=self.profile)
455 474
456 def emptyTrash(self): 475 def emptyTrash(self):
457 """Delete everything in the .Trash dir""" 476 """Delete everything in the .Trash dir"""
458 import shutils 477 import shutils
459 pdb.set_trace() 478 pdb.set_trace()