[Git][gajim/python-nbxmpp][master] 5 commits: Better detect MUC PMs

Philipp Hörist gitlab at dev.gajim.org
Fri Jan 4 00:13:18 CET 2019


Philipp Hörist pushed to branch master at gajim / python-nbxmpp


Commits:
5cca4c7d by Philipp Hörist at 2019-01-03T11:48:03Z
Better detect MUC PMs

- - - - -
2386104f by Philipp Hörist at 2019-01-03T11:54:09Z
Add is_self_message property

- - - - -
6b2b6f8b by Philipp Hörist at 2019-01-03T13:48:36Z
Split base message handler

- - - - -
a2a68ffe by Philipp Hörist at 2019-01-03T15:55:43Z
Unwrap MAM messages

- - - - -
46707d9d by Philipp Hörist at 2019-01-03T19:45:50Z
Never return None on show parsing

- - - - -


6 changed files:

- nbxmpp/dispatcher_nb.py
- nbxmpp/modules/message.py
- nbxmpp/modules/misc.py
- nbxmpp/modules/muc.py
- nbxmpp/modules/presence.py
- nbxmpp/structs.py


Changes:

=====================================
nbxmpp/dispatcher_nb.py
=====================================
@@ -34,6 +34,7 @@ from nbxmpp.protocol import NS_STREAMS
 from nbxmpp.protocol import NS_HTTP_BIND
 from nbxmpp.protocol import NodeProcessed
 from nbxmpp.protocol import InvalidFrom
+from nbxmpp.protocol import InvalidStanza
 from nbxmpp.protocol import Iq
 from nbxmpp.protocol import Presence
 from nbxmpp.protocol import Message
@@ -55,6 +56,7 @@ from nbxmpp.modules.vcard_avatar import VCardAvatar
 from nbxmpp.modules.captcha import Captcha
 from nbxmpp.modules.entity_caps import EntityCaps
 from nbxmpp.modules.misc import unwrap_carbon
+from nbxmpp.modules.misc import unwrap_mam
 from nbxmpp.util import get_properties_struct
 
 
@@ -517,6 +519,7 @@ class XMPPDispatcher(PlugIn):
                 log.warning('Message addressed to someone else: %s', stanza)
                 return
 
+            # Unwrap carbon
             try:
                 stanza, properties.carbon_type = unwrap_carbon(stanza, own_jid)
             except InvalidFrom as exc:
@@ -526,6 +529,12 @@ class XMPPDispatcher(PlugIn):
                 log.info(exc)
                 return
 
+            # Unwrap mam
+            try:
+                stanza, properties.mam = unwrap_mam(stanza, own_jid)
+            except InvalidStanza:
+                return
+
         typ = stanza.getType()
         if name == 'message' and not typ:
             typ = 'normal'


=====================================
nbxmpp/modules/message.py
=====================================
@@ -20,6 +20,7 @@ import logging
 from nbxmpp.protocol import NodeProcessed
 from nbxmpp.structs import StanzaHandler
 from nbxmpp.structs import ErrorProperties
+from nbxmpp.structs import StanzaIDData
 from nbxmpp.const import MessageType
 
 log = logging.getLogger('nbxmpp.m.message')
@@ -31,6 +32,9 @@ class BaseMessage:
         self.handlers = [
             StanzaHandler(name='message',
                           callback=self._process_message_base,
+                          priority=5),
+            StanzaHandler(name='message',
+                          callback=self._process_message_after_base,
                           priority=10),
         ]
 
@@ -38,13 +42,23 @@ class BaseMessage:
         properties.type = self._parse_type(stanza)
         properties.jid = stanza.getFrom()
         properties.id = stanza.getID()
-        properties.body = stanza.getBody()
-        properties.thread = stanza.getThread()
-        properties.subject = stanza.getSubject()
+        properties.self_message = self._parse_self_message(stanza, properties)
+
+        # Stanza ID
+        id_, by = stanza.getStanzaIDAttrs()
+        properties.stanza_id = StanzaIDData(id=id_, by=by)
 
         if properties.type.is_error:
             properties.error = ErrorProperties(stanza)
 
+    @staticmethod
+    def _process_message_after_base(_con, stanza, properties):
+        # This handler runs after decryption handlers had the chance
+        # to decrypt the body
+        properties.body = stanza.getBody()
+        properties.thread = stanza.getThread()
+        properties.subject = stanza.getSubject()
+
     @staticmethod
     def _parse_type(stanza):
         type_ = stanza.getType()
@@ -57,3 +71,9 @@ class BaseMessage:
             log.warning('Message with invalid type: %s', type_)
             log.warning(stanza)
             raise NodeProcessed
+
+    @staticmethod
+    def _parse_self_message(stanza, properties):
+        if properties.type.is_groupchat:
+            return False
+        return stanza.getFrom().bareMatch(stanza.getTo())


=====================================
nbxmpp/modules/misc.py
=====================================
@@ -20,9 +20,14 @@ import logging
 from nbxmpp.protocol import NS_CARBONS
 from nbxmpp.protocol import NS_FORWARD
 from nbxmpp.protocol import NS_MUC_USER
+from nbxmpp.protocol import NS_MAM_1
+from nbxmpp.protocol import NS_MAM_2
 from nbxmpp.protocol import NodeProcessed
 from nbxmpp.protocol import InvalidFrom
+from nbxmpp.protocol import InvalidStanza
 from nbxmpp.protocol import Message
+from nbxmpp.structs import MAMData
+from nbxmpp.modules.delay import parse_delay
 
 
 log = logging.getLogger('nbxmpp.m.misc')
@@ -43,6 +48,8 @@ def unwrap_carbon(stanza, own_jid):
     message = Message(node=forwarded.getTag('message'))
 
     type_ = carbon.getName()
+
+    # Fill missing to/from
     to = message.getTo()
     if to is None:
         message.setTo(own_jid.getBare())
@@ -64,3 +71,49 @@ def unwrap_carbon(stanza, own_jid):
             raise NodeProcessed('Drop MUC-PM "received"-Carbon')
 
     return message, type_
+
+
+def unwrap_mam(stanza, own_jid):
+    result = stanza.getTag('result', namespace=NS_MAM_2)
+    if result is None:
+        result = stanza.getTag('result', namespace=NS_MAM_1)
+        if result is None:
+            return stanza, None
+
+    query_id = result.getAttr('queryid')
+    if query_id is None:
+        log.warning('No queryid on MAM message')
+        log.warning(stanza)
+        raise InvalidStanza
+
+    id_ = result.getAttr('id')
+    if id_ is None:
+        log.warning('No id on MAM message')
+        log.warning(stanza)
+        raise InvalidStanza
+
+    forwarded = result.getTag('forwarded', namespace=NS_FORWARD)
+    message = Message(node=forwarded.getTag('message'))
+
+    # Fill missing to/from
+    to = message.getTo()
+    if to is None:
+        message.setTo(own_jid.getBare())
+
+    frm = message.getFrom()
+    if frm is None:
+        message.setFrom(own_jid.getBare())
+
+    # Timestamp parsing
+    # Most servers dont set the 'from' attr, so we cant check for it
+    delay_timestamp = parse_delay(forwarded)
+    if delay_timestamp is None:
+        log.warning('No timestamp on MAM message')
+        log.warning(stanza)
+        raise InvalidStanza
+
+    return message, MAMData(id=id_,
+                            query_id=query_id,
+                            archive=stanza.getFrom(),
+                            namespace=result.getNamespace(),
+                            timestamp=delay_timestamp)


=====================================
nbxmpp/modules/muc.py
=====================================
@@ -99,8 +99,7 @@ class MUC:
         properties.from_muc = True
         properties.muc_nickname = properties.jid.getResource()
 
-    @staticmethod
-    def _process_muc_user_presence(_con, stanza, properties):
+    def _process_muc_user_presence(self, _con, stanza, properties):
         muc_user = stanza.getTag('x', namespace=NS_MUC_USER)
         if muc_user is None:
             return
@@ -112,7 +111,7 @@ class MUC:
             if alternate is not None:
                 try:
                     alternate = JID(validate_jid(alternate))
-                except InvalidJid as error:
+                except InvalidJid:
                     log.warning('Invalid alternate JID provided')
                     log.warning(stanza)
                     alternate = None
@@ -155,23 +154,15 @@ class MUC:
         if codes:
             properties.muc_status_codes = codes
 
-        item = muc_user.getTag('item')
-        if item is not None:
-            item_dict = item.getAttrs()
-            if 'role' in item_dict:
-                item_dict['role'] = Role(item_dict['role'])
-            if 'affiliation' in item_dict:
-                item_dict['affiliation'] = Affiliation(item_dict['affiliation'])
-            if 'jid' in item_dict:
-                item_dict['jid'] = JID(item_dict['jid'])
-            item_dict['actor'] = item.getTagAttr('actor', 'nick')
-            item_dict['reason'] = item.getTagData('reason')
-            properties.muc_user = MucUserData(**item_dict)
+        properties.muc_user = self._parse_muc_user(muc_user)
 
-    @staticmethod
-    def _process_groupchat_message(_con, _stanza, properties):
+    def _process_groupchat_message(self, _con, stanza, properties):
         properties.from_muc = True
         properties.muc_nickname = properties.jid.getResource() or None
+        
+        muc_user = stanza.getTag('x', namespace=NS_MUC_USER)
+        if muc_user is not None:
+            properties.muc_user = self._parse_muc_user(muc_user)
 
     @staticmethod
     def _process_message(_con, stanza, properties):
@@ -180,7 +171,7 @@ class MUC:
             return
 
         # MUC Private message
-        if properties.type == MessageType.CHAT:
+        if properties.type == MessageType.CHAT and not muc_user.getChildren():
             properties.muc_private_message = True
             return
 
@@ -502,3 +493,27 @@ class MUC:
             return CommonResult(jid=stanza.getFrom(),
                                 error=stanza.getError())
         return CommonResult(jid=stanza.getFrom())
+
+    @staticmethod
+    def _parse_muc_user(muc_user):
+        item = muc_user.getTag('item')
+        if item is not None:
+            item_dict = item.getAttrs()
+            if 'role' in item_dict:
+                item_dict['role'] = Role(item_dict['role'])
+            else:
+                item_dict['role'] = None
+
+            if 'affiliation' in item_dict:
+                item_dict['affiliation'] = Affiliation(item_dict['affiliation'])
+            else:
+                item_dict['affiliation'] = None
+
+            if 'jid' in item_dict:
+                item_dict['jid'] = JID(item_dict['jid'])
+            else:
+                item_dict['jid'] = None
+
+            item_dict['actor'] = item.getTagAttr('actor', 'nick')
+            item_dict['reason'] = item.getTagData('reason')
+            return MucUserData(**item_dict)


=====================================
nbxmpp/modules/presence.py
=====================================
@@ -84,11 +84,9 @@ class BasePresence:
 
     @staticmethod
     def _parse_show(stanza):
-        show = stanza.getShow()
-        if show is None:
-            return PresenceShow.ONLINE
         try:
-            return PresenceShow(show)
+            return PresenceShow(stanza.getShow())
         except ValueError:
             log.warning('Presence with invalid show')
             log.warning(stanza)
+            return PresenceShow.ONLINE


=====================================
nbxmpp/structs.py
=====================================
@@ -20,6 +20,8 @@ from collections import namedtuple
 
 from nbxmpp.protocol import JID
 from nbxmpp.protocol import NS_STANZAS
+from nbxmpp.protocol import NS_MAM_1
+from nbxmpp.protocol import NS_MAM_2
 from nbxmpp.const import MessageType
 from nbxmpp.const import AvatarState
 from nbxmpp.const import StatusCode
@@ -53,6 +55,23 @@ EntityCapsData.__new__.__defaults__ = (None, None, None)
 HTTPAuthData = namedtuple('HTTPAuthData', 'id method url body')
 HTTPAuthData.__new__.__defaults__ = (None, None, None, None)
 
+StanzaIDData = namedtuple('StanzaIDData', 'id by')
+StanzaIDData.__new__.__defaults__ = (None, None)
+
+
+class MAMData(namedtuple('MAMData', 'id query_id archive namespace timestamp')):
+
+    __slots__ = []
+
+    @property
+    def is_ver_1(self):
+        return self.namespace == NS_MAM_1
+
+    @property
+    def is_ver_2(self):
+        return self.namespace == NS_MAM_2
+
+
 class Properties:
     pass
 
@@ -62,6 +81,7 @@ class MessageProperties:
         self.carbon_type = None
         self.type = MessageType.NORMAL
         self.id = None
+        self.stanza_id = None
         self.jid = None
         self.subject = None
         self.body = None
@@ -78,8 +98,15 @@ class MessageProperties:
         self.muc_private_message = False
         self.muc_invite = None
         self.muc_decline = None
+        self.muc_user = None
         self.captcha = None
         self.voice_request = None
+        self.self_message = False
+        self.mam = None
+
+    @property
+    def is_mam_message(self):
+        return self.mam is not None
 
     @property
     def is_http_auth(self):
@@ -112,6 +139,10 @@ class MessageProperties:
     def is_voice_request(self):
         return self.voice_request is not None
 
+    @property
+    def is_self_message(self):
+        return self.self_message
+
 
 class IqProperties:
     def __init__(self):



View it on GitLab: https://dev.gajim.org/gajim/python-nbxmpp/compare/2c8f64557619fcc2d7065fbaedddad4ed700cdb7...46707d9dd5065a937807450c946a0d6591f4c5eb

-- 
View it on GitLab: https://dev.gajim.org/gajim/python-nbxmpp/compare/2c8f64557619fcc2d7065fbaedddad4ed700cdb7...46707d9dd5065a937807450c946a0d6591f4c5eb
You're receiving this email because of your account on dev.gajim.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gajim.org/pipermail/commits/attachments/20190104/79318ccc/attachment-0001.html>


More information about the Commits mailing list