Commit a2a68ffe authored by Philipp Hörist's avatar Philipp Hörist
Browse files

Unwrap MAM messages

parent 6b2b6f8b
......@@ -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'
......
......@@ -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)
......@@ -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):
......@@ -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)
......@@ -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
......@@ -56,6 +58,20 @@ 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
......@@ -82,9 +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):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment