comparison sat/plugins/plugin_misc_maildir.py @ 3028:ab2696e34d29

Python 3 port: /!\ this is a huge commit /!\ starting from this commit, SàT is needs Python 3.6+ /!\ SàT maybe be instable or some feature may not work anymore, this will improve with time This patch port backend, bridge and frontends to Python 3. Roughly this has been done this way: - 2to3 tools has been applied (with python 3.7) - all references to python2 have been replaced with python3 (notably shebangs) - fixed files not handled by 2to3 (notably the shell script) - several manual fixes - fixed issues reported by Python 3 that where not handled in Python 2 - replaced "async" with "async_" when needed (it's a reserved word from Python 3.7) - replaced zope's "implements" with @implementer decorator - temporary hack to handle data pickled in database, as str or bytes may be returned, to be checked later - fixed hash comparison for password - removed some code which is not needed anymore with Python 3 - deactivated some code which needs to be checked (notably certificate validation) - tested with jp, fixed reported issues until some basic commands worked - ported Primitivus (after porting dependencies like urwid satext) - more manual fixes
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:08:41 +0200
parents 26edcf3a30eb
children
comparison
equal deleted inserted replaced
3027:ff5bcb12ae60 3028:ab2696e34d29
1 #!/usr/bin/env python2 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 3
4 # SàT plugin for managing Maildir type mail boxes 4 # SàT plugin for managing Maildir type mail boxes
5 # Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) 5 # Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org)
6 6
137 """Remove a reference to a box 137 """Remove a reference to a box
138 @param name: name of the box 138 @param name: name of the box
139 @param mailboxUser: MailboxUser instance""" 139 @param mailboxUser: MailboxUser instance"""
140 if boxname not in self.__mailboxes: 140 if boxname not in self.__mailboxes:
141 err_msg = _("Trying to remove an mailboxUser not referenced") 141 err_msg = _("Trying to remove an mailboxUser not referenced")
142 log.error(_(u"INTERNAL ERROR: ") + err_msg) 142 log.error(_("INTERNAL ERROR: ") + err_msg)
143 raise MaildirError(err_msg) 143 raise MaildirError(err_msg)
144 assert self.__mailboxes[profile][boxname] == mailboxUser 144 assert self.__mailboxes[profile][boxname] == mailboxUser
145 del self.__mailboxes[profile][boxname] 145 del self.__mailboxes[profile][boxname]
146 146
147 def _checkBoxReference(self, boxname, profile): 147 def _checkBoxReference(self, boxname, profile):
156 """Return the date of a box""" 156 """Return the date of a box"""
157 try: 157 try:
158 return self.data[profile][boxname] # the boxname MUST exist in the data 158 return self.data[profile][boxname] # the boxname MUST exist in the data
159 except KeyError: 159 except KeyError:
160 err_msg = _("Boxname doesn't exist in internal data") 160 err_msg = _("Boxname doesn't exist in internal data")
161 log.error(_(u"INTERNAL ERROR: ") + err_msg) 161 log.error(_("INTERNAL ERROR: ") + err_msg)
162 raise MaildirError(err_msg) 162 raise MaildirError(err_msg)
163 163
164 def getUid(self, boxname, message_id, profile): 164 def getUid(self, boxname, message_id, profile):
165 """Return an unique integer, always ascending, for a message 165 """Return an unique integer, always ascending, for a message
166 This is mainly needed for the IMAP protocol 166 This is mainly needed for the IMAP protocol
209 """Return the message unique id from it's integer UID 209 """Return the message unique id from it's integer UID
210 @param boxname: name of the box where the message is 210 @param boxname: name of the box where the message is
211 @param message_uid: unique integer identifier 211 @param message_uid: unique integer identifier
212 @return: unique id of the message as given by MaildirMailbox or None if not found""" 212 @return: unique id of the message as given by MaildirMailbox or None if not found"""
213 box_data = self.__getBoxData(boxname, profile) 213 box_data = self.__getBoxData(boxname, profile)
214 for message_id in box_data.keys(): # TODO: this is highly inefficient on big mailbox, must be replaced in the future 214 for message_id in list(box_data.keys()): # TODO: this is highly inefficient on big mailbox, must be replaced in the future
215 if message_id == 'cur_idx': 215 if message_id == 'cur_idx':
216 continue 216 continue
217 if box_data[message_id][0] == message_uid: 217 if box_data[message_id][0] == message_uid:
218 return message_id 218 return message_id
219 return None 219 return None
246 """Return ids of messages where a flag is set 246 """Return ids of messages where a flag is set
247 @param boxname: name of the box where the message is 247 @param boxname: name of the box where the message is
248 @param flag: flag to check 248 @param flag: flag to check
249 @return: list of id (as given by MaildirMailbox)""" 249 @return: list of id (as given by MaildirMailbox)"""
250 box_data = self.__getBoxData(boxname, profile) 250 box_data = self.__getBoxData(boxname, profile)
251 assert(isinstance(flag, basestring)) 251 assert(isinstance(flag, str))
252 flag = flag.upper() 252 flag = flag.upper()
253 result = [] 253 result = []
254 for key in box_data: 254 for key in box_data:
255 if key == 'cur_idx': 255 if key == 'cur_idx':
256 continue 256 continue
294 """Remove an observer of maildir box changes 294 """Remove an observer of maildir box changes
295 @param callback: method to remove from obervers 295 @param callback: method to remove from obervers
296 @param boxname: name of the box which was observed 296 @param boxname: name of the box which was observed
297 @param signal: which signal was observed by the caller""" 297 @param signal: which signal was observed by the caller"""
298 if (profile, boxname) not in self.__observed: 298 if (profile, boxname) not in self.__observed:
299 err_msg = _(u"Trying to remove an observer for an inexistant mailbox") 299 err_msg = _("Trying to remove an observer for an inexistant mailbox")
300 log.error(_(u"INTERNAL ERROR: ") + err_msg) 300 log.error(_("INTERNAL ERROR: ") + err_msg)
301 raise MaildirError(err_msg) 301 raise MaildirError(err_msg)
302 if signal not in self.__observed[(profile, boxname)]: 302 if signal not in self.__observed[(profile, boxname)]:
303 err_msg = _(u"Trying to remove an inexistant observer, no observer for this signal") 303 err_msg = _("Trying to remove an inexistant observer, no observer for this signal")
304 log.error(_(u"INTERNAL ERROR: ") + err_msg) 304 log.error(_("INTERNAL ERROR: ") + err_msg)
305 raise MaildirError(err_msg) 305 raise MaildirError(err_msg)
306 if not callback in self.__observed[(profile, boxname)][signal]: 306 if not callback in self.__observed[(profile, boxname)][signal]:
307 err_msg = _(u"Trying to remove an inexistant observer") 307 err_msg = _("Trying to remove an inexistant observer")
308 log.error(_(u"INTERNAL ERROR: ") + err_msg) 308 log.error(_("INTERNAL ERROR: ") + err_msg)
309 raise MaildirError(err_msg) 309 raise MaildirError(err_msg)
310 self.__observed[(profile, boxname)][signal].remove(callback) 310 self.__observed[(profile, boxname)][signal].remove(callback)
311 311
312 def emitSignal(self, profile, boxname, signal_name): 312 def emitSignal(self, profile, boxname, signal_name):
313 """Emit the signal to observer""" 313 """Emit the signal to observer"""
314 log.debug(u'emitSignal %s %s %s' % (profile, boxname, signal_name)) 314 log.debug('emitSignal %s %s %s' % (profile, boxname, signal_name))
315 try: 315 try:
316 for observer_cb in self.__observed[(profile, boxname)][signal_name]: 316 for observer_cb in self.__observed[(profile, boxname)][signal_name]:
317 observer_cb() 317 observer_cb()
318 except KeyError: 318 except KeyError:
319 pass 319 pass
345 """@param _maildir: the main MaildirBox instance 345 """@param _maildir: the main MaildirBox instance
346 @param name: name of the mailbox 346 @param name: name of the mailbox
347 @param profile: real profile (ie not a profile_key) 347 @param profile: real profile (ie not a profile_key)
348 THIS OBJECT MUST NOT BE USED DIRECTLY: use MaildirBox.accessMessageBox instead""" 348 THIS OBJECT MUST NOT BE USED DIRECTLY: use MaildirBox.accessMessageBox instead"""
349 if _maildir._checkBoxReference(name, profile): 349 if _maildir._checkBoxReference(name, profile):
350 log.error(u"INTERNAL ERROR: MailboxUser MUST NOT be instancied directly") 350 log.error("INTERNAL ERROR: MailboxUser MUST NOT be instancied directly")
351 raise MaildirError('double MailboxUser instanciation') 351 raise MaildirError('double MailboxUser instanciation')
352 if name != "INBOX": 352 if name != "INBOX":
353 raise NotImplementedError 353 raise NotImplementedError
354 self.name = name 354 self.name = name
355 self.profile = profile 355 self.profile = profile
356 self.maildir = _maildir 356 self.maildir = _maildir
357 profile_path = self.maildir._getProfilePath(profile) 357 profile_path = self.maildir._getProfilePath(profile)
358 full_profile_path = os.path.join(self.maildir.host.memory.getConfig('', 'local_dir'), 'maildir', profile_path) 358 full_profile_path = os.path.join(self.maildir.host.memory.getConfig('', 'local_dir'), 'maildir', profile_path)
359 if not os.path.exists(full_profile_path): 359 if not os.path.exists(full_profile_path):
360 os.makedirs(full_profile_path, 0700) 360 os.makedirs(full_profile_path, 0o700)
361 mailbox_path = os.path.join(full_profile_path, MAILDIR_PATH) 361 mailbox_path = os.path.join(full_profile_path, MAILDIR_PATH)
362 self.mailbox_path = mailbox_path 362 self.mailbox_path = mailbox_path
363 self.mailbox = maildir.MaildirMailbox(mailbox_path) 363 self.mailbox = maildir.MaildirMailbox(mailbox_path)
364 self.observer = observer 364 self.observer = observer
365 self.__uid_table_update() 365 self.__uid_table_update()
366 366
367 if observer: 367 if observer:
368 log.debug(u"adding observer for %s (%s)" % (name, profile)) 368 log.debug("adding observer for %s (%s)" % (name, profile))
369 self.maildir.addObserver(observer, profile, name, "NEW_MESSAGE") 369 self.maildir.addObserver(observer, profile, name, "NEW_MESSAGE")
370 370
371 def __uid_table_update(self): 371 def __uid_table_update(self):
372 existant_id = [] 372 existant_id = []
373 for mess_idx in range(self.getMessageCount()): 373 for mess_idx in range(self.getMessageCount()):
376 self.getUid(mess_idx) 376 self.getUid(mess_idx)
377 self.maildir.cleanTable(self.name, existant_id, profile=self.profile) 377 self.maildir.cleanTable(self.name, existant_id, profile=self.profile)
378 378
379 def __del__(self): 379 def __del__(self):
380 if self.observer: 380 if self.observer:
381 log.debug(u"removing observer for %s" % self.name) 381 log.debug("removing observer for %s" % self.name)
382 self._maildir.removeObserver(self.observer, self.name, "NEW_MESSAGE") 382 self._maildir.removeObserver(self.observer, self.name, "NEW_MESSAGE")
383 self.maildir._removeBoxAccess(self.name, self, profile=self.profile) 383 self.maildir._removeBoxAccess(self.name, self, profile=self.profile)
384 384
385 def addMessage(self, message): 385 def addMessage(self, message):
386 """Add a message to the box 386 """Add a message to the box
488 def removeDeleted(self): 488 def removeDeleted(self):
489 """Actually delete message flagged "\\Deleted" 489 """Actually delete message flagged "\\Deleted"
490 Also purge the internal data of these messages 490 Also purge the internal data of these messages
491 """ 491 """
492 for mess_id in self.getMessageIdsWithFlag("\\Deleted"): 492 for mess_id in self.getMessageIdsWithFlag("\\Deleted"):
493 print ("Deleting %s" % mess_id) 493 print(("Deleting %s" % mess_id))
494 self.mailbox.deleteMessage(self.getIdxFromId(mess_id)) 494 self.mailbox.deleteMessage(self.getIdxFromId(mess_id))
495 self.mailbox = maildir.MaildirMailbox(self.mailbox_path) # We need to reparse the dir to have coherent indexing 495 self.mailbox = maildir.MaildirMailbox(self.mailbox_path) # We need to reparse the dir to have coherent indexing
496 self.maildir.purgeDeleted(self.name, profile=self.profile) 496 self.maildir.purgeDeleted(self.name, profile=self.profile)
497 497
498 def emptyTrash(self): 498 def emptyTrash(self):