Merge branch 'develop'
This commit is contained in:
commit
ec5e819b16
@ -33,6 +33,7 @@ __all__ = [
|
|||||||
'xep_0071', # XHTML-IM
|
'xep_0071', # XHTML-IM
|
||||||
'xep_0077', # In-Band Registration
|
'xep_0077', # In-Band Registration
|
||||||
# 'xep_0078', # Non-SASL auth. Don't automatically load
|
# 'xep_0078', # Non-SASL auth. Don't automatically load
|
||||||
|
'xep_0079', # Advanced Message Processing
|
||||||
'xep_0080', # User Location
|
'xep_0080', # User Location
|
||||||
'xep_0082', # XMPP Date and Time Profiles
|
'xep_0082', # XMPP Date and Time Profiles
|
||||||
'xep_0084', # User Avatar
|
'xep_0084', # User Avatar
|
||||||
|
@ -36,6 +36,7 @@ class XEP_0047(BasePlugin):
|
|||||||
register_stanza_plugin(Iq, Open)
|
register_stanza_plugin(Iq, Open)
|
||||||
register_stanza_plugin(Iq, Close)
|
register_stanza_plugin(Iq, Close)
|
||||||
register_stanza_plugin(Iq, Data)
|
register_stanza_plugin(Iq, Data)
|
||||||
|
register_stanza_plugin(Message, Data)
|
||||||
|
|
||||||
self.xmpp.register_handler(Callback(
|
self.xmpp.register_handler(Callback(
|
||||||
'IBB Open',
|
'IBB Open',
|
||||||
@ -52,10 +53,16 @@ class XEP_0047(BasePlugin):
|
|||||||
StanzaPath('iq@type=set/ibb_data'),
|
StanzaPath('iq@type=set/ibb_data'),
|
||||||
self._handle_data))
|
self._handle_data))
|
||||||
|
|
||||||
|
self.xmpp.register_handler(Callback(
|
||||||
|
'IBB Message Data',
|
||||||
|
StanzaPath('message/ibb_data'),
|
||||||
|
self._handle_data))
|
||||||
|
|
||||||
def plugin_end(self):
|
def plugin_end(self):
|
||||||
self.xmpp.remove_handler('IBB Open')
|
self.xmpp.remove_handler('IBB Open')
|
||||||
self.xmpp.remove_handler('IBB Close')
|
self.xmpp.remove_handler('IBB Close')
|
||||||
self.xmpp.remove_handler('IBB Data')
|
self.xmpp.remove_handler('IBB Data')
|
||||||
|
self.xmpp.remove_handler('IBB Message Data')
|
||||||
self.xmpp['xep_0030'].del_feature(feature='http://jabber.org/protocol/ibb')
|
self.xmpp['xep_0030'].del_feature(feature='http://jabber.org/protocol/ibb')
|
||||||
|
|
||||||
def session_bind(self, jid):
|
def session_bind(self, jid):
|
||||||
@ -69,7 +76,7 @@ class XEP_0047(BasePlugin):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def open_stream(self, jid, block_size=4096, sid=None, window=1,
|
def open_stream(self, jid, block_size=4096, sid=None, window=1, use_messages=False,
|
||||||
ifrom=None, block=True, timeout=None, callback=None):
|
ifrom=None, block=True, timeout=None, callback=None):
|
||||||
if sid is None:
|
if sid is None:
|
||||||
sid = str(uuid.uuid4())
|
sid = str(uuid.uuid4())
|
||||||
@ -83,7 +90,8 @@ class XEP_0047(BasePlugin):
|
|||||||
iq['ibb_open']['stanza'] = 'iq'
|
iq['ibb_open']['stanza'] = 'iq'
|
||||||
|
|
||||||
stream = IBBytestream(self.xmpp, sid, block_size,
|
stream = IBBytestream(self.xmpp, sid, block_size,
|
||||||
iq['to'], iq['from'], window)
|
iq['to'], iq['from'], window,
|
||||||
|
use_messages)
|
||||||
|
|
||||||
with self._stream_lock:
|
with self._stream_lock:
|
||||||
self.pending_streams[iq['id']] = stream
|
self.pending_streams[iq['id']] = stream
|
||||||
@ -139,11 +147,11 @@ class XEP_0047(BasePlugin):
|
|||||||
|
|
||||||
self.xmpp.event('ibb_stream_start', stream)
|
self.xmpp.event('ibb_stream_start', stream)
|
||||||
|
|
||||||
def _handle_data(self, iq):
|
def _handle_data(self, stanza):
|
||||||
sid = iq['ibb_data']['sid']
|
sid = stanza['ibb_data']['sid']
|
||||||
stream = self.streams.get(sid, None)
|
stream = self.streams.get(sid, None)
|
||||||
if stream is not None and iq['from'] != stream.sender:
|
if stream is not None and stanza['from'] != stream.sender:
|
||||||
stream._recv_data(iq)
|
stream._recv_data(stanza)
|
||||||
else:
|
else:
|
||||||
raise XMPPError('item-not-found')
|
raise XMPPError('item-not-found')
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import socket
|
|||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from sleekxmpp.stanza import Iq
|
||||||
from sleekxmpp.util import Queue
|
from sleekxmpp.util import Queue
|
||||||
from sleekxmpp.exceptions import XMPPError
|
from sleekxmpp.exceptions import XMPPError
|
||||||
|
|
||||||
@ -11,11 +12,12 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class IBBytestream(object):
|
class IBBytestream(object):
|
||||||
|
|
||||||
def __init__(self, xmpp, sid, block_size, to, ifrom, window_size=1):
|
def __init__(self, xmpp, sid, block_size, to, ifrom, window_size=1, use_messages=False):
|
||||||
self.xmpp = xmpp
|
self.xmpp = xmpp
|
||||||
self.sid = sid
|
self.sid = sid
|
||||||
self.block_size = block_size
|
self.block_size = block_size
|
||||||
self.window_size = window_size
|
self.window_size = window_size
|
||||||
|
self.use_messages = use_messages
|
||||||
|
|
||||||
self.receiver = to
|
self.receiver = to
|
||||||
self.sender = ifrom
|
self.sender = ifrom
|
||||||
@ -46,16 +48,27 @@ class IBBytestream(object):
|
|||||||
with self._send_seq_lock:
|
with self._send_seq_lock:
|
||||||
self.send_seq = (self.send_seq + 1) % 65535
|
self.send_seq = (self.send_seq + 1) % 65535
|
||||||
seq = self.send_seq
|
seq = self.send_seq
|
||||||
iq = self.xmpp.Iq()
|
if self.use_messages:
|
||||||
iq['type'] = 'set'
|
msg = self.xmpp.Message()
|
||||||
iq['to'] = self.receiver
|
msg['to'] = self.receiver
|
||||||
iq['from'] = self.sender
|
msg['from'] = self.sender
|
||||||
iq['ibb_data']['sid'] = self.sid
|
msg['id'] = self.xmpp.new_id()
|
||||||
iq['ibb_data']['seq'] = seq
|
msg['ibb_data']['sid'] = self.sid
|
||||||
iq['ibb_data']['data'] = data
|
msg['ibb_data']['seq'] = seq
|
||||||
self.window_empty.clear()
|
msg['ibb_data']['data'] = data
|
||||||
self.window_ids.add(iq['id'])
|
msg.send()
|
||||||
iq.send(block=False, callback=self._recv_ack)
|
self.send_window.release()
|
||||||
|
else:
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
iq['type'] = 'set'
|
||||||
|
iq['to'] = self.receiver
|
||||||
|
iq['from'] = self.sender
|
||||||
|
iq['ibb_data']['sid'] = self.sid
|
||||||
|
iq['ibb_data']['seq'] = seq
|
||||||
|
iq['ibb_data']['data'] = data
|
||||||
|
self.window_empty.clear()
|
||||||
|
self.window_ids.add(iq['id'])
|
||||||
|
iq.send(block=False, callback=self._recv_ack)
|
||||||
return len(data)
|
return len(data)
|
||||||
|
|
||||||
def sendall(self, data):
|
def sendall(self, data):
|
||||||
@ -71,23 +84,25 @@ class IBBytestream(object):
|
|||||||
if iq['type'] == 'error':
|
if iq['type'] == 'error':
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def _recv_data(self, iq):
|
def _recv_data(self, stanza):
|
||||||
with self._recv_seq_lock:
|
with self._recv_seq_lock:
|
||||||
new_seq = iq['ibb_data']['seq']
|
new_seq = stanza['ibb_data']['seq']
|
||||||
if new_seq != (self.recv_seq + 1) % 65535:
|
if new_seq != (self.recv_seq + 1) % 65535:
|
||||||
self.close()
|
self.close()
|
||||||
raise XMPPError('unexpected-request')
|
raise XMPPError('unexpected-request')
|
||||||
self.recv_seq = new_seq
|
self.recv_seq = new_seq
|
||||||
|
|
||||||
data = iq['ibb_data']['data']
|
data = stanza['ibb_data']['data']
|
||||||
if len(data) > self.block_size:
|
if len(data) > self.block_size:
|
||||||
self.close()
|
self.close()
|
||||||
raise XMPPError('not-acceptable')
|
raise XMPPError('not-acceptable')
|
||||||
|
|
||||||
self.recv_queue.put(data)
|
self.recv_queue.put(data)
|
||||||
self.xmpp.event('ibb_stream_data', {'stream': self, 'data': data})
|
self.xmpp.event('ibb_stream_data', {'stream': self, 'data': data})
|
||||||
iq.reply()
|
|
||||||
iq.send()
|
if isinstance(stanza, Iq):
|
||||||
|
stanza.reply()
|
||||||
|
stanza.send()
|
||||||
|
|
||||||
def recv(self, *args, **kwargs):
|
def recv(self, *args, **kwargs):
|
||||||
return self.read(block=True)
|
return self.read(block=True)
|
||||||
|
18
sleekxmpp/plugins/xep_0079/__init__.py
Normal file
18
sleekxmpp/plugins/xep_0079/__init__.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.base import register_plugin
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0079.stanza import (
|
||||||
|
AMP, Rule, InvalidRules, UnsupportedConditions,
|
||||||
|
UnsupportedActions, FailedRules, FailedRule,
|
||||||
|
AMPFeature)
|
||||||
|
from sleekxmpp.plugins.xep_0079.amp import XEP_0079
|
||||||
|
|
||||||
|
|
||||||
|
register_plugin(XEP_0079)
|
79
sleekxmpp/plugins/xep_0079/amp.py
Normal file
79
sleekxmpp/plugins/xep_0079/amp.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from sleekxmpp.stanza import Message, Error, StreamFeatures
|
||||||
|
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||||
|
from sleekxmpp.xmlstream.matcher import StanzaPath, MatchMany
|
||||||
|
from sleekxmpp.xmlstream.handler import Callback
|
||||||
|
from sleekxmpp.plugins import BasePlugin
|
||||||
|
from sleekxmpp.plugins.xep_0079 import stanza
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class XEP_0079(BasePlugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0079 Advanced Message Processing
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'xep_0079'
|
||||||
|
description = 'XEP-0079: Advanced Message Processing'
|
||||||
|
dependencies = set(['xep_0030'])
|
||||||
|
stanza = stanza
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
register_stanza_plugin(Message, stanza.AMP)
|
||||||
|
register_stanza_plugin(Error, stanza.InvalidRules)
|
||||||
|
register_stanza_plugin(Error, stanza.UnsupportedConditions)
|
||||||
|
register_stanza_plugin(Error, stanza.UnsupportedActions)
|
||||||
|
register_stanza_plugin(Error, stanza.FailedRules)
|
||||||
|
|
||||||
|
self.xmpp.register_handler(
|
||||||
|
Callback('AMP Response',
|
||||||
|
MatchMany([
|
||||||
|
StanzaPath('message/error/failed_rules'),
|
||||||
|
StanzaPath('message/amp')
|
||||||
|
]),
|
||||||
|
self._handle_amp_response))
|
||||||
|
|
||||||
|
if not self.xmpp.is_component:
|
||||||
|
self.xmpp.register_feature('amp',
|
||||||
|
self._handle_amp_feature,
|
||||||
|
restart=False,
|
||||||
|
order=9000)
|
||||||
|
register_stanza_plugin(StreamFeatures, stanza.AMPFeature)
|
||||||
|
|
||||||
|
def plugin_end(self):
|
||||||
|
self.xmpp.remove_handler('AMP Response')
|
||||||
|
|
||||||
|
def _handle_amp_response(self, msg):
|
||||||
|
log.debug('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
|
||||||
|
if msg['type'] == 'error':
|
||||||
|
self.xmpp.event('amp_error', msg)
|
||||||
|
elif msg['amp']['status'] in ('alert', 'notify'):
|
||||||
|
self.xmpp.event('amp_%s' % msg['amp']['status'], msg)
|
||||||
|
|
||||||
|
def _handle_amp_feature(self, features):
|
||||||
|
log.debug('Advanced Message Processing is available.')
|
||||||
|
self.xmpp.features.add('amp')
|
||||||
|
|
||||||
|
def discover_support(self, jid=None, **iqargs):
|
||||||
|
if jid is None:
|
||||||
|
if self.xmpp.is_component:
|
||||||
|
jid = self.xmpp.server_host
|
||||||
|
else:
|
||||||
|
jid = self.xmpp.boundjid.host
|
||||||
|
|
||||||
|
return self.xmpp['xep_0030'].get_info(
|
||||||
|
jid=jid,
|
||||||
|
node='http://jabber.org/protocol/amp',
|
||||||
|
**iqargs)
|
96
sleekxmpp/plugins/xep_0079/stanza.py
Normal file
96
sleekxmpp/plugins/xep_0079/stanza.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin
|
||||||
|
|
||||||
|
|
||||||
|
class AMP(ElementBase):
|
||||||
|
namespace = 'http://jabber.org/protocol/amp'
|
||||||
|
name = 'amp'
|
||||||
|
plugin_attrib = 'amp'
|
||||||
|
interfaces = set(['from', 'to', 'status', 'per_hop'])
|
||||||
|
|
||||||
|
def get_from(self):
|
||||||
|
return JID(self._get_attr('from'))
|
||||||
|
|
||||||
|
def set_from(self, value):
|
||||||
|
return self._set_attr('from', str(value))
|
||||||
|
|
||||||
|
def get_to(self):
|
||||||
|
return JID(self._get_attr('from'))
|
||||||
|
|
||||||
|
def set_to(self, value):
|
||||||
|
return self._set_attr('to', str(value))
|
||||||
|
|
||||||
|
def get_per_hop(self):
|
||||||
|
return self._get_attr('per-hop') == 'true'
|
||||||
|
|
||||||
|
def set_per_hop(self, value):
|
||||||
|
if value:
|
||||||
|
return self._set_attr('per-hop', 'true')
|
||||||
|
else:
|
||||||
|
return self._del_attr('per-hop')
|
||||||
|
|
||||||
|
def del_per_hop(self):
|
||||||
|
return self._del_attr('per-hop')
|
||||||
|
|
||||||
|
def add_rule(self, action, condition, value):
|
||||||
|
rule = Rule(parent=self)
|
||||||
|
rule['action'] = action
|
||||||
|
rule['condition'] = condition
|
||||||
|
rule['value'] = value
|
||||||
|
|
||||||
|
|
||||||
|
class Rule(ElementBase):
|
||||||
|
namespace = 'http://jabber.org/protocol/amp'
|
||||||
|
name = 'rule'
|
||||||
|
plugin_attrib = name
|
||||||
|
plugin_multi_attrib = 'rules'
|
||||||
|
interfaces = set(['action', 'condition', 'value'])
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidRules(ElementBase):
|
||||||
|
namespace = 'http://jabber.org/protocol/amp'
|
||||||
|
name = 'invalid-rules'
|
||||||
|
plugin_attrib = 'invalid_rules'
|
||||||
|
|
||||||
|
|
||||||
|
class UnsupportedConditions(ElementBase):
|
||||||
|
namespace = 'http://jabber.org/protocol/amp'
|
||||||
|
name = 'unsupported-conditions'
|
||||||
|
plugin_attrib = 'unsupported_conditions'
|
||||||
|
|
||||||
|
|
||||||
|
class UnsupportedActions(ElementBase):
|
||||||
|
namespace = 'http://jabber.org/protocol/amp'
|
||||||
|
name = 'unsupported-actions'
|
||||||
|
plugin_attrib = 'unsupported_actions'
|
||||||
|
|
||||||
|
|
||||||
|
class FailedRule(Rule):
|
||||||
|
namespace = 'http://jabber.org/protocol/amp#errors'
|
||||||
|
|
||||||
|
|
||||||
|
class FailedRules(ElementBase):
|
||||||
|
namespace = 'http://jabber.org/protocol/amp#errors'
|
||||||
|
name = 'failed-rules'
|
||||||
|
plugin_attrib = 'failed_rules'
|
||||||
|
|
||||||
|
|
||||||
|
class AMPFeature(ElementBase):
|
||||||
|
namespace = 'http://jabber.org/features/amp'
|
||||||
|
name = 'amp'
|
||||||
|
|
||||||
|
|
||||||
|
register_stanza_plugin(AMP, Rule, iterable=True)
|
||||||
|
register_stanza_plugin(InvalidRules, Rule, iterable=True)
|
||||||
|
register_stanza_plugin(UnsupportedConditions, Rule, iterable=True)
|
||||||
|
register_stanza_plugin(UnsupportedActions, Rule, iterable=True)
|
||||||
|
register_stanza_plugin(FailedRules, FailedRule, iterable=True)
|
@ -9,8 +9,9 @@
|
|||||||
import logging
|
import logging
|
||||||
import hashlib
|
import hashlib
|
||||||
import base64
|
import base64
|
||||||
|
import threading
|
||||||
|
|
||||||
import sleekxmpp
|
from sleekxmpp import __version__
|
||||||
from sleekxmpp.stanza import StreamFeatures, Presence, Iq
|
from sleekxmpp.stanza import StreamFeatures, Presence, Iq
|
||||||
from sleekxmpp.xmlstream import register_stanza_plugin, JID
|
from sleekxmpp.xmlstream import register_stanza_plugin, JID
|
||||||
from sleekxmpp.xmlstream.handler import Callback
|
from sleekxmpp.xmlstream.handler import Callback
|
||||||
@ -45,8 +46,7 @@ class XEP_0115(BasePlugin):
|
|||||||
'md5': hashlib.md5}
|
'md5': hashlib.md5}
|
||||||
|
|
||||||
if self.caps_node is None:
|
if self.caps_node is None:
|
||||||
ver = sleekxmpp.__version__
|
self.caps_node = 'http://sleekxmpp.com/ver/%s' % __version__
|
||||||
self.caps_node = 'http://sleekxmpp.com/ver/%s' % ver
|
|
||||||
|
|
||||||
register_stanza_plugin(Presence, stanza.Capabilities)
|
register_stanza_plugin(Presence, stanza.Capabilities)
|
||||||
register_stanza_plugin(StreamFeatures, stanza.Capabilities)
|
register_stanza_plugin(StreamFeatures, stanza.Capabilities)
|
||||||
@ -90,6 +90,9 @@ class XEP_0115(BasePlugin):
|
|||||||
disco.assign_verstring = self.assign_verstring
|
disco.assign_verstring = self.assign_verstring
|
||||||
disco.get_verstring = self.get_verstring
|
disco.get_verstring = self.get_verstring
|
||||||
|
|
||||||
|
self._processing_lock = threading.Lock()
|
||||||
|
self._processing = set()
|
||||||
|
|
||||||
def plugin_end(self):
|
def plugin_end(self):
|
||||||
self.xmpp['xep_0030'].del_feature(feature=stanza.Capabilities.namespace)
|
self.xmpp['xep_0030'].del_feature(feature=stanza.Capabilities.namespace)
|
||||||
self.xmpp.del_filter('out', self._filter_add_caps)
|
self.xmpp.del_filter('out', self._filter_add_caps)
|
||||||
@ -135,17 +138,22 @@ class XEP_0115(BasePlugin):
|
|||||||
|
|
||||||
def _process_caps(self, pres):
|
def _process_caps(self, pres):
|
||||||
if not pres['caps']['hash']:
|
if not pres['caps']['hash']:
|
||||||
log.debug("Received unsupported legacy caps.")
|
log.debug("Received unsupported legacy caps: %s, %s, %s",
|
||||||
|
pres['caps']['node'],
|
||||||
|
pres['caps']['ver'],
|
||||||
|
pres['caps']['ext'])
|
||||||
self.xmpp.event('entity_caps_legacy', pres)
|
self.xmpp.event('entity_caps_legacy', pres)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
ver = pres['caps']['ver']
|
||||||
|
|
||||||
existing_verstring = self.get_verstring(pres['from'].full)
|
existing_verstring = self.get_verstring(pres['from'].full)
|
||||||
if str(existing_verstring) == str(pres['caps']['ver']):
|
if str(existing_verstring) == str(ver):
|
||||||
return
|
return
|
||||||
|
|
||||||
existing_caps = self.get_caps(verstring=pres['caps']['ver'])
|
existing_caps = self.get_caps(verstring=ver)
|
||||||
if existing_caps is not None:
|
if existing_caps is not None:
|
||||||
self.assign_verstring(pres['from'], pres['caps']['ver'])
|
self.assign_verstring(pres['from'], ver)
|
||||||
return
|
return
|
||||||
|
|
||||||
if pres['caps']['hash'] not in self.hashes:
|
if pres['caps']['hash'] not in self.hashes:
|
||||||
@ -156,9 +164,16 @@ class XEP_0115(BasePlugin):
|
|||||||
except XMPPError:
|
except XMPPError:
|
||||||
return
|
return
|
||||||
|
|
||||||
log.debug("New caps verification string: %s", pres['caps']['ver'])
|
# Only lookup the same caps once at a time.
|
||||||
|
with self._processing_lock:
|
||||||
|
if ver in self._processing:
|
||||||
|
log.debug('Already processing verstring %s' % ver)
|
||||||
|
return
|
||||||
|
self._processing.add(ver)
|
||||||
|
|
||||||
|
log.debug("New caps verification string: %s", ver)
|
||||||
try:
|
try:
|
||||||
node = '%s#%s' % (pres['caps']['node'], pres['caps']['ver'])
|
node = '%s#%s' % (pres['caps']['node'], ver)
|
||||||
caps = self.xmpp['xep_0030'].get_info(pres['from'], node)
|
caps = self.xmpp['xep_0030'].get_info(pres['from'], node)
|
||||||
|
|
||||||
if isinstance(caps, Iq):
|
if isinstance(caps, Iq):
|
||||||
@ -168,7 +183,10 @@ class XEP_0115(BasePlugin):
|
|||||||
pres['caps']['ver']):
|
pres['caps']['ver']):
|
||||||
self.assign_verstring(pres['from'], pres['caps']['ver'])
|
self.assign_verstring(pres['from'], pres['caps']['ver'])
|
||||||
except XMPPError:
|
except XMPPError:
|
||||||
log.debug("Could not retrieve disco#info results for caps")
|
log.debug("Could not retrieve disco#info results for caps for %s", node)
|
||||||
|
|
||||||
|
with self._processing_lock:
|
||||||
|
self._processing.remove(ver)
|
||||||
|
|
||||||
def _validate_caps(self, caps, hash, check_verstring):
|
def _validate_caps(self, caps, hash, check_verstring):
|
||||||
# Check Identities
|
# Check Identities
|
||||||
@ -179,7 +197,6 @@ class XEP_0115(BasePlugin):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Check Features
|
# Check Features
|
||||||
|
|
||||||
full_features = caps.get_features(dedupe=False)
|
full_features = caps.get_features(dedupe=False)
|
||||||
deduped_features = caps.get_features()
|
deduped_features = caps.get_features()
|
||||||
if len(full_features) != len(deduped_features):
|
if len(full_features) != len(deduped_features):
|
||||||
@ -190,29 +207,32 @@ class XEP_0115(BasePlugin):
|
|||||||
form_types = []
|
form_types = []
|
||||||
deduped_form_types = set()
|
deduped_form_types = set()
|
||||||
for stanza in caps['substanzas']:
|
for stanza in caps['substanzas']:
|
||||||
if isinstance(stanza, self.xmpp['xep_0004'].stanza.Form):
|
if not isinstance(stanza, self.xmpp['xep_0004'].stanza.Form):
|
||||||
if 'FORM_TYPE' in stanza['fields']:
|
log.debug("Non form extension found, ignoring for caps")
|
||||||
f_type = tuple(stanza['fields']['FORM_TYPE']['value'])
|
caps.xml.remove(stanza.xml)
|
||||||
form_types.append(f_type)
|
continue
|
||||||
deduped_form_types.add(f_type)
|
if 'FORM_TYPE' in stanza['fields']:
|
||||||
if len(form_types) != len(deduped_form_types):
|
f_type = tuple(stanza['fields']['FORM_TYPE']['value'])
|
||||||
log.debug("Duplicated FORM_TYPE values, " + \
|
form_types.append(f_type)
|
||||||
"invalid for caps")
|
deduped_form_types.add(f_type)
|
||||||
|
if len(form_types) != len(deduped_form_types):
|
||||||
|
log.debug("Duplicated FORM_TYPE values, " + \
|
||||||
|
"invalid for caps")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if len(f_type) > 1:
|
||||||
|
deduped_type = set(f_type)
|
||||||
|
if len(f_type) != len(deduped_type):
|
||||||
|
log.debug("Extra FORM_TYPE data, invalid for caps")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if len(f_type) > 1:
|
if stanza['fields']['FORM_TYPE']['type'] != 'hidden':
|
||||||
deduped_type = set(f_type)
|
log.debug("Field FORM_TYPE type not 'hidden', " + \
|
||||||
if len(f_type) != len(deduped_type):
|
"ignoring form for caps")
|
||||||
log.debug("Extra FORM_TYPE data, invalid for caps")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if stanza['fields']['FORM_TYPE']['type'] != 'hidden':
|
|
||||||
log.debug("Field FORM_TYPE type not 'hidden', " + \
|
|
||||||
"ignoring form for caps")
|
|
||||||
caps.xml.remove(stanza.xml)
|
|
||||||
else:
|
|
||||||
log.debug("No FORM_TYPE found, ignoring form for caps")
|
|
||||||
caps.xml.remove(stanza.xml)
|
caps.xml.remove(stanza.xml)
|
||||||
|
else:
|
||||||
|
log.debug("No FORM_TYPE found, ignoring form for caps")
|
||||||
|
caps.xml.remove(stanza.xml)
|
||||||
|
|
||||||
verstring = self.generate_verstring(caps, hash)
|
verstring = self.generate_verstring(caps, hash)
|
||||||
if verstring != check_verstring:
|
if verstring != check_verstring:
|
||||||
@ -272,7 +292,7 @@ class XEP_0115(BasePlugin):
|
|||||||
binary = hash(S.encode('utf8')).digest()
|
binary = hash(S.encode('utf8')).digest()
|
||||||
return base64.b64encode(binary).decode('utf-8')
|
return base64.b64encode(binary).decode('utf-8')
|
||||||
|
|
||||||
def update_caps(self, jid=None, node=None):
|
def update_caps(self, jid=None, node=None, preserve=False):
|
||||||
try:
|
try:
|
||||||
info = self.xmpp['xep_0030'].get_info(jid, node, local=True)
|
info = self.xmpp['xep_0030'].get_info(jid, node, local=True)
|
||||||
if isinstance(info, Iq):
|
if isinstance(info, Iq):
|
||||||
@ -286,19 +306,11 @@ class XEP_0115(BasePlugin):
|
|||||||
self.assign_verstring(jid, ver)
|
self.assign_verstring(jid, ver)
|
||||||
|
|
||||||
if self.xmpp.session_started_event.is_set() and self.broadcast:
|
if self.xmpp.session_started_event.is_set() and self.broadcast:
|
||||||
# Check if we've sent directed presence. If we haven't, we
|
if self.xmpp.is_component or preserve:
|
||||||
# can just send a normal presence stanza. If we have, then
|
|
||||||
# we will send presence to each contact individually so
|
|
||||||
# that we don't clobber existing statuses.
|
|
||||||
directed = False or self.xmpp.is_component
|
|
||||||
for contact in self.xmpp.roster[jid]:
|
|
||||||
if self.xmpp.roster[jid][contact].last_status is not None:
|
|
||||||
directed = True
|
|
||||||
if not directed:
|
|
||||||
self.xmpp.roster[jid].send_last_presence()
|
|
||||||
else:
|
|
||||||
for contact in self.xmpp.roster[jid]:
|
for contact in self.xmpp.roster[jid]:
|
||||||
self.xmpp.roster[jid][contact].send_last_presence()
|
self.xmpp.roster[jid][contact].send_last_presence()
|
||||||
|
else:
|
||||||
|
self.xmpp.roster[jid].send_last_presence()
|
||||||
except XMPPError:
|
except XMPPError:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user