diff sat/plugins/plugin_xep_0313.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 1f74cd0f22c3
children 9d0df638c8b4
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0313.py	Wed Jul 31 11:31:22 2019 +0200
+++ b/sat/plugins/plugin_xep_0313.py	Tue Aug 13 19:08:41 2019 +0200
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # SAT plugin for Message Archive Management (XEP-0313)
@@ -25,7 +25,7 @@
 from sat.tools.common import data_format
 from twisted.words.protocols.jabber import jid
 from twisted.internet import defer
-from zope.interface import implements
+from zope.interface import implementer
 from datetime import datetime
 from dateutil import tz
 from wokkel import disco
@@ -40,19 +40,19 @@
 log = getLogger(__name__)
 
 PLUGIN_INFO = {
-    C.PI_NAME: u"Message Archive Management",
-    C.PI_IMPORT_NAME: u"XEP-0313",
-    C.PI_TYPE: u"XEP",
-    C.PI_PROTOCOLS: [u"XEP-0313"],
-    C.PI_DEPENDENCIES: [u"XEP-0059", u"XEP-0359"],
-    C.PI_MAIN: u"XEP_0313",
-    C.PI_HANDLER: u"yes",
-    C.PI_DESCRIPTION: _(u"""Implementation of Message Archive Management"""),
+    C.PI_NAME: "Message Archive Management",
+    C.PI_IMPORT_NAME: "XEP-0313",
+    C.PI_TYPE: "XEP",
+    C.PI_PROTOCOLS: ["XEP-0313"],
+    C.PI_DEPENDENCIES: ["XEP-0059", "XEP-0359"],
+    C.PI_MAIN: "XEP_0313",
+    C.PI_HANDLER: "yes",
+    C.PI_DESCRIPTION: _("""Implementation of Message Archive Management"""),
 }
 
-MAM_PREFIX = u"mam_"
+MAM_PREFIX = "mam_"
 FILTER_PREFIX = MAM_PREFIX + "filter_"
-KEY_LAST_STANZA_ID = u"last_stanza_id"
+KEY_LAST_STANZA_ID = "last_stanza_id"
 MESSAGE_RESULT = "/message/result[@xmlns='{mam_ns}' and @queryid='{query_id}']"
 MESSAGE_STANZA_ID = '/message/stanza-id[@xmlns="{ns_stanza_id}"]'
 
@@ -61,16 +61,16 @@
     def __init__(self, host):
         log.info(_("Message Archive Management plugin initialization"))
         self.host = host
-        self.host.registerNamespace(u"mam", mam.NS_MAM)
-        self._rsm = host.plugins[u"XEP-0059"]
-        self._sid = host.plugins[u"XEP-0359"]
+        self.host.registerNamespace("mam", mam.NS_MAM)
+        self._rsm = host.plugins["XEP-0059"]
+        self._sid = host.plugins["XEP-0359"]
         # Deferred used to store last stanza id in order of reception
         self._last_stanza_id_d = defer.Deferred()
         self._last_stanza_id_d.callback(None)
         host.bridge.addMethod(
             "MAMGet", ".plugin", in_sign='sss',
             out_sign='(a(sdssa{ss}a{ss}sa{ss})a{ss}s)', method=self._getArchives,
-            async=True)
+            async_=True)
 
     @defer.inlineCallbacks
     def resume(self, client):
@@ -79,15 +79,15 @@
             mam.NS_MAM, [KEY_LAST_STANZA_ID], profile=client.profile)
         stanza_id = stanza_id_data.get(KEY_LAST_STANZA_ID)
         if stanza_id is None:
-            log.info(u"can't retrieve last stanza ID, checking history")
+            log.info("can't retrieve last stanza ID, checking history")
             last_mess = yield self.host.memory.historyGet(
-                None, None, limit=1, filters={u'not_types': C.MESS_TYPE_GROUPCHAT,
-                                              u'last_stanza_id': True},
+                None, None, limit=1, filters={'not_types': C.MESS_TYPE_GROUPCHAT,
+                                              'last_stanza_id': True},
                 profile=client.profile)
             if not last_mess:
-                log.info(_(u"It seems that we have no MAM history yet"))
+                log.info(_("It seems that we have no MAM history yet"))
                 return
-            stanza_id = last_mess[0][-1][u'stanza_id']
+            stanza_id = last_mess[0][-1]['stanza_id']
         rsm_req = rsm.RSMRequest(max_=100, after=stanza_id)
         mam_req = mam.MAMRequest(rsm_=rsm_req)
         complete = False
@@ -96,7 +96,7 @@
             mam_data = yield self.getArchives(client, mam_req,
                                               service=client.jid.userhostJID())
             elt_list, rsm_response, mam_response = mam_data
-            complete = mam_response[u"complete"]
+            complete = mam_response["complete"]
             # we update MAM request for next iteration
             mam_req.rsm.after = rsm_response.last
             if not elt_list:
@@ -114,7 +114,7 @@
                 try:
                     destinee = jid.JID(fwd_message_elt['to'])
                 except KeyError:
-                    log.warning(_(u'missing "to" attribute in forwarded message'))
+                    log.warning(_('missing "to" attribute in forwarded message'))
                     destinee = client.jid
                 if destinee.userhostJID() == client.jid.userhostJID():
                     # message to use, we insert the forwarded message in the normal
@@ -125,12 +125,12 @@
                     try:
                         from_jid = jid.JID(fwd_message_elt['from'])
                     except KeyError:
-                        log.warning(_(u'missing "from" attribute in forwarded message'))
+                        log.warning(_('missing "from" attribute in forwarded message'))
                         from_jid = client.jid
                     if from_jid.userhostJID() != client.jid.userhostJID():
                         log.warning(_(
-                            u'was expecting a message sent by our jid, but this one if '
-                            u'from {from_jid}, ignoring\n{xml}').format(
+                            'was expecting a message sent by our jid, but this one if '
+                            'from {from_jid}, ignoring\n{xml}').format(
                                 from_jid=from_jid.full(), xml=mess_elt.toXml()))
                         continue
                     # adding message to history
@@ -139,16 +139,16 @@
                         yield client.messageProt.addToHistory(mess_data)
                     except exceptions.CancelError as e:
                         log.warning(
-                            u"message has not been added to history: {e}".format(e=e))
+                            "message has not been added to history: {e}".format(e=e))
                     except Exception as e:
                         log.error(
-                            u"can't add message to history: {e}\n{xml}"
+                            "can't add message to history: {e}\n{xml}"
                             .format(e=e, xml=mess_elt.toXml()))
 
         if not count:
-            log.info(_(u"We have received no message while offline"))
+            log.info(_("We have received no message while offline"))
         else:
-            log.info(_(u"We have received {num_mess} message(s) while offline.")
+            log.info(_("We have received {num_mess} message(s) while offline.")
                 .format(num_mess=count))
 
     def profileConnected(self, client):
@@ -168,31 +168,31 @@
         """
         mam_args = {}
         form_args = {}
-        for arg in (u"start", u"end"):
+        for arg in ("start", "end"):
             try:
                 value = extra.pop(MAM_PREFIX + arg)
                 form_args[arg] = datetime.fromtimestamp(float(value), tz.tzutc())
             except (TypeError, ValueError):
-                log.warning(u"Bad value for {arg} filter ({value}), ignoring".format(
+                log.warning("Bad value for {arg} filter ({value}), ignoring".format(
                     arg=arg, value=value))
             except KeyError:
                 continue
 
         try:
-            form_args[u"with_jid"] = jid.JID(extra.pop(
-                MAM_PREFIX + u"with"))
+            form_args["with_jid"] = jid.JID(extra.pop(
+                MAM_PREFIX + "with"))
         except (jid.InvalidFormat):
-            log.warning(u"Bad value for jid filter")
+            log.warning("Bad value for jid filter")
         except KeyError:
             pass
 
-        for name, value in extra.iteritems():
+        for name, value in extra.items():
             if name.startswith(FILTER_PREFIX):
                 var = name[len(FILTER_PREFIX):]
-                extra_fields = form_args.setdefault(u"extra_fields", [])
+                extra_fields = form_args.setdefault("extra_fields", [])
                 extra_fields.append(data_form.Field(var=var, value=value))
 
-        for arg in (u"node", u"query_id"):
+        for arg in ("node", "query_id"):
             try:
                 value = extra.pop(MAM_PREFIX + arg)
                 mam_args[arg] = value
@@ -209,8 +209,8 @@
 
         # we only set orderBy if we have other MAM args
         # else we would make a MAM query while it's not expected
-        if u"order_by" in extra and mam_args:
-            order_by = extra.pop(u"order_by")
+        if "order_by" in extra and mam_args:
+            order_by = extra.pop("order_by")
             assert isinstance(order_by, list)
             mam_args["orderBy"] = order_by
 
@@ -230,8 +230,8 @@
         """
         if data is None:
             data = {}
-        data[u"mam_complete"] = C.boolConst(mam_response[u'complete'])
-        data[u"mam_stable"] = C.boolConst(mam_response[u'stable'])
+        data["mam_complete"] = C.boolConst(mam_response['complete'])
+        data["mam_stable"] = C.boolConst(mam_response['stable'])
         return data
 
     def getMessageFromResult(self, client, mess_elt, mam_req, service=None):
@@ -245,38 +245,38 @@
             None if it's user server
         @return domish.Element): <message/> that can be used directly with onMessage
         """
-        if mess_elt.name != u"message":
-            log.warning(u"unexpected stanza in archive: {xml}".format(
+        if mess_elt.name != "message":
+            log.warning("unexpected stanza in archive: {xml}".format(
                 xml=mess_elt.toXml()))
-            raise exceptions.DataError(u"Invalid element")
+            raise exceptions.DataError("Invalid element")
         service_jid = client.jid.userhostJID() if service is None else service
-        mess_from = mess_elt[u"from"]
+        mess_from = mess_elt["from"]
         # we check that the message has been sent by the right service
         # if service is None (i.e. message expected from our own server)
         # from can be server jid or user's bare jid
         if (mess_from != service_jid.full()
             and not (service is None and mess_from == client.jid.host)):
-            log.error(u"Message is not from our server, something went wrong: "
-                      u"{xml}".format(xml=mess_elt.toXml()))
-            raise exceptions.DataError(u"Invalid element")
+            log.error("Message is not from our server, something went wrong: "
+                      "{xml}".format(xml=mess_elt.toXml()))
+            raise exceptions.DataError("Invalid element")
         try:
-            result_elt = next(mess_elt.elements(mam.NS_MAM, u"result"))
-            forwarded_elt = next(result_elt.elements(C.NS_FORWARD, u"forwarded"))
+            result_elt = next(mess_elt.elements(mam.NS_MAM, "result"))
+            forwarded_elt = next(result_elt.elements(C.NS_FORWARD, "forwarded"))
             try:
-                delay_elt = next(forwarded_elt.elements(C.NS_DELAY, u"delay"))
+                delay_elt = next(forwarded_elt.elements(C.NS_DELAY, "delay"))
             except StopIteration:
                 # delay_elt is not mandatory
                 delay_elt = None
-            fwd_message_elt = next(forwarded_elt.elements(C.NS_CLIENT, u"message"))
+            fwd_message_elt = next(forwarded_elt.elements(C.NS_CLIENT, "message"))
         except StopIteration:
-            log.warning(u"Invalid message received from MAM: {xml}".format(
+            log.warning("Invalid message received from MAM: {xml}".format(
                 xml=mess_elt.toXml()))
-            raise exceptions.DataError(u"Invalid element")
+            raise exceptions.DataError("Invalid element")
         else:
-            if not result_elt[u"queryid"] == mam_req.query_id:
-                log.error(u"Unexpected query id (was expecting {query_id}): {xml}"
+            if not result_elt["queryid"] == mam_req.query_id:
+                log.error("Unexpected query id (was expecting {query_id}): {xml}"
                     .format(query_id=mam.query_id, xml=mess_elt.toXml()))
-                raise exceptions.DataError(u"Invalid element")
+                raise exceptions.DataError("Invalid element")
             stanza_id = self._sid.getStanzaId(fwd_message_elt,
                                               service_jid)
             if stanza_id is None:
@@ -284,11 +284,11 @@
                 # will be archived with it, and we won't request several times
                 # the same MAM achive
                 try:
-                    stanza_id = result_elt[u"id"]
+                    stanza_id = result_elt["id"]
                 except AttributeError:
-                    log.warning(u'Invalid MAM result: missing "id" attribute: {xml}'
+                    log.warning('Invalid MAM result: missing "id" attribute: {xml}'
                                 .format(xml=result_elt.toXml()))
-                    raise exceptions.DataError(u"Invalid element")
+                    raise exceptions.DataError("Invalid element")
                 self._sid.addStanzaId(client, fwd_message_elt, stanza_id, by=service_jid)
 
             if delay_elt is not None:
@@ -323,12 +323,12 @@
     def _queryFinished(self, iq_result, client, elt_list, event):
         client.xmlstream.removeObserver(event, self._appendMessage)
         try:
-            fin_elt = iq_result.elements(mam.NS_MAM, "fin").next()
+            fin_elt = next(iq_result.elements(mam.NS_MAM, "fin"))
         except StopIteration:
-            raise exceptions.DataError(u"Invalid MAM result")
+            raise exceptions.DataError("Invalid MAM result")
 
-        mam_response = {u"complete": C.bool(fin_elt.getAttribute(u"complete", C.BOOL_FALSE)),
-                        u"stable": C.bool(fin_elt.getAttribute(u"stable", C.BOOL_TRUE))}
+        mam_response = {"complete": C.bool(fin_elt.getAttribute("complete", C.BOOL_FALSE)),
+                        "stable": C.bool(fin_elt.getAttribute("stable", C.BOOL_TRUE))}
 
         try:
             rsm_response = rsm.RSMResponse.fromElement(fin_elt)
@@ -383,7 +383,7 @@
                 - stable: a boolean which is False if items order may be changed
         """
         if query.query_id is None:
-            query.query_id = unicode(uuid.uuid4())
+            query.query_id = str(uuid.uuid4())
         elt_list = []
         event = MESSAGE_RESULT.format(mam_ns=mam.NS_MAM, query_id=query.query_id)
         client.xmlstream.addObserver(event, self._appendMessage, 0, elt_list, message_cb)
@@ -431,7 +431,7 @@
         service_jid = client.jid.userhostJID()
         stanza_id = self._sid.getStanzaId(message_elt, service_jid)
         if stanza_id is None:
-            log.debug(u"Ignoring <message>, stanza id is not from our server")
+            log.debug("Ignoring <message>, stanza id is not from our server")
         else:
             # we use self._last_stanza_id_d do be sure that last_stanza_id is stored in
             # the order of reception
@@ -443,8 +443,8 @@
                     profile=client.profile))
 
 
+@implementer(disco.IDisco)
 class SatMAMClient(mam.MAMClient):
-    implements(disco.IDisco)
 
     def __init__(self, plugin_parent):
         self.plugin_parent = plugin_parent
@@ -455,7 +455,7 @@
 
     def connectionInitialized(self):
         observer_xpath = MESSAGE_STANZA_ID.format(
-            ns_stanza_id=self.host.ns_map[u'stanza_id'])
+            ns_stanza_id=self.host.ns_map['stanza_id'])
         self.xmlstream.addObserver(
             observer_xpath, self.plugin_parent.onMessageStanzaId, client=self.parent
         )