Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_imap.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 | 56f94936df1e |
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 imap server | 4 # SàT plugin for managing imap server |
5 # Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
27 from twisted.cred import error as cred_error | 27 from twisted.cred import error as cred_error |
28 from twisted.mail import imap4 | 28 from twisted.mail import imap4 |
29 from twisted.python import failure | 29 from twisted.python import failure |
30 from email.parser import Parser | 30 from email.parser import Parser |
31 import os | 31 import os |
32 from cStringIO import StringIO | 32 from io import StringIO |
33 from twisted.internet import reactor | 33 from twisted.internet import reactor |
34 | 34 |
35 from zope.interface import implements | 35 from zope.interface import implementer |
36 | 36 |
37 PLUGIN_INFO = { | 37 PLUGIN_INFO = { |
38 C.PI_NAME: "IMAP server Plugin", | 38 C.PI_NAME: "IMAP server Plugin", |
39 C.PI_IMPORT_NAME: "IMAP", | 39 C.PI_IMPORT_NAME: "IMAP", |
40 C.PI_TYPE: "Misc", | 40 C.PI_TYPE: "Misc", |
73 | 73 |
74 self.server_factory = ImapServerFactory(self.host) | 74 self.server_factory = ImapServerFactory(self.host) |
75 reactor.listenTCP(port, self.server_factory) | 75 reactor.listenTCP(port, self.server_factory) |
76 | 76 |
77 | 77 |
78 @implementer(imap4.IMessage) | |
78 class Message(object): | 79 class Message(object): |
79 implements(imap4.IMessage) | |
80 | 80 |
81 def __init__(self, uid, flags, mess_fp): | 81 def __init__(self, uid, flags, mess_fp): |
82 log.debug("Message Init") | 82 log.debug("Message Init") |
83 self.uid = uid | 83 self.uid = uid |
84 self.flags = flags | 84 self.flags = flags |
110 @param names: The names of the headers to retrieve or omit. | 110 @param names: The names of the headers to retrieve or omit. |
111 @param negate: If True, indicates that the headers listed in names | 111 @param negate: If True, indicates that the headers listed in names |
112 should be omitted from the return value, rather than included. | 112 should be omitted from the return value, rather than included. |
113 @return: A mapping of header field names to header field values | 113 @return: A mapping of header field names to header field values |
114 """ | 114 """ |
115 log.debug(u"getHeaders %s - %s" % (negate, names)) | 115 log.debug("getHeaders %s - %s" % (negate, names)) |
116 final_dict = {} | 116 final_dict = {} |
117 to_check = [name.lower() for name in names] | 117 to_check = [name.lower() for name in names] |
118 for header in self.message.keys(): | 118 for header in list(self.message.keys()): |
119 if (negate and not header.lower() in to_check) or ( | 119 if (negate and not header.lower() in to_check) or ( |
120 not negate and header.lower() in to_check | 120 not negate and header.lower() in to_check |
121 ): | 121 ): |
122 final_dict[header] = self.message[header] | 122 final_dict[header] = self.message[header] |
123 return final_dict | 123 return final_dict |
148 """ | 148 """ |
149 log.debug("getSubPart") | 149 log.debug("getSubPart") |
150 return TypeError | 150 return TypeError |
151 | 151 |
152 | 152 |
153 @implementer(imap4.IMailbox) | |
153 class SatMailbox(object): | 154 class SatMailbox(object): |
154 implements(imap4.IMailbox) | |
155 | 155 |
156 def __init__(self, host, name, profile): | 156 def __init__(self, host, name, profile): |
157 self.host = host | 157 self.host = host |
158 self.listeners = set() | 158 self.listeners = set() |
159 log.debug(u"Mailbox init (%s)" % name) | 159 log.debug("Mailbox init (%s)" % name) |
160 if name != "INBOX": | 160 if name != "INBOX": |
161 raise imap4.MailboxException("Only INBOX is managed for the moment") | 161 raise imap4.MailboxException("Only INBOX is managed for the moment") |
162 self.mailbox = self.host.plugins["Maildir"].accessMessageBox( | 162 self.mailbox = self.host.plugins["Maildir"].accessMessageBox( |
163 name, self.messageNew, profile | 163 name, self.messageNew, profile |
164 ) | 164 ) |
185 def getUID(self, message): | 185 def getUID(self, message): |
186 """Return the UID of a message in the mailbox | 186 """Return the UID of a message in the mailbox |
187 @param message: The message sequence number | 187 @param message: The message sequence number |
188 @return: The UID of the message. | 188 @return: The UID of the message. |
189 """ | 189 """ |
190 log.debug(u"getUID (%i)" % message) | 190 log.debug("getUID (%i)" % message) |
191 # return self.mailbox.getUid(message-1) #XXX: it seems that this method get uid and not message sequence number | 191 # return self.mailbox.getUid(message-1) #XXX: it seems that this method get uid and not message sequence number |
192 return message | 192 return message |
193 | 193 |
194 def getMessageCount(self): | 194 def getMessageCount(self): |
195 """Return the number of messages in this mailbox. | 195 """Return the number of messages in this mailbox. |
241 | 241 |
242 @type listener: Any object which implements C{IMailboxListener} | 242 @type listener: Any object which implements C{IMailboxListener} |
243 @param listener: An object to add to the set of those which will | 243 @param listener: An object to add to the set of those which will |
244 be notified when the contents of this mailbox change. | 244 be notified when the contents of this mailbox change. |
245 """ | 245 """ |
246 log.debug(u"addListener %s" % listener) | 246 log.debug("addListener %s" % listener) |
247 self.listeners.add(listener) | 247 self.listeners.add(listener) |
248 | 248 |
249 def removeListener(self, listener): | 249 def removeListener(self, listener): |
250 """Remove a mailbox change listener | 250 """Remove a mailbox change listener |
251 | 251 |
286 """Retrieve one or more messages. | 286 """Retrieve one or more messages. |
287 @param messages: The identifiers of messages to retrieve information | 287 @param messages: The identifiers of messages to retrieve information |
288 about | 288 about |
289 @param uid: If true, the IDs specified in the query are UIDs; | 289 @param uid: If true, the IDs specified in the query are UIDs; |
290 """ | 290 """ |
291 log.debug(u"fetch (%s, %s)" % (messages, uid)) | 291 log.debug("fetch (%s, %s)" % (messages, uid)) |
292 if uid: | 292 if uid: |
293 messages.last = self.mailbox.getMaxUid() | 293 messages.last = self.mailbox.getMaxUid() |
294 messages.getnext = self.mailbox.getNextExistingUid | 294 messages.getnext = self.mailbox.getNextExistingUid |
295 for mess_uid in messages: | 295 for mess_uid in messages: |
296 if mess_uid is None: | 296 if mess_uid is None: |
410 | 410 |
411 def _emptyMailbox(self, name, id): | 411 def _emptyMailbox(self, name, id): |
412 return SatMailbox(self.host, name, self.profile) | 412 return SatMailbox(self.host, name, self.profile) |
413 | 413 |
414 | 414 |
415 @implementer(portal.IRealm) | |
415 class ImapRealm(object): | 416 class ImapRealm(object): |
416 implements(portal.IRealm) | |
417 | 417 |
418 def __init__(self, host): | 418 def __init__(self, host): |
419 self.host = host | 419 self.host = host |
420 | 420 |
421 def requestAvatar(self, avatarID, mind, *interfaces): | 421 def requestAvatar(self, avatarID, mind, *interfaces): |
422 log.debug("requestAvatar") | 422 log.debug("requestAvatar") |
423 profile = avatarID.decode("utf-8") | 423 profile = avatarID |
424 if imap4.IAccount not in interfaces: | 424 if imap4.IAccount not in interfaces: |
425 raise NotImplementedError | 425 raise NotImplementedError |
426 return imap4.IAccount, ImapSatAccount(self.host, profile), lambda: None | 426 return imap4.IAccount, ImapSatAccount(self.host, profile), lambda: None |
427 | 427 |
428 | 428 |
429 @implementer(checkers.ICredentialsChecker) | |
429 class SatProfileCredentialChecker(object): | 430 class SatProfileCredentialChecker(object): |
430 """ | 431 """ |
431 This credential checker check against SàT's profile and associated jabber's password | 432 This credential checker check against SàT's profile and associated jabber's password |
432 Check if the profile exists, and if the password is OK | 433 Check if the profile exists, and if the password is OK |
433 Return the profile as avatarId | 434 Return the profile as avatarId |
434 """ | 435 """ |
435 | 436 |
436 implements(checkers.ICredentialsChecker) | |
437 credentialInterfaces = ( | 437 credentialInterfaces = ( |
438 credentials.IUsernamePassword, | 438 credentials.IUsernamePassword, |
439 credentials.IUsernameHashedPassword, | 439 credentials.IUsernameHashedPassword, |
440 ) | 440 ) |
441 | 441 |
468 | 468 |
469 def startedConnecting(self, connector): | 469 def startedConnecting(self, connector): |
470 log.debug(_("IMAP server connection started")) | 470 log.debug(_("IMAP server connection started")) |
471 | 471 |
472 def clientConnectionLost(self, connector, reason): | 472 def clientConnectionLost(self, connector, reason): |
473 log.debug(_(u"IMAP server connection lost (reason: %s)"), reason) | 473 log.debug(_("IMAP server connection lost (reason: %s)"), reason) |
474 | 474 |
475 def buildProtocol(self, addr): | 475 def buildProtocol(self, addr): |
476 log.debug("Building protocol") | 476 log.debug("Building protocol") |
477 prot = protocol.ServerFactory.buildProtocol(self, addr) | 477 prot = protocol.ServerFactory.buildProtocol(self, addr) |
478 prot.portal = portal.Portal(ImapRealm(self.host)) | 478 prot.portal = portal.Portal(ImapRealm(self.host)) |