Merge branch 'master' into develop

This commit is contained in:
Lance Stout 2012-07-16 20:13:35 -07:00
commit 78f0325398
53 changed files with 455 additions and 55 deletions

View File

@ -45,7 +45,7 @@ The latest source code for SleekXMPP may be found on `Github
``develop`` branch.
**Latest Release**
- `1.1.7 <http://github.com/fritzy/SleekXMPP/zipball/1.1.7>`_
- `1.1.8 <http://github.com/fritzy/SleekXMPP/zipball/1.1.8>`_
**Develop Releases**
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_

View File

@ -122,6 +122,19 @@ if __name__ == '__main__':
xmpp.register_plugin('xep_0060') # PubSub
xmpp.register_plugin('xep_0199') # XMPP Ping
# If you are connecting to Facebook and wish to use the
# X-FACEBOOK-PLATFORM authentication mechanism, you will need
# your API key and an access token. Then you'll set:
# xmpp.credentials['api_key'] = 'THE_API_KEY'
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
# If you are connecting to MSN, then you will need an
# access token, and it does not matter what JID you
# specify other than that the domain is 'messenger.live.com',
# so '_@messenger.live.com' will work. You can specify
# the access token as so:
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3

View File

@ -86,6 +86,7 @@ packages = [ 'sleekxmpp',
'sleekxmpp/plugins/xep_0172',
'sleekxmpp/plugins/xep_0184',
'sleekxmpp/plugins/xep_0186',
'sleekxmpp/plugins/xep_0191',
'sleekxmpp/plugins/xep_0198',
'sleekxmpp/plugins/xep_0199',
'sleekxmpp/plugins/xep_0202',

View File

@ -99,7 +99,7 @@ class APIRegistry(object):
"""
self._setup(ctype, op)
if jid in (None, ''):
if not jid:
jid = self.xmpp.boundjid
if jid and not isinstance(jid, JID):
jid = JID(jid)
@ -113,7 +113,7 @@ class APIRegistry(object):
else:
jid = jid.full
else:
if self.settings[ctype].get('client_bare', True):
if self.settings[ctype].get('client_bare', False):
jid = jid.bare
else:
jid = jid.full

View File

@ -16,6 +16,7 @@ from __future__ import with_statement, unicode_literals
import sys
import logging
import threading
import sleekxmpp
from sleekxmpp import plugins, features, roster
@ -69,8 +70,11 @@ class BaseXMPP(XMLStream):
#: The JabberID (JID) used by this connection.
self.boundjid = JID(jid)
self._expected_server_name = self.boundjid.host
self.session_bind_event = threading.Event()
#: A dictionary mapping plugin names to plugins.
self.plugin = PluginManager(self)
@ -655,6 +659,7 @@ class BaseXMPP(XMLStream):
def _handle_disconnected(self, event):
"""When disconnected, reset the roster"""
self.roster.reset()
self.session_bind_event.clear()
def _handle_stream_error(self, error):
self.event('stream_error', error)

View File

@ -173,6 +173,12 @@ class ClientXMPP(BaseXMPP):
self._stream_feature_order.append((order, name))
self._stream_feature_order.sort()
def unregister_feature(self, name, order):
if name in self._stream_feature_handlers:
del self._stream_feature_handlers[name]
self._stream_feature_order.remove((order, name))
self._stream_feature_order.sort()
def update_roster(self, jid, name=None, subscription=None, groups=[],
block=True, timeout=None, callback=None):
"""Add or change a roster item.

View File

@ -156,7 +156,9 @@ class ComponentXMPP(BaseXMPP):
:param xml: The reply handshake stanza.
"""
self.session_bind_event.set()
self.session_started_event.set()
self.event("session_bind", self.xmpp.boundjid.full, direct=True)
self.event("session_start")
def _handle_probe(self, presence):

View File

@ -50,7 +50,8 @@ class FeatureBind(BasePlugin):
self.xmpp.set_jid(response['bind']['jid'])
self.xmpp.bound = True
self.xmpp.event('session_bind', self.xmpp.boundjid, direct=True)
self.xmpp.event('session_bind', self.xmpp.boundjid.full, direct=True)
self.xmpp.session_bind_event.set()
self.xmpp.features.add('bind')

View File

@ -47,6 +47,7 @@ __all__ = [
'xep_0172', # User Nickname
'xep_0184', # Message Receipts
'xep_0186', # Invisible Command
'xep_0191', # Simple Communications Blocking
'xep_0198', # Stream Management
'xep_0199', # Ping
'xep_0202', # Entity Time

View File

@ -167,8 +167,7 @@ class PluginManager(object):
self._plugins[name] = plugin
for dep in plugin.dependencies:
self.enable(dep, enabled=enabled)
plugin.plugin_init()
log.debug("Loaded Plugin: %s", plugin.description)
plugin._init()
if top_level:
for name in enabled:
@ -229,7 +228,7 @@ class PluginManager(object):
raise PluginNotFound(name)
for dep in PLUGIN_DEPENDENTS[name]:
self.disable(dep, _disabled)
plugin.plugin_end()
plugin._end()
if name in self._enabled:
self._enabled.remove(name)
del self._plugins[name]
@ -282,6 +281,28 @@ class BasePlugin(object):
#: configuration settings will be provided as a dictionary.
self.config = config if config is not None else {}
def _init(self):
"""Initialize plugin state, such as registering event handlers.
Also sets up required event handlers.
"""
if self.xmpp is not None:
self.xmpp.add_event_handler('session_bind', self.session_bind)
if self.xmpp.session_bind_event.is_set():
self.session_bind(self.xmpp.boundjid.full)
self.plugin_init()
log.debug('Loaded Plugin: %s', self.description)
def _end(self):
"""Cleanup plugin state, and prepare for plugin removal.
Also removes required event handlers.
"""
if self.xmpp is not None:
self.xmpp.del_event_handler('session_bind', self.session_bind)
self.plugin_end()
log.debug('Disabled Plugin: %s' % self.description)
def plugin_init(self):
"""Initialize plugin state, such as registering event handlers."""
pass
@ -290,6 +311,10 @@ class BasePlugin(object):
"""Cleanup plugin state, and prepare for plugin removal."""
pass
def session_bind(self, jid):
"""Initialize plugin state based on the bound JID."""
pass
def post_init(self):
"""Initialize any cross-plugin state.

View File

@ -27,7 +27,7 @@ class XEP_0004(BasePlugin):
stanza = stanza
def plugin_init(self):
self.xmpp.registerHandler(
self.xmpp.register_handler(
Callback('Data Form',
StanzaPath('message/form'),
self.handle_form))
@ -36,6 +36,11 @@ class XEP_0004(BasePlugin):
register_stanza_plugin(Form, FormField, iterable=True)
register_stanza_plugin(Message, Form)
def plugin_end(self):
self.xmpp.remove_handler('Data Form')
self.xmpp['xep_0030'].del_feature(feature='jabber:x:data')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('jabber:x:data')
def make_form(self, ftype='form', title='', instructions=''):

View File

@ -37,13 +37,11 @@ class XEP_0012(BasePlugin):
self._last_activities = {}
self.xmpp.registerHandler(
self.xmpp.register_handler(
Callback('Last Activity',
StanzaPath('iq@type=get/last_activity'),
self._handle_get_last_activity))
self.xmpp.plugin['xep_0030'].add_feature('jabber:iq:last')
self.api.register(self._default_get_last_activity,
'get_last_activity',
default=True)
@ -54,6 +52,13 @@ class XEP_0012(BasePlugin):
'del_last_activity',
default=True)
def plugin_end(self):
self.xmpp.remove_handler('Last Activity')
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('jabber:iq:last')
def begin_idle(self, jid=None, status=None):
self.set_last_activity(jid, 0, status)

View File

@ -79,6 +79,13 @@ class XEP_0027(BasePlugin):
StanzaPath('message/encrypted'),
self._handle_encrypted_message))
def plugin_end(self):
self.xmpp.remove_handler('Encrypted Message')
self.xmpp.remove_handler('Signed Presence')
self.xmpp.del_filter('out', self._sign_presence)
self.xmpp.del_event_handler('unverified_signed_presence',
self._handle_unverified_signed_presence)
def _sign_presence(self, stanza):
if isinstance(stanza, Presence):
if stanza['type'] == 'available' or \

View File

@ -622,11 +622,7 @@ class XEP_0030(BasePlugin):
if iq['type'] == 'get':
log.debug("Received disco info query from " + \
"<%s> to <%s>.", iq['from'], iq['to'])
if self.xmpp.is_component:
jid = iq['to'].full
else:
jid = iq['to'].bare
info = self.api['get_info'](jid,
info = self.api['get_info'](iq['to'],
iq['disco_info']['node'],
iq['from'],
iq)
@ -649,7 +645,7 @@ class XEP_0030(BasePlugin):
ito = iq['to'].full
else:
ito = None
self.api['cache_info'](iq['from'].full,
self.api['cache_info'](iq['from'],
iq['disco_info']['node'],
ito,
iq)
@ -667,13 +663,9 @@ class XEP_0030(BasePlugin):
if iq['type'] == 'get':
log.debug("Received disco items query from " + \
"<%s> to <%s>.", iq['from'], iq['to'])
if self.xmpp.is_component:
jid = iq['to'].full
else:
jid = iq['to'].bare
items = self.api['get_items'](jid,
items = self.api['get_items'](iq['to'],
iq['disco_items']['node'],
iq['from'].full,
iq['from'],
iq)
if isinstance(items, Iq):
items.send()

View File

@ -237,7 +237,7 @@ class StaticDisco(object):
with self.lock:
if not self.node_exists(jid, node):
if not node:
return DiscoInfo()
return DiscoItems()
else:
raise XMPPError(condition='item-not-found')
else:
@ -424,9 +424,6 @@ class StaticDisco(object):
The data parameter is not used.
"""
with self.lock:
if isinstance(jid, JID):
jid = jid.full
if not self.node_exists(jid, node, ifrom):
return None
else:

View File

@ -26,7 +26,12 @@ class XEP_0033(BasePlugin):
stanza = stanza
def plugin_init(self):
self.xmpp['xep_0030'].add_feature(Addresses.namespace)
register_stanza_plugin(Message, Addresses)
register_stanza_plugin(Presence, Addresses)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=Addresses.namespace)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(Addresses.namespace)

View File

@ -51,6 +51,13 @@ class XEP_0047(BasePlugin):
StanzaPath('iq@type=set/ibb_data'),
self._handle_data))
def plugin_end(self):
self.xmpp.remove_handler('IBB Open')
self.xmpp.remove_handler('IBB Close')
self.xmpp.remove_handler('IBB 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 _accept_stream(self, iq):

View File

@ -110,6 +110,20 @@ class XEP_0050(BasePlugin):
self._handle_command_complete,
threaded=self.threaded)
def plugin_end(self):
self.xmpp.del_event_handler('command_execute',
self._handle_command_start)
self.xmpp.del_event_handler('command_next',
self._handle_command_next)
self.xmpp.del_event_handler('command_cancel',
self._handle_command_cancel)
self.xmpp.del_event_handler('command_complete',
self._handle_command_complete)
self.xmpp.remove_handler('Ad-Hoc Execute')
self.xmpp['xep_0030'].del_feature(feature=Command.namespace)
self.xmpp['xep_0030'].set_items(node=Command.namespace, items=tuple())
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(Command.namespace)
self.xmpp['xep_0030'].set_items(node=Command.namespace, items=tuple())

View File

@ -37,7 +37,6 @@ class XEP_0054(BasePlugin):
"""
register_stanza_plugin(Iq, VCardTemp)
self.xmpp['xep_0030'].add_feature('vcard-temp')
self.api.register(self._set_vcard, 'set_vcard', default=True)
self.api.register(self._get_vcard, 'get_vcard', default=True)
@ -50,6 +49,13 @@ class XEP_0054(BasePlugin):
StanzaPath('iq/vcard_temp'),
self._handle_get_vcard))
def plugin_end(self):
self.xmpp.remove_handler('VCardTemp')
self.xmpp['xep_0030'].del_feature(feature='vcard-temp')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('vcard-temp')
def make_vcard(self):
return VCardTemp()

View File

@ -47,6 +47,7 @@ class ResultIterator():
self.start = start
self.interface = interface
self.reverse = reverse
self._stop = False
def __iter__(self):
return self
@ -62,6 +63,8 @@ class ResultIterator():
results will be the items before the current page
of items.
"""
if self._stop:
raise StopIteration
self.query[self.interface]['rsm']['before'] = self.reverse
self.query['id'] = self.query.stream.new_id()
self.query[self.interface]['rsm']['max'] = str(self.amount)
@ -84,7 +87,7 @@ class ResultIterator():
first = int(r[self.interface]['rsm']['first_index'])
num_items = len(r[self.interface]['substanzas'])
if first + num_items == count:
raise StopIteration
self._stop = True
if self.reverse:
self.start = r[self.interface]['rsm']['first']
@ -111,10 +114,15 @@ class XEP_0059(BasePlugin):
"""
Start the XEP-0059 plugin.
"""
self.xmpp['xep_0030'].add_feature(Set.namespace)
register_stanza_plugin(self.xmpp['xep_0030'].stanza.DiscoItems,
self.stanza.Set)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=Set.namespace)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(Set.namespace)
def iterate(self, stanza, interface):
"""
Create a new result set iterator for a given stanza query.

View File

@ -53,6 +53,13 @@ class XEP_0060(BasePlugin):
StanzaPath('message/pubsub_event/subscription'),
self._handle_event_subscription))
def plugin_end(self):
self.xmpp.remove_handler('Pubsub Event: Items')
self.xmpp.remove_handler('Pubsub Event: Purge')
self.xmpp.remove_handler('Pubsub Event: Delete')
self.xmpp.remove_handler('Pubsub Event: Configuration')
self.xmpp.remove_handler('Pubsub Event: Subscription')
def _handle_event_items(self, msg):
"""Raise events for publish and retraction notifications."""
node = msg['pubsub_event']['items']['node']

View File

@ -62,6 +62,12 @@ class XEP_0066(BasePlugin):
StanzaPath('iq@type=set/oob_transfer'),
self._handle_transfer))
def plugin_end(self):
self.xmpp.remove_handler('OOB Transfer')
self.xmpp['xep_0030'].del_feature(feature=stanza.OOBTransfer.namespace)
self.xmpp['xep_0030'].del_feature(feature=stanza.OOB.namespace)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(stanza.OOBTransfer.namespace)
self.xmpp['xep_0030'].add_feature(stanza.OOB.namespace)

View File

@ -34,9 +34,7 @@ class XEP_0077(BasePlugin):
register_stanza_plugin(StreamFeatures, RegisterFeature)
register_stanza_plugin(Iq, Register)
if self.xmpp.is_component:
pass
else:
if not self.xmpp.is_component:
self.xmpp.register_feature('register',
self._handle_register_feature,
restart=False,
@ -45,6 +43,10 @@ class XEP_0077(BasePlugin):
register_stanza_plugin(Register, self.xmpp['xep_0004'].stanza.Form)
register_stanza_plugin(Register, self.xmpp['xep_0066'].stanza.OOB)
def plugin_end(self):
if not self.xmpp.is_component:
self.xmpp.unregister_feature('register', self.config.get('order', 50))
def _handle_register_feature(self, features):
if 'mechanisms' in self.xmpp.features:
# We have already logged in with an account

View File

@ -44,6 +44,9 @@ class XEP_0078(BasePlugin):
register_stanza_plugin(Iq, stanza.IqAuth)
register_stanza_plugin(StreamFeatures, stanza.AuthFeature)
def plugin_end(self):
self.xmpp.unregister_feature('auth', self.config.get('order', 15))
def _handle_auth(self, features):
# If we can or have already authenticated with SASL, do nothing.
if 'mechanisms' in features['features']:

View File

@ -28,8 +28,11 @@ class XEP_0080(BasePlugin):
dependencies = set(['xep_0163'])
stanza = stanza
def plugin_init(self):
"""Start the XEP-0080 plugin."""
def plugin_end(self):
self.xmpp['xep_0163'].remove_interest(Geoloc.namespace)
self.xmpp['xep_0030'].del_feature(feature=Geoloc.namespace)
def session_bind(self, jid):
self.xmpp['xep_0163'].register_pep('user_location', Geoloc)
def publish_location(self, **kwargs):

View File

@ -28,14 +28,19 @@ class XEP_0084(BasePlugin):
stanza = stanza
def plugin_init(self):
self.xmpp['xep_0163'].register_pep('avatar_metadata', MetaData)
pubsub_stanza = self.xmpp['xep_0060'].stanza
register_stanza_plugin(pubsub_stanza.Item, Data)
register_stanza_plugin(pubsub_stanza.EventItem, Data)
self.xmpp['xep_0060'].map_node_event(Data.namespace, 'avatar_data')
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=MetaData.namespace)
self.xmpp['xep_0163'].remove_interest(MetaData.namespace)
def session_bind(self, jid):
self.xmpp['xep_0163'].register_pep('avatar_metadata', MetaData)
def retrieve_avatar(self, jid, id, url=None, ifrom=None, block=True,
callback=None, timeout=None):
return self.xmpp['xep_0060'].get_item(jid, Data.namespace, id,

View File

@ -43,6 +43,10 @@ class XEP_0085(BasePlugin):
register_stanza_plugin(Message, stanza.Inactive)
register_stanza_plugin(Message, stanza.Paused)
def plugin_end(self):
self.xmpp.remove_handler('Chat State')
def session_bind(self, jid):
self.xmpp.plugin['xep_0030'].add_feature(ChatState.namespace)
def _handle_chat_state(self, msg):

View File

@ -48,6 +48,11 @@ class XEP_0092(BasePlugin):
register_stanza_plugin(Iq, Version)
def plugin_end(self):
self.xmpp.remove_handler('Software Version')
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:version')
def session_bind(self, jid):
self.xmpp.plugin['xep_0030'].add_feature('jabber:iq:version')
def _handle_version(self, iq):

View File

@ -32,6 +32,12 @@ class XEP_0107(BasePlugin):
def plugin_init(self):
register_stanza_plugin(Message, UserMood)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=UserMood.namespace)
self.xmpp['xep_0163'].remove_interest(UserMood.namespace)
def session_bind(self, jid):
self.xmpp['xep_0163'].register_pep('user_mood', UserMood)
def publish_mood(self, value=None, text=None, options=None,

View File

@ -26,7 +26,11 @@ class XEP_0108(BasePlugin):
dependencies = set(['xep_0163'])
stanza = stanza
def plugin_init(self):
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=UserActivity.namespace)
self.xmpp['xep_0163'].remove_interest(UserActivity.namespace)
def session_bind(self, jid):
self.xmpp['xep_0163'].register_pep('user_activity', UserActivity)
def publish_activity(self, general, specific=None, text=None, options=None,

View File

@ -73,16 +73,15 @@ class XEP_0115(BasePlugin):
restart=False,
order=10010)
self.xmpp['xep_0030'].add_feature(stanza.Capabilities.namespace)
disco = self.xmpp['xep_0030']
self.static = StaticCaps(self.xmpp, disco.static)
self.api.settings['client_bare'] = False
self.api.settings['component_bare'] = False
for op in self._disco_ops:
self.api.register(getattr(self.static, op), op, default=True)
for op in ('supports', 'has_identity'):
self.xmpp['xep_0030'].api.register(getattr(self.static, op), op)
self._run_node_handler = disco._run_node_handler
disco.cache_caps = self.cache_caps
@ -90,6 +89,19 @@ class XEP_0115(BasePlugin):
disco.assign_verstring = self.assign_verstring
disco.get_verstring = self.get_verstring
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=stanza.Capabilities.namespace)
self.xmpp.del_filter('out', self._filter_add_caps)
self.xmpp.del_event_handler('entity_caps', self._process_caps)
self.xmpp.remove_handler('Entity Capabilities')
if not self.xmpp.is_component:
self.xmpp.unregister_feature('caps', 10010)
for op in ('supports', 'has_identity'):
self.xmpp['xep_0030'].restore_defaults(op)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(stanza.Capabilities.namespace)
def _filter_add_caps(self, stanza):
if isinstance(stanza, Presence) and self.broadcast:
ver = self.get_verstring(stanza['from'])

View File

@ -26,7 +26,11 @@ class XEP_0118(BasePlugin):
dependencies = set(['xep_0163'])
stanza = stanza
def plugin_init(self):
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=UserTune.namespace)
self.xmpp['xep_0163'].remove_interest(UserTune.namespace)
def session_bind(self, jid):
self.xmpp['xep_0163'].register_pep('user_tune', UserTune)
def publish_tune(self, artist=None, length=None, rating=None, source=None,

View File

@ -51,8 +51,6 @@ class XEP_0128(BasePlugin):
register_stanza_plugin(DiscoInfo, Form, iterable=True)
def post_init(self):
"""Handle cross-plugin dependencies."""
self.disco = self.xmpp['xep_0030']
self.static = StaticExtendedDisco(self.disco.static)

View File

@ -45,6 +45,15 @@ class XEP_0153(BasePlugin):
self.api.register(self._set_hash, 'set_hash', default=True)
self.api.register(self._get_hash, 'get_hash', default=True)
def plugin_end(self):
self.xmpp.del_filter('out', self._update_presence)
self.xmpp.del_event_handler('session_start', self._start)
self.xmpp.del_event_handler('presence_available', self._recv_presence)
self.xmpp.del_event_handler('presence_dnd', self._recv_presence)
self.xmpp.del_event_handler('presence_xa', self._recv_presence)
self.xmpp.del_event_handler('presence_chat', self._recv_presence)
self.xmpp.del_event_handler('presence_away', self._recv_presence)
def set_avatar(self, jid=None, avatar=None, mtype=None, block=True,
timeout=None, callback=None):
vcard = self.xmpp['xep_0054'].get_vcard(jid, cached=True)

View File

@ -74,7 +74,7 @@ class XEP_0163(BasePlugin):
be a list of such namespaces.
jid -- Optionally specify the JID.
"""
if not isinstance(namespace, set) and not isinstance(namespace, list):
if not isinstance(namespace, (set, list)):
namespace = [namespace]
for ns in namespace:

View File

@ -34,6 +34,12 @@ class XEP_0172(BasePlugin):
def plugin_init(self):
register_stanza_plugin(Message, UserNick)
register_stanza_plugin(Presence, UserNick)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=UserNick.namespace)
self.xmpp['xep_0163'].remove_interest(UserNick.namespace)
def session_bind(self, jid):
self.xmpp['xep_0163'].register_pep('user_nick', UserNick)
def publish_nick(self, nick=None, options=None, ifrom=None, block=True,

View File

@ -48,6 +48,13 @@ class XEP_0184(BasePlugin):
StanzaPath('message/request_receipt'),
self._handle_receipt_request))
def plugin_end(self):
self.xmpp['xep_0030'].del_feature('urn:xmpp:receipts')
self.xmpp.del_filter('out', self._filter_add_receipt_request)
self.xmpp.remove_handler('Message Receipt')
self.xmpp.remove_handler('Message Receipt Request')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:receipts')
def ack(self, msg):

View File

@ -0,0 +1,15 @@
"""
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_0191.stanza import Block, Unblock, BlockList
from sleekxmpp.plugins.xep_0191.blocking import XEP_0191
register_plugin(XEP_0191)

View File

@ -0,0 +1,83 @@
"""
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.
"""
import logging
from sleekxmpp import Iq
from sleekxmpp.plugins import BasePlugin
from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath
from sleekxmpp.xmlstream import register_stanza_plugin, JID
from sleekxmpp.plugins.xep_0191 import stanza, Block, Unblock, BlockList
log = logging.getLogger(__name__)
class XEP_0191(BasePlugin):
name = 'xep_0191'
description = 'XEP-0191: Simple Communications Blocking'
dependencies = set(['xep_0030'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, BlockList)
register_stanza_plugin(Iq, Block)
register_stanza_plugin(Iq, Unblock)
self.xmpp.register_handler(
Callback('Blocked Contact',
StanzaPath('iq@type=set/block'),
self._handle_blocked))
self.xmpp.register_handler(
Callback('Unblocked Contact',
StanzaPath('iq@type=set/unblock'),
self._handle_unblocked))
def plugin_end(self):
self.xmpp.remove_handler('Blocked Contact')
self.xmpp.remove_handler('Unblocked Contact')
def get_blocked(self, ifrom=None, block=True, timeout=None, callback=None):
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq['from'] = 'ifrom'
iq.enable('blocklist')
return iq.send(block=block, timeout=timeout, callback=callback)
def block(self, jids, ifrom=None, block=True, timeout=None, callback=None):
iq = self.xmpp.Iq()
iq['type'] = 'set'
iq['from'] = ifrom
if not isinstance(jids, (set, list)):
jids = [jids]
iq['block']['items'] = jids
return iq.send(block=block, timeout=timeout, callback=callback)
def unblock(self, jids=None, ifrom=None, block=True, timeout=None, callback=None):
iq = self.xmpp.Iq()
iq['type'] = 'set'
iq['from'] = ifrom
if jids is None:
jids = []
if not isinstance(jids, (set, list)):
jids = [jids]
iq['unblock']['items'] = jids
return iq.send(block=block, timeout=timeout, callback=callback)
def _handle_blocked(self, iq):
self.xmpp.event('blocked', iq)
def _handle_unblocked(self, iq):
self.xmpp.event('unblocked', iq)

View File

@ -0,0 +1,50 @@
"""
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.xmlstream import ET, ElementBase, JID
class BlockList(ElementBase):
name = 'blocklist'
namespace = 'urn:xmpp:blocking'
plugin_attrib = 'blocklist'
interfaces = set(['items'])
def get_items(self):
result = set()
items = self.xml.findall('{%s}item' % self.namespace)
if items is not None:
for item in items:
jid = JID(item.attrib.get('jid', ''))
if jid:
result.add(jid)
return result
def set_items(self, values):
self.del_items()
for jid in values:
if jid:
item = ET.Element('{%s}item' % self.namespace)
item.attrib['jid'] = JID(jid).full
self.xml.append(item)
def del_items(self):
items = self.xml.findall('{%s}item' % self.namespace)
if items is not None:
for item in items:
self.xml.remove(item)
class Block(BlockList):
name = 'block'
plugin_attrib = 'block'
class Unblock(BlockList):
name = 'unblock'
plugin_attrib = 'unblock'

View File

@ -133,6 +133,27 @@ class XEP_0198(BasePlugin):
self.xmpp.add_event_handler('session_end', self.session_end)
def plugin_end(self):
if self.xmpp.is_component:
return
self.xmpp.unregister_feature('sm', self.config.get('order', 10100))
self.xmpp.unregister_feature('sm', self.config.get('resume_order', 9000))
self.xmpp.del_event_handler('session_end', self.session_end)
self.xmpp.del_filter('in', self._handle_incoming)
self.xmpp.del_filter('out_sync', self._handle_outgoing)
self.xmpp.remove_handler('Stream Management Enabled')
self.xmpp.remove_handler('Stream Management Resumed')
self.xmpp.remove_handler('Stream Management Failed')
self.xmpp.remove_handler('Stream Management Ack')
self.xmpp.remove_handler('Stream Management Request Ack')
self.xmpp.remove_stanza(stanza.Enable)
self.xmpp.remove_stanza(stanza.Enabled)
self.xmpp.remove_stanza(stanza.Resume)
self.xmpp.remove_stanza(stanza.Resumed)
self.xmpp.remove_stanza(stanza.Ack)
self.xmpp.remove_stanza(stanza.RequestAck)
def session_end(self, event):
"""Reset stream management state."""
self.enabled.clear()

View File

@ -74,6 +74,16 @@ class XEP_0199(BasePlugin):
self.xmpp.add_event_handler('session_end',
self._handle_session_end)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=Ping.namespace)
self.xmpp.remove_handler('Ping')
if self.keepalive:
self.xmpp.del_event_handler('session_start',
self._handle_keepalive)
self.xmpp.del_event_handler('session_end',
self._handle_session_end)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(Ping.namespace)
def _handle_keepalive(self, event):

View File

@ -53,6 +53,11 @@ class XEP_0202(BasePlugin):
self._handle_time_request))
register_stanza_plugin(Iq, stanza.EntityTime)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time')
self.xmpp.remove_handler('Entity Time')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
def _handle_time_request(self, iq):

View File

@ -39,6 +39,11 @@ class XEP_0224(BasePlugin):
StanzaPath('message/attention'),
self._handle_attention))
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=stanza.Attention.namespace)
self.xmpp.remove_handler('Attention')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(stanza.Attention.namespace)
def request_attention(self, to, mfrom=None, mbody=''):

View File

@ -35,8 +35,6 @@ class XEP_0231(BasePlugin):
def plugin_init(self):
self._cids = {}
self.xmpp['xep_0030'].add_feature('urn:xmpp:bob')
register_stanza_plugin(Iq, BitsOfBinary)
self.xmpp.register_handler(
@ -58,6 +56,15 @@ class XEP_0231(BasePlugin):
self.api.register(self._set_bob, 'set_bob', default=True)
self.api.register(self._del_bob, 'del_bob', default=True)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:bob')
self.xmpp.remove_handler('Bits of Binary - Iq')
self.xmpp.remove_handler('Bits of Binary - Message')
self.xmpp.remove_handler('Bits of Binary - Presence')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:bob')
def set_bob(self, data, mtype, cid=None, max_age=None):
if cid is None:
cid = 'sha1+%s@bob.xmpp.org' % hashlib.sha1(data).hexdigest()

View File

@ -39,6 +39,11 @@ class XEP_0249(BasePlugin):
register_stanza_plugin(Message, Invite)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=Invite.namespace)
self.xmpp.remove_handler('Direct MUC Invitations')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(Invite.namespace)
def _handle_invite(self, msg):

View File

@ -9,6 +9,7 @@
import logging
from sleekxmpp import Presence
from sleekxmpp.exceptions import XMPPError
from sleekxmpp.plugins import BasePlugin, register_plugin
from sleekxmpp.xmlstream import register_stanza_plugin
@ -35,6 +36,10 @@ class XEP_0256(BasePlugin):
self._initial_presence = set()
def plugin_end(self):
self.xmpp.del_filter('out', self._initial_presence_activity)
self.xmpp.del_event_handler('connected', self._reset_presence_activity)
def _reset_presence_activity(self, e):
self._initial_presence = set()

View File

@ -25,11 +25,15 @@ class XEP_0258(BasePlugin):
stanza = stanza
def plugin_init(self):
self.xmpp['xep_0030'].add_feature(SecurityLabel.namespace)
register_stanza_plugin(Message, SecurityLabel)
register_stanza_plugin(Iq, Catalog)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature=SecurityLabel.namespace)
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature(SecurityLabel.namespace)
def get_catalog(self, jid, ifrom=None, block=True,
callback=None, timeout=None):
iq = self.xmpp.Iq()

View File

@ -15,6 +15,9 @@ def bytes(text):
:param text: Unicode text to convert to bytes
:rtype: bytes (Python3), str (Python2.6+)
"""
if text is None:
return b''
if sys.version_info < (3, 0):
import __builtin__
return __builtin__.bytes(text)

View File

@ -9,5 +9,5 @@
# We don't want to have to import the entire library
# just to get the version info for setup.py
__version__ = '1.1.7'
__version_info__ = (1, 1, 7, '', 0)
__version__ = '1.1.8'
__version_info__ = (1, 1, 8, '', 0)

View File

@ -254,6 +254,7 @@ def get_SRV(host, port, service, proto='tcp', resolver=None):
by SRV priorities and weights.
"""
if resolver is None:
log.warning("DNS: dnspython not found. Can not use SRV lookup.")
return [(host, port)]
log.debug("DNS: Querying SRV records for %s" % host)

View File

@ -172,6 +172,7 @@ class Scheduler(object):
else:
updated = True
self.schedule_lock.acquire()
if newtask is not None:
self.schedule.append(newtask)
finally:
if updated:

View File

@ -954,6 +954,10 @@ class XMLStream(object):
else:
self.__filters[mode].append(handler)
def del_filter(self, mode, handler):
"""Remove an incoming or outgoing filter."""
self.__filters[mode].remove(handler)
def add_handler(self, mask, pointer, name=None, disposable=False,
threaded=False, filter=False, instream=False):
"""A shortcut method for registering a handler using XML masks.