diff options
Diffstat (limited to 'sleekxmpp/plugins/xep_0047')
-rw-r--r-- | sleekxmpp/plugins/xep_0047/__init__.py | 21 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0047/ibb.py | 215 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0047/stanza.py | 67 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0047/stream.py | 148 |
4 files changed, 0 insertions, 451 deletions
diff --git a/sleekxmpp/plugins/xep_0047/__init__.py b/sleekxmpp/plugins/xep_0047/__init__.py deleted file mode 100644 index 5cd7df2e..00000000 --- a/sleekxmpp/plugins/xep_0047/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 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_0047 import stanza -from sleekxmpp.plugins.xep_0047.stanza import Open, Close, Data -from sleekxmpp.plugins.xep_0047.stream import IBBytestream -from sleekxmpp.plugins.xep_0047.ibb import XEP_0047 - - -register_plugin(XEP_0047) - - -# Retain some backwards compatibility -xep_0047 = XEP_0047 diff --git a/sleekxmpp/plugins/xep_0047/ibb.py b/sleekxmpp/plugins/xep_0047/ibb.py deleted file mode 100644 index 62dddac2..00000000 --- a/sleekxmpp/plugins/xep_0047/ibb.py +++ /dev/null @@ -1,215 +0,0 @@ -import uuid -import logging -import threading - -from sleekxmpp import Message, Iq -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0047 import stanza, Open, Close, Data, IBBytestream - - -log = logging.getLogger(__name__) - - -class XEP_0047(BasePlugin): - - name = 'xep_0047' - description = 'XEP-0047: In-band Bytestreams' - dependencies = set(['xep_0030']) - stanza = stanza - default_config = { - 'block_size': 4096, - 'max_block_size': 8192, - 'window_size': 1, - 'auto_accept': False, - } - - def plugin_init(self): - self._streams = {} - self._pending_streams = {} - self._pending_lock = threading.Lock() - self._stream_lock = threading.Lock() - - self._preauthed_sids_lock = threading.Lock() - self._preauthed_sids = {} - - register_stanza_plugin(Iq, Open) - register_stanza_plugin(Iq, Close) - register_stanza_plugin(Iq, Data) - register_stanza_plugin(Message, Data) - - self.xmpp.register_handler(Callback( - 'IBB Open', - StanzaPath('iq@type=set/ibb_open'), - self._handle_open_request)) - - self.xmpp.register_handler(Callback( - 'IBB Close', - StanzaPath('iq@type=set/ibb_close'), - self._handle_close)) - - self.xmpp.register_handler(Callback( - 'IBB Data', - StanzaPath('iq@type=set/ibb_data'), - self._handle_data)) - - self.xmpp.register_handler(Callback( - 'IBB Message Data', - StanzaPath('message/ibb_data'), - self._handle_data)) - - self.api.register(self._authorized, 'authorized', default=True) - self.api.register(self._authorized_sid, 'authorized_sid', default=True) - self.api.register(self._preauthorize_sid, 'preauthorize_sid', default=True) - self.api.register(self._get_stream, 'get_stream', default=True) - self.api.register(self._set_stream, 'set_stream', default=True) - self.api.register(self._del_stream, 'del_stream', default=True) - - def plugin_end(self): - self.xmpp.remove_handler('IBB Open') - self.xmpp.remove_handler('IBB Close') - 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') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('http://jabber.org/protocol/ibb') - - def _get_stream(self, jid, sid, peer_jid, data): - return self._streams.get((jid, sid, peer_jid), None) - - def _set_stream(self, jid, sid, peer_jid, stream): - self._streams[(jid, sid, peer_jid)] = stream - - def _del_stream(self, jid, sid, peer_jid, data): - with self._stream_lock: - if (jid, sid, peer_jid) in self._streams: - del self._streams[(jid, sid, peer_jid)] - - def _accept_stream(self, iq): - receiver = iq['to'] - sender = iq['from'] - sid = iq['ibb_open']['sid'] - - if self.api['authorized_sid'](receiver, sid, sender, iq): - return True - return self.api['authorized'](receiver, sid, sender, iq) - - def _authorized(self, jid, sid, ifrom, iq): - if self.auto_accept: - if iq['ibb_open']['block_size'] <= self.max_block_size: - return True - return False - - def _authorized_sid(self, jid, sid, ifrom, iq): - with self._preauthed_sids_lock: - if (jid, sid, ifrom) in self._preauthed_sids: - del self._preauthed_sids[(jid, sid, ifrom)] - return True - return False - - def _preauthorize_sid(self, jid, sid, ifrom, data): - with self._preauthed_sids_lock: - self._preauthed_sids[(jid, sid, ifrom)] = True - - def open_stream(self, jid, block_size=None, sid=None, window=1, use_messages=False, - ifrom=None, block=True, timeout=None, callback=None): - if sid is None: - sid = str(uuid.uuid4()) - if block_size is None: - block_size = self.block_size - - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = jid - iq['from'] = ifrom - iq['ibb_open']['block_size'] = block_size - iq['ibb_open']['sid'] = sid - iq['ibb_open']['stanza'] = 'iq' - - stream = IBBytestream(self.xmpp, sid, block_size, - iq['from'], iq['to'], window, - use_messages) - - with self._stream_lock: - self._pending_streams[iq['id']] = stream - - self._pending_streams[iq['id']] = stream - - if block: - resp = iq.send(timeout=timeout) - self._handle_opened_stream(resp) - return stream - else: - cb = None - if callback is not None: - def chained(resp): - self._handle_opened_stream(resp) - callback(resp) - cb = chained - else: - cb = self._handle_opened_stream - return iq.send(block=block, timeout=timeout, callback=cb) - - def _handle_opened_stream(self, iq): - if iq['type'] == 'result': - with self._stream_lock: - stream = self._pending_streams.get(iq['id'], None) - if stream is not None: - log.debug('IBB stream (%s) accepted by %s', stream.sid, iq['from']) - stream.self_jid = iq['to'] - stream.peer_jid = iq['from'] - stream.stream_started.set() - self.api['set_stream'](stream.self_jid, stream.sid, stream.peer_jid, stream) - self.xmpp.event('ibb_stream_start', stream) - self.xmpp.event('stream:%s:%s' % (stream.sid, stream.peer_jid), stream) - - with self._stream_lock: - if iq['id'] in self._pending_streams: - del self._pending_streams[iq['id']] - - def _handle_open_request(self, iq): - sid = iq['ibb_open']['sid'] - size = iq['ibb_open']['block_size'] or self.block_size - - log.debug('Received IBB stream request from %s', iq['from']) - - if not sid: - raise XMPPError(etype='modify', condition='bad-request') - - if not self._accept_stream(iq): - raise XMPPError(etype='modify', condition='not-acceptable') - - if size > self.max_block_size: - raise XMPPError('resource-constraint') - - stream = IBBytestream(self.xmpp, sid, size, - iq['to'], iq['from'], - self.window_size) - stream.stream_started.set() - self.api['set_stream'](stream.self_jid, stream.sid, stream.peer_jid, stream) - iq.reply() - iq.send() - - self.xmpp.event('ibb_stream_start', stream) - self.xmpp.event('stream:%s:%s' % (sid, stream.peer_jid), stream) - - def _handle_data(self, stanza): - sid = stanza['ibb_data']['sid'] - stream = self.api['get_stream'](stanza['to'], sid, stanza['from']) - if stream is not None and stanza['from'] == stream.peer_jid: - stream._recv_data(stanza) - else: - raise XMPPError('item-not-found') - - def _handle_close(self, iq): - sid = iq['ibb_close']['sid'] - stream = self.api['get_stream'](iq['to'], sid, iq['from']) - if stream is not None and iq['from'] == stream.peer_jid: - stream._closed(iq) - self.api['del_stream'](stream.self_jid, stream.sid, stream.peer_jid) - else: - raise XMPPError('item-not-found') diff --git a/sleekxmpp/plugins/xep_0047/stanza.py b/sleekxmpp/plugins/xep_0047/stanza.py deleted file mode 100644 index 7e5d2fed..00000000 --- a/sleekxmpp/plugins/xep_0047/stanza.py +++ /dev/null @@ -1,67 +0,0 @@ -import re -import base64 - -from sleekxmpp.util import bytes -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import ElementBase - - -VALID_B64 = re.compile(r'[A-Za-z0-9\+\/]*=*') - - -def to_b64(data): - return bytes(base64.b64encode(bytes(data))).decode('utf-8') - - -def from_b64(data): - return bytes(base64.b64decode(bytes(data))) - - -class Open(ElementBase): - name = 'open' - namespace = 'http://jabber.org/protocol/ibb' - plugin_attrib = 'ibb_open' - interfaces = set(('block_size', 'sid', 'stanza')) - - def get_block_size(self): - return int(self._get_attr('block-size')) - - def set_block_size(self, value): - self._set_attr('block-size', str(value)) - - def del_block_size(self): - self._del_attr('block-size') - - -class Data(ElementBase): - name = 'data' - namespace = 'http://jabber.org/protocol/ibb' - plugin_attrib = 'ibb_data' - interfaces = set(('seq', 'sid', 'data')) - sub_interfaces = set(['data']) - - def get_seq(self): - return int(self._get_attr('seq', '0')) - - def set_seq(self, value): - self._set_attr('seq', str(value)) - - def get_data(self): - b64_data = self.xml.text.strip() - if VALID_B64.match(b64_data).group() == b64_data: - return from_b64(b64_data) - else: - raise XMPPError('not-acceptable') - - def set_data(self, value): - self.xml.text = to_b64(value) - - def del_data(self): - self.xml.text = '' - - -class Close(ElementBase): - name = 'close' - namespace = 'http://jabber.org/protocol/ibb' - plugin_attrib = 'ibb_close' - interfaces = set(['sid']) diff --git a/sleekxmpp/plugins/xep_0047/stream.py b/sleekxmpp/plugins/xep_0047/stream.py deleted file mode 100644 index 9651edf8..00000000 --- a/sleekxmpp/plugins/xep_0047/stream.py +++ /dev/null @@ -1,148 +0,0 @@ -import socket -import threading -import logging - -from sleekxmpp.stanza import Iq -from sleekxmpp.util import Queue -from sleekxmpp.exceptions import XMPPError - - -log = logging.getLogger(__name__) - - -class IBBytestream(object): - - def __init__(self, xmpp, sid, block_size, jid, peer, window_size=1, use_messages=False): - self.xmpp = xmpp - self.sid = sid - self.block_size = block_size - self.window_size = window_size - self.use_messages = use_messages - - if jid is None: - jid = xmpp.boundjid - self.self_jid = jid - self.peer_jid = peer - - self.send_seq = -1 - self.recv_seq = -1 - - self._send_seq_lock = threading.Lock() - self._recv_seq_lock = threading.Lock() - - self.stream_started = threading.Event() - self.stream_in_closed = threading.Event() - self.stream_out_closed = threading.Event() - - self.recv_queue = Queue() - - self.send_window = threading.BoundedSemaphore(value=self.window_size) - self.window_ids = set() - self.window_empty = threading.Event() - self.window_empty.set() - - def send(self, data): - if not self.stream_started.is_set() or \ - self.stream_out_closed.is_set(): - raise socket.error - data = data[0:self.block_size] - self.send_window.acquire() - with self._send_seq_lock: - self.send_seq = (self.send_seq + 1) % 65535 - seq = self.send_seq - if self.use_messages: - msg = self.xmpp.Message() - msg['to'] = self.peer_jid - msg['from'] = self.self_jid - msg['id'] = self.xmpp.new_id() - msg['ibb_data']['sid'] = self.sid - msg['ibb_data']['seq'] = seq - msg['ibb_data']['data'] = data - msg.send() - self.send_window.release() - else: - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = self.peer_jid - iq['from'] = self.self_jid - 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) - - def sendall(self, data): - sent_len = 0 - while sent_len < len(data): - sent_len += self.send(data[sent_len:]) - - def _recv_ack(self, iq): - self.window_ids.remove(iq['id']) - if not self.window_ids: - self.window_empty.set() - self.send_window.release() - if iq['type'] == 'error': - self.close() - - def _recv_data(self, stanza): - with self._recv_seq_lock: - new_seq = stanza['ibb_data']['seq'] - if new_seq != (self.recv_seq + 1) % 65535: - self.close() - raise XMPPError('unexpected-request') - self.recv_seq = new_seq - - data = stanza['ibb_data']['data'] - if len(data) > self.block_size: - self.close() - raise XMPPError('not-acceptable') - - self.recv_queue.put(data) - self.xmpp.event('ibb_stream_data', {'stream': self, 'data': data}) - - if isinstance(stanza, Iq): - stanza.reply() - stanza.send() - - def recv(self, *args, **kwargs): - return self.read(block=True) - - def read(self, block=True, timeout=None, **kwargs): - if not self.stream_started.is_set() or \ - self.stream_in_closed.is_set(): - raise socket.error - if timeout is not None: - block = True - try: - return self.recv_queue.get(block, timeout) - except: - return None - - def close(self): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = self.peer_jid - iq['from'] = self.self_jid - iq['ibb_close']['sid'] = self.sid - self.stream_out_closed.set() - iq.send(block=False, - callback=lambda x: self.stream_in_closed.set()) - self.xmpp.event('ibb_stream_end', self) - - def _closed(self, iq): - self.stream_in_closed.set() - self.stream_out_closed.set() - iq.reply() - iq.send() - self.xmpp.event('ibb_stream_end', self) - - def makefile(self, *args, **kwargs): - return self - - def connect(*args, **kwargs): - return None - - def shutdown(self, *args, **kwargs): - return None |