Compare commits

..

1 Commits

Author SHA1 Message Date
mathieui
4512248901 Merge branch 'develop' of https://github.com/fritzy/SleekXMPP into sleek-merge
Conflicts:
	README.rst
	examples/IoT_TestDevice.py
	examples/disco_browser.py
	setup.py
	sleekxmpp/jid.py
	sleekxmpp/plugins/google/auth/stanza.py
	sleekxmpp/plugins/google/gmail/notifications.py
	sleekxmpp/plugins/google/nosave/stanza.py
	sleekxmpp/plugins/google/settings/settings.py
	sleekxmpp/thirdparty/__init__.py
	sleekxmpp/thirdparty/socks.py
	sleekxmpp/thirdparty/statemachine.py
	sleekxmpp/util/__init__.py
	sleekxmpp/xmlstream/xmlstream.py
	slixmpp/basexmpp.py
	slixmpp/plugins/xep_0004/stanza/form.py
	slixmpp/plugins/xep_0009/rpc.py
	slixmpp/plugins/xep_0050/adhoc.py
	slixmpp/plugins/xep_0065/proxy.py
	slixmpp/plugins/xep_0084/stanza.py
	slixmpp/plugins/xep_0202/time.py
	slixmpp/plugins/xep_0323/sensordata.py
	slixmpp/plugins/xep_0325/control.py
	slixmpp/plugins/xep_0325/stanza/control.py
	slixmpp/roster/single.py
	slixmpp/stanza/atom.py
	slixmpp/stanza/rootstanza.py
	slixmpp/test/slixtest.py
	slixmpp/util/sasl/mechanisms.py
	slixmpp/version.py
	slixmpp/xmlstream/stanzabase.py
	tests/test_stanza_xep_0323.py
	tests/test_stanza_xep_0325.py
	tests/test_stream_xep_0323.py
	tests/test_stream_xep_0325.py
2015-09-23 23:15:09 +02:00
256 changed files with 1365 additions and 1861 deletions

View File

@@ -1,14 +0,0 @@
Contributing to the Slixmpp project
===================================
To contribute, the preferred way is to commit your changes on some
publicly-available git repository (on a fork `on github
<https://github.com/poezio/slixmpp>`_ or on your own repository) and to
notify the developers with either:
- a ticket `on the bug tracker <https://dev.poez.io/new>`_
- a pull request on github
- a simple message on `the XMPP MUC <xmpp:slixmpp@muc.poez.io>`_
Even though Slixmpps github repository is just a read-only mirror, we can
still be notified of the pull requests and fetch your mirror manually to
integrate your changes.

View File

@@ -8,15 +8,6 @@ Slixmpp's goals is to only rewrite the core of the library (the low level
socket handling, the timers, the events dispatching) in order to remove all socket handling, the timers, the events dispatching) in order to remove all
threads. threads.
Building
--------
Slixmpp can make use of cython to improve performance on critical modules.
To do that, **cython3** is necessary along with **libidn** headers.
Otherwise, no compilation is needed. Building is done by running setup.py::
python3 setup.py build_ext --inplace
Documentation and Testing Documentation and Testing
------------------------- -------------------------
Documentation can be found both inline in the code, and as a Sphinx project in ``/docs``. Documentation can be found both inline in the code, and as a Sphinx project in ``/docs``.
@@ -102,17 +93,8 @@ Slixmpp projects::
Slixmpp Credits Slixmpp Credits
--------------- ---------------
**Maintainers:** **Maintainer of the slixmpp fork:** Florent Le Coz
- Florent Le Coz (`louiz@louiz.org <xmpp:louiz@louiz.org?message>`_), `louiz@louiz.org <xmpp:louiz@louiz.org?message>`_,
- Mathieu Pasquet (`mathieui@mathieui.net <xmpp:mathieui@mathieui.net?message>`_),
**Contributors:**
- Emmanuel Gil Peyrot (`Link mauve <xmpp:linkmauve@linkmauve.fr?message>`_)
- Sam Whited (`Sam Whited <mailto:sam@samwhited.com>`_)
- Dan Sully (`Dan Sully <mailto:daniel@electricalrain.com>`_)
- Gasper Zejn (`Gasper Zejn <mailto:zejn@kiberpipa.org>`_)
- Krzysztof Kotlenga (`Krzysztof Kotlenga <mailto:pocek@users.sf.net>`_)
- Tsukasa Hiiragi (`Tsukasa Hiiragi <mailto:bakalolka@gmail.com>`_)
Credits (SleekXMPP) Credits (SleekXMPP)
------------------- -------------------

View File

@@ -48,9 +48,9 @@ copyright = u'2011, Nathan Fritz, Lance Stout'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '1.1' version = '1.0'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '1.1' release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@@ -163,7 +163,7 @@ behaviour:
namespace = 'jabber:iq:register' namespace = 'jabber:iq:register'
name = 'query' name = 'query'
plugin_attrib = 'register' plugin_attrib = 'register'
interfaces = {'username', 'password', 'registered', 'remove'} interfaces = set(('username', 'password', 'registered', 'remove'))
sub_interfaces = interfaces sub_interfaces = interfaces
def getRegistered(self): def getRegistered(self):
@@ -535,10 +535,10 @@ with some additional registration fields implemented.
namespace = 'jabber:iq:register' namespace = 'jabber:iq:register'
name = 'query' name = 'query'
plugin_attrib = 'register' plugin_attrib = 'register'
interfaces = {'username', 'password', 'email', 'nick', 'name', interfaces = set(('username', 'password', 'email', 'nick', 'name',
'first', 'last', 'address', 'city', 'state', 'zip', 'first', 'last', 'address', 'city', 'state', 'zip',
'phone', 'url', 'date', 'misc', 'text', 'key', 'phone', 'url', 'date', 'misc', 'text', 'key',
'registered', 'remove', 'instructions'} 'registered', 'remove', 'instructions'))
sub_interfaces = interfaces sub_interfaces = interfaces
def getRegistered(self): def getRegistered(self):

View File

@@ -259,8 +259,8 @@ Event Index
Signal that a connection to the XMPP server has been lost and the current Signal that a connection to the XMPP server has been lost and the current
stream session has ended. Currently equivalent to :term:`disconnected`, but stream session has ended. Currently equivalent to :term:`disconnected`, but
implementations of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_ future implementation of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
distinguish between the two events. will distinguish the two events.
Plugins that maintain session-based state should clear themselves when Plugins that maintain session-based state should clear themselves when
this event is fired. this event is fired.

View File

@@ -70,7 +70,7 @@ as well.
class EchoBot(slixmpp.ClientXMPP): class EchoBot(slixmpp.ClientXMPP):
def __init__(self, jid, password): def __init__(self, jid, password):
super().__init__(jid, password) super(EchoBot, self).__init__(jid, password)
Handling Session Start Handling Session Start
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
@@ -83,7 +83,7 @@ started. To do that, we will register an event handler for the :term:`session_st
.. code-block:: python .. code-block:: python
def __init__(self, jid, password): def __init__(self, jid, password):
super().__init__(jid, password) super(EchoBot, self).__init__(jid, password)
self.add_event_handler('session_start', self.start) self.add_event_handler('session_start', self.start)
@@ -153,7 +153,7 @@ whenever a messsage is received.
.. code-block:: python .. code-block:: python
def __init__(self, jid, password): def __init__(self, jid, password):
super().__init__(jid, password) super(EchoBot, self).__init__(jid, password)
self.add_event_handler('session_start', self.start) self.add_event_handler('session_start', self.start)
self.add_event_handler('message', self.message) self.add_event_handler('message', self.message)
@@ -329,7 +329,7 @@ The Final Product
----------------- -----------------
Here then is what the final result should look like after working through the guide above. The code Here then is what the final result should look like after working through the guide above. The code
can also be found in the Slixmpp `examples directory <http://git.poez.io/slixmpp/tree/examples>`_. can also be found in the Slixmpp `examples directory <http://github.com/fritzy/Slixmpp/tree/master/examples>`_.
.. compound:: .. compound::

View File

@@ -63,13 +63,13 @@ has been established:
def start(self, event): def start(self, event):
self.get_roster() self.get_roster()
self.send_presence() self.send_presence()
self.plugin['xep_0045'].join_muc(self.room, self.plugin['xep_0045'].joinMUC(self.room,
self.nick, self.nick,
wait=True) wait=True)
Note that as in :ref:`echobot`, we need to include send an initial presence and request Note that as in :ref:`echobot`, we need to include send an initial presence and request
the roster. Next, we want to join the group chat, so we call the the roster. Next, we want to join the group chat, so we call the
``join_muc`` method of the MUC plugin. ``joinMUC`` method of the MUC plugin.
.. note:: .. note::

View File

@@ -24,7 +24,7 @@ for the JID that will receive our message, and the string content of the message
class SendMsgBot(slixmpp.ClientXMPP): class SendMsgBot(slixmpp.ClientXMPP):
def __init__(self, jid, password, recipient, msg): def __init__(self, jid, password, recipient, msg):
super().__init__(jid, password) super(SendMsgBot, self).__init__(jid, password)
self.recipient = recipient self.recipient = recipient
self.msg = msg self.msg = msg

View File

@@ -61,7 +61,7 @@ operation using these stanzas without doing any complex operations such as
checking an ACL, etc. checking an ACL, etc.
You may find it necessary at some point to revert a particular node or JID to You may find it necessary at some point to revert a particular node or JID to
using the default, static handlers. To do so, use the method ``restore_defaults()``. using the default, static handlers. To do so, use the method ``make_static()``.
You may also elect to only convert a given set of actions instead. You may also elect to only convert a given set of actions instead.
Creating a Node Handler Creating a Node Handler
@@ -162,7 +162,7 @@ item itself, and the JID and node that will own the item.
parameters ``ijid`` and ``node``. parameters ``ijid`` and ``node``.
Performing Disco Queries Performing Disco Queries
------------------------ -----------------------
The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs
and their nodes for disco information. Since these methods are wrappers for and their nodes for disco information. Since these methods are wrappers for
sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()`` sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()``

View File

@@ -68,7 +68,7 @@ class CommandBot(slixmpp.ClientXMPP):
session. Additional, custom data may be saved session. Additional, custom data may be saved
here to persist across handler callbacks. here to persist across handler callbacks.
""" """
form = self['xep_0004'].make_form('form', 'Greeting') form = self['xep_0004'].makeForm('form', 'Greeting')
form['instructions'] = 'Send a custom greeting to a JID' form['instructions'] = 'Send a custom greeting to a JID'
form.addField(var='greeting', form.addField(var='greeting',
ftype='text-single', ftype='text-single',

View File

@@ -94,7 +94,7 @@ class CommandUserBot(slixmpp.ClientXMPP):
# label="Your greeting" /> # label="Your greeting" />
# </x> # </x>
form = self['xep_0004'].make_form(ftype='submit') form = self['xep_0004'].makeForm(ftype='submit')
form.addField(var='greeting', form.addField(var='greeting',
value=session['greeting']) value=session['greeting'])

View File

@@ -1,100 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2015 Emmanuel Gil Peyrot
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp.exceptions import XMPPError
from slixmpp import asyncio
log = logging.getLogger(__name__)
class AnswerConfirm(slixmpp.ClientXMPP):
"""
A basic client demonstrating how to confirm or deny an HTTP request.
"""
def __init__(self, jid, password, trusted):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.add_event_handler("http_confirm", self.confirm)
self.add_event_handler("session_start", self.start)
def start(self, *args):
self.make_presence().send()
def prompt(self, stanza):
confirm = stanza['confirm']
print('Received confirm request %s from %s to access %s using '
'method %s' % (
confirm['id'], stanza['from'], confirm['url'],
confirm['method'])
)
result = input("Do you accept (y/N)? ")
return 'y' == result.lower()
def confirm(self, stanza):
if self.prompt(stanza):
reply = stanza.reply()
else:
reply = stanza.reply()
reply.enable('error')
reply['error']['type'] = 'auth'
reply['error']['code'] = '401'
reply['error']['condition'] = 'not-authorized'
reply.append(stanza['confirm'])
reply.send()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
parser.add_argument("-q","--quiet", help="set logging to ERROR",
action="store_const",
dest="loglevel",
const=logging.ERROR,
default=logging.INFO)
parser.add_argument("-d","--debug", help="set logging to DEBUG",
action="store_const",
dest="loglevel",
const=logging.DEBUG,
default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
# Other options.
parser.add_argument("-t", "--trusted", nargs='*',
help="List of trusted JIDs")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
xmpp = AnswerConfirm(args.jid, args.password, args.trusted)
xmpp.register_plugin('xep_0070')
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process()

View File

@@ -1,125 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2015 Emmanuel Gil Peyrot
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp.exceptions import XMPPError, IqError
from slixmpp import asyncio
log = logging.getLogger(__name__)
class AskConfirm(slixmpp.ClientXMPP):
"""
A basic client asking an entity if they confirm the access to an HTTP URL.
"""
def __init__(self, jid, password, recipient, id, url, method):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.recipient = recipient
self.id = id
self.url = url
self.method = method
# Will be used to set the proper exit code.
self.confirmed = asyncio.Future()
self.add_event_handler("session_start", self.start)
self.add_event_handler("message", self.start)
self.add_event_handler("http_confirm_message", self.confirm)
def confirm(self, message):
print(message)
if message['confirm']['id'] == self.id:
if message['type'] == 'error':
self.confirmed.set_result(False)
else:
self.confirmed.set_result(True)
@asyncio.coroutine
def start(self, event):
log.info('Sending confirm request %s to %s who wants to access %s using '
'method %s...' % (self.id, self.recipient, self.url, self.method))
try:
confirmed = yield from self['xep_0070'].ask_confirm(self.recipient,
id=self.id,
url=self.url,
method=self.method,
message='Plz say yes or no for {method} {url} ({id}).')
if isinstance(confirmed, slixmpp.Message):
confirmed = yield from self.confirmed
else:
confirmed = True
except IqError:
confirmed = False
if confirmed:
print('Confirmed')
else:
print('Denied')
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
parser.add_argument("-q","--quiet", help="set logging to ERROR",
action="store_const",
dest="loglevel",
const=logging.ERROR,
default=logging.INFO)
parser.add_argument("-d","--debug", help="set logging to DEBUG",
action="store_const",
dest="loglevel",
const=logging.DEBUG,
default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
# Other options.
parser.add_argument("-r", "--recipient", required=True,
help="Recipient JID")
parser.add_argument("-i", "--id", required=True,
help="id TODO")
parser.add_argument("-u", "--url", required=True,
help="URL the user tried to access")
parser.add_argument("-m", "--method", required=True,
help="HTTP method used")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
xmpp = AskConfirm(args.jid, args.password, args.recipient, args.id,
args.url, args.method)
xmpp.register_plugin('xep_0070')
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process(forever=False)
sys.exit(0 if xmpp.confirmed else 1)

View File

@@ -41,7 +41,7 @@ class Action(ElementBase):
#: del action['status'] #: del action['status']
#: #:
#: to set, get, or remove its values. #: to set, get, or remove its values.
interfaces = {'method', 'param', 'status'} interfaces = set(('method', 'param', 'status'))
#: By default, values in the `interfaces` set are mapped to #: By default, values in the `interfaces` set are mapped to
#: attribute values. This can be changed such that an interface #: attribute values. This can be changed such that an interface

View File

@@ -67,11 +67,11 @@ class MUCBot(slixmpp.ClientXMPP):
""" """
self.get_roster() self.get_roster()
self.send_presence() self.send_presence()
self.plugin['xep_0045'].join_muc(self.room, self.plugin['xep_0045'].joinMUC(self.room,
self.nick, self.nick,
# If a room password is needed, use: # If a room password is needed, use:
# password=the_room_password, # password=the_room_password,
wait=True) wait=True)
def muc_message(self, msg): def muc_message(self, msg):
""" """

View File

@@ -15,7 +15,7 @@ class PubsubClient(slixmpp.ClientXMPP):
def __init__(self, jid, password, server, def __init__(self, jid, password, server,
node=None, action='nodes', data=''): node=None, action='nodes', data=''):
super().__init__(jid, password) super(PubsubClient, self).__init__(jid, password)
self.register_plugin('xep_0030') self.register_plugin('xep_0030')
self.register_plugin('xep_0059') self.register_plugin('xep_0059')

View File

@@ -14,7 +14,7 @@ from slixmpp.xmlstream.handler import Callback
class PubsubEvents(slixmpp.ClientXMPP): class PubsubEvents(slixmpp.ClientXMPP):
def __init__(self, jid, password): def __init__(self, jid, password):
super().__init__(jid, password) super(PubsubEvents, self).__init__(jid, password)
self.register_plugin('xep_0030') self.register_plugin('xep_0030')
self.register_plugin('xep_0059') self.register_plugin('xep_0059')

View File

@@ -22,7 +22,7 @@ from slixmpp import ClientXMPP
class LocationBot(ClientXMPP): class LocationBot(ClientXMPP):
def __init__(self, jid, password): def __init__(self, jid, password):
super().__init__(jid, password) super(LocationBot, self).__init__(jid, password)
self.add_event_handler('session_start', self.start) self.add_event_handler('session_start', self.start)
self.add_event_handler('user_location_publish', self.add_event_handler('user_location_publish',

View File

@@ -17,7 +17,7 @@ from slixmpp import ClientXMPP
class TuneBot(ClientXMPP): class TuneBot(ClientXMPP):
def __init__(self, jid, password): def __init__(self, jid, password):
super().__init__(jid, password) super(TuneBot, self).__init__(jid, password)
# Check for the current song every 5 seconds. # Check for the current song every 5 seconds.
self.schedule('Check Current Tune', 5, self._update_tune, repeat=True) self.schedule('Check Current Tune', 5, self._update_tune, repeat=True)

View File

@@ -7,15 +7,20 @@
# This software is licensed as described in the README.rst and LICENSE # This software is licensed as described in the README.rst and LICENSE
# file, which you should have received as part of this distribution. # file, which you should have received as part of this distribution.
import os
from pathlib import Path from pathlib import Path
from subprocess import call, DEVNULL
from tempfile import TemporaryFile
try: try:
from setuptools import setup from setuptools import setup
except ImportError: except ImportError:
from distutils.core import setup from distutils.core import setup
try:
from Cython.Build import cythonize
except ImportError:
print('Cython not found, falling back to the slow stringprep module.')
ext_modules = None
else:
ext_modules = cythonize('slixmpp/stringprep.pyx')
from run_tests import TestCommand from run_tests import TestCommand
from slixmpp.version import __version__ from slixmpp.version import __version__
@@ -35,27 +40,6 @@ CLASSIFIERS = [
packages = [str(mod.parent) for mod in Path('slixmpp').rglob('__init__.py')] packages = [str(mod.parent) for mod in Path('slixmpp').rglob('__init__.py')]
def check_include(header):
command = [os.environ.get('CC', 'cc'), '-E', '-']
with TemporaryFile('w+') as c_file:
c_file.write('#include <%s>' % header)
c_file.seek(0)
try:
return call(command, stdin=c_file, stdout=DEVNULL, stderr=DEVNULL) == 0
except FileNotFoundError:
return False
ext_modules = None
if check_include('stringprep.h'):
try:
from Cython.Build import cythonize
except ImportError:
print('Cython not found, falling back to the slow stringprep module.')
else:
ext_modules = cythonize('slixmpp/stringprep.pyx')
else:
print('libidn-dev not found, falling back to the slow stringprep module.')
setup( setup(
name="slixmpp", name="slixmpp",
version=VERSION, version=VERSION,

View File

@@ -7,8 +7,7 @@
""" """
import asyncio import asyncio
if hasattr(asyncio, 'sslproto'): # no ssl proto: very old asyncio = no need for this asyncio.sslproto._is_sslproto_available=lambda: False
asyncio.sslproto._is_sslproto_available=lambda: False
import logging import logging
logging.getLogger(__name__).addHandler(logging.NullHandler()) logging.getLogger(__name__).addHandler(logging.NullHandler())

View File

@@ -12,8 +12,8 @@
:license: MIT, see LICENSE for more details :license: MIT, see LICENSE for more details
""" """
import asyncio
import logging import logging
import threading
from slixmpp import plugins, roster, stanza from slixmpp import plugins, roster, stanza
from slixmpp.api import APIRegistry from slixmpp.api import APIRegistry
@@ -21,6 +21,7 @@ from slixmpp.exceptions import IqError, IqTimeout
from slixmpp.stanza import Message, Presence, Iq, StreamError from slixmpp.stanza import Message, Presence, Iq, StreamError
from slixmpp.stanza.roster import Roster from slixmpp.stanza.roster import Roster
from slixmpp.stanza.nick import Nick
from slixmpp.xmlstream import XMLStream, JID from slixmpp.xmlstream import XMLStream, JID
from slixmpp.xmlstream import ET, register_stanza_plugin from slixmpp.xmlstream import ET, register_stanza_plugin
@@ -69,7 +70,7 @@ class BaseXMPP(XMLStream):
#: redirections that will be followed before quitting. #: redirections that will be followed before quitting.
self.max_redirects = 5 self.max_redirects = 5
self.session_bind_event = asyncio.Event() self.session_bind_event = threading.Event()
#: A dictionary mapping plugin names to plugins. #: A dictionary mapping plugin names to plugins.
self.plugin = PluginManager(self) self.plugin = PluginManager(self)
@@ -193,6 +194,7 @@ class BaseXMPP(XMLStream):
# Initialize a few default stanza plugins. # Initialize a few default stanza plugins.
register_stanza_plugin(Iq, Roster) register_stanza_plugin(Iq, Roster)
register_stanza_plugin(Message, Nick)
def start_stream_handler(self, xml): def start_stream_handler(self, xml):
"""Save the stream ID once the streams have been established. """Save the stream ID once the streams have been established.
@@ -685,6 +687,7 @@ class BaseXMPP(XMLStream):
self.address = (host, port) self.address = (host, port)
self.default_domain = host self.default_domain = host
self.dns_records = None self.dns_records = None
self.reconnect_delay = None
self.reconnect() self.reconnect()
def _handle_message(self, msg): def _handle_message(self, msg):
@@ -750,9 +753,6 @@ class BaseXMPP(XMLStream):
Update the roster with presence information. Update the roster with presence information.
""" """
if self.roster[presence['from']].ignore_updates:
return
if not self.is_component and not presence['to'].bare: if not self.is_component and not presence['to'].bare:
presence['to'] = self.boundjid presence['to'] = self.boundjid

View File

@@ -12,7 +12,6 @@
:license: MIT, see LICENSE for more details :license: MIT, see LICENSE for more details
""" """
import asyncio
import logging import logging
from slixmpp.stanza import StreamFeatures from slixmpp.stanza import StreamFeatures
@@ -20,7 +19,7 @@ from slixmpp.basexmpp import BaseXMPP
from slixmpp.exceptions import XMPPError from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream import XMLStream from slixmpp.xmlstream import XMLStream
from slixmpp.xmlstream.matcher import StanzaPath, MatchXPath from slixmpp.xmlstream.matcher import StanzaPath, MatchXPath
from slixmpp.xmlstream.handler import Callback, CoroutineCallback from slixmpp.xmlstream.handler import Callback
# Flag indicating if DNS SRV records are available for use. # Flag indicating if DNS SRV records are available for use.
try: try:
@@ -105,18 +104,13 @@ class ClientXMPP(BaseXMPP):
self.register_stanza(StreamFeatures) self.register_stanza(StreamFeatures)
self.register_handler( self.register_handler(
CoroutineCallback('Stream Features', Callback('Stream Features',
MatchXPath('{%s}features' % self.stream_ns), MatchXPath('{%s}features' % self.stream_ns),
self._handle_stream_features)) self._handle_stream_features))
def roster_push_filter(iq):
from_ = iq['from']
if from_ and from_ != self.boundjid.bare:
return
self.event('roster_update', iq)
self.register_handler( self.register_handler(
Callback('Roster Update', Callback('Roster Update',
StanzaPath('iq@type=set/roster'), StanzaPath('iq@type=set/roster'),
roster_push_filter)) lambda iq: self.event('roster_update', iq)))
# Setup default stream features # Setup default stream features
self.register_plugin('feature_starttls') self.register_plugin('feature_starttls')
@@ -146,11 +140,8 @@ class ClientXMPP(BaseXMPP):
will be used. will be used.
:param address: A tuple containing the server's host and port. :param address: A tuple containing the server's host and port.
:param force_starttls: Indicates that negotiation should be aborted :param use_tls: Indicates if TLS should be used for the
if the server does not advertise support for connection. Defaults to ``True``.
STARTTLS. Defaults to ``True``.
:param disable_starttls: Disables TLS for the connection.
Defaults to ``False``.
:param use_ssl: Indicates if the older SSL connection method :param use_ssl: Indicates if the older SSL connection method
should be used. Defaults to ``False``. should be used. Defaults to ``False``.
""" """
@@ -258,7 +249,6 @@ class ClientXMPP(BaseXMPP):
self.bindfail = False self.bindfail = False
self.features = set() self.features = set()
@asyncio.coroutine
def _handle_stream_features(self, features): def _handle_stream_features(self, features):
"""Process the received stream features. """Process the received stream features.
@@ -267,11 +257,7 @@ class ClientXMPP(BaseXMPP):
for order, name in self._stream_feature_order: for order, name in self._stream_feature_order:
if name in features['features']: if name in features['features']:
handler, restart = self._stream_feature_handlers[name] handler, restart = self._stream_feature_handlers[name]
if asyncio.iscoroutinefunction(handler): if handler(features) and restart:
result = yield from handler(features)
else:
result = handler(features)
if result and restart:
# Don't continue if the feature requires # Don't continue if the feature requires
# restarting the XML stream. # restarting the XML stream.
return True return True

View File

@@ -77,7 +77,7 @@ class IqTimeout(XMPPError):
""" """
def __init__(self, iq): def __init__(self, iq):
super().__init__( super(IqTimeout, self).__init__(
condition='remote-server-timeout', condition='remote-server-timeout',
etype='cancel') etype='cancel')
@@ -94,7 +94,7 @@ class IqError(XMPPError):
""" """
def __init__(self, iq): def __init__(self, iq):
super().__init__( super(IqError, self).__init__(
condition=iq['error']['condition'], condition=iq['error']['condition'],
text=iq['error']['text'], text=iq['error']['text'],
etype=iq['error']['type']) etype=iq['error']['type'])

View File

@@ -13,3 +13,7 @@ from slixmpp.features.feature_bind.stanza import Bind
register_plugin(FeatureBind) register_plugin(FeatureBind)
# Retain some backwards compatibility
feature_bind = FeatureBind

View File

@@ -6,7 +6,6 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
import asyncio
import logging import logging
from slixmpp.jid import JID from slixmpp.jid import JID
@@ -35,7 +34,6 @@ class FeatureBind(BasePlugin):
register_stanza_plugin(Iq, stanza.Bind) register_stanza_plugin(Iq, stanza.Bind)
register_stanza_plugin(StreamFeatures, stanza.Bind) register_stanza_plugin(StreamFeatures, stanza.Bind)
@asyncio.coroutine
def _handle_bind_resource(self, features): def _handle_bind_resource(self, features):
""" """
Handle requesting a specific resource. Handle requesting a specific resource.
@@ -51,7 +49,7 @@ class FeatureBind(BasePlugin):
if self.xmpp.requested_jid.resource: if self.xmpp.requested_jid.resource:
iq['bind']['resource'] = self.xmpp.requested_jid.resource iq['bind']['resource'] = self.xmpp.requested_jid.resource
yield from iq.send(callback=self._on_bind_response) iq.send(callback=self._on_bind_response)
def _on_bind_response(self, response): def _on_bind_response(self, response):
self.xmpp.boundjid = JID(response['bind']['jid']) self.xmpp.boundjid = JID(response['bind']['jid'])

View File

@@ -16,6 +16,6 @@ class Bind(ElementBase):
name = 'bind' name = 'bind'
namespace = 'urn:ietf:params:xml:ns:xmpp-bind' namespace = 'urn:ietf:params:xml:ns:xmpp-bind'
interfaces = {'resource', 'jid'} interfaces = set(('resource', 'jid'))
sub_interfaces = interfaces sub_interfaces = interfaces
plugin_attrib = 'bind' plugin_attrib = 'bind'

View File

@@ -16,3 +16,7 @@ from slixmpp.features.feature_mechanisms.stanza import Failure
register_plugin(FeatureMechanisms) register_plugin(FeatureMechanisms)
# Retain some backwards compatibility
feature_mechanisms = FeatureMechanisms

View File

@@ -49,7 +49,7 @@ class FeatureMechanisms(BasePlugin):
if self.security_callback is None: if self.security_callback is None:
self.security_callback = self._default_security self.security_callback = self._default_security
creds = self.sasl_callback({'username'}, set()) creds = self.sasl_callback(set(['username']), set())
if not self.use_mech and not creds['username']: if not self.use_mech and not creds['username']:
self.use_mech = 'ANONYMOUS' self.use_mech = 'ANONYMOUS'

View File

@@ -19,12 +19,12 @@ class Auth(StanzaBase):
name = 'auth' name = 'auth'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = {'mechanism', 'value'} interfaces = set(('mechanism', 'value'))
plugin_attrib = name plugin_attrib = name
#: Some SASL mechs require sending values as is, #: Some SASL mechs require sending values as is,
#: without converting base64. #: without converting base64.
plain_mechs = {'X-MESSENGER-OAUTH2'} plain_mechs = set(['X-MESSENGER-OAUTH2'])
def setup(self, xml): def setup(self, xml):
StanzaBase.setup(self, xml) StanzaBase.setup(self, xml)

View File

@@ -19,7 +19,7 @@ class Challenge(StanzaBase):
name = 'challenge' name = 'challenge'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = {'value'} interfaces = set(('value',))
plugin_attrib = name plugin_attrib = name
def setup(self, xml): def setup(self, xml):

View File

@@ -16,14 +16,13 @@ class Failure(StanzaBase):
name = 'failure' name = 'failure'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = {'condition', 'text'} interfaces = set(('condition', 'text'))
plugin_attrib = name plugin_attrib = name
sub_interfaces = {'text'} sub_interfaces = set(('text',))
conditions = {'aborted', 'account-disabled', 'credentials-expired', conditions = set(('aborted', 'account-disabled', 'credentials-expired',
'encryption-required', 'incorrect-encoding', 'encryption-required', 'incorrect-encoding', 'invalid-authzid',
'invalid-authzid', 'invalid-mechanism', 'malformed-request', 'invalid-mechanism', 'malformed-request', 'mechansism-too-weak',
'mechansism-too-weak', 'not-authorized', 'not-authorized', 'temporary-auth-failure'))
'temporary-auth-failure'}
def setup(self, xml=None): def setup(self, xml=None):
""" """

View File

@@ -16,7 +16,7 @@ class Mechanisms(ElementBase):
name = 'mechanisms' name = 'mechanisms'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = {'mechanisms', 'required'} interfaces = set(('mechanisms', 'required'))
plugin_attrib = name plugin_attrib = name
is_extension = True is_extension = True
@@ -29,7 +29,7 @@ class Mechanisms(ElementBase):
""" """
""" """
results = [] results = []
mechs = self.xml.findall('{%s}mechanism' % self.namespace) mechs = self.findall('{%s}mechanism' % self.namespace)
if mechs: if mechs:
for mech in mechs: for mech in mechs:
results.append(mech.text) results.append(mech.text)
@@ -47,7 +47,7 @@ class Mechanisms(ElementBase):
def del_mechanisms(self): def del_mechanisms(self):
""" """
""" """
mechs = self.xml.findall('{%s}mechanism' % self.namespace) mechs = self.findall('{%s}mechanism' % self.namespace)
if mechs: if mechs:
for mech in mechs: for mech in mechs:
self.xml.remove(mech) self.xml.remove(mech)

View File

@@ -19,7 +19,7 @@ class Response(StanzaBase):
name = 'response' name = 'response'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = {'value'} interfaces = set(('value',))
plugin_attrib = name plugin_attrib = name
def setup(self, xml): def setup(self, xml):

View File

@@ -18,7 +18,7 @@ class Success(StanzaBase):
name = 'success' name = 'success'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = {'value'} interfaces = set(['value'])
plugin_attrib = name plugin_attrib = name
def setup(self, xml): def setup(self, xml):

View File

@@ -13,3 +13,7 @@ from slixmpp.features.feature_rosterver.stanza import RosterVer
register_plugin(FeatureRosterVer) register_plugin(FeatureRosterVer)
# Retain some backwards compatibility
feature_rosterver = FeatureRosterVer

View File

@@ -13,3 +13,7 @@ from slixmpp.features.feature_session.stanza import Session
register_plugin(FeatureSession) register_plugin(FeatureSession)
# Retain some backwards compatibility
feature_session = FeatureSession

View File

@@ -6,7 +6,6 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
import asyncio
import logging import logging
from slixmpp.stanza import Iq, StreamFeatures from slixmpp.stanza import Iq, StreamFeatures
@@ -35,7 +34,6 @@ class FeatureSession(BasePlugin):
register_stanza_plugin(Iq, stanza.Session) register_stanza_plugin(Iq, stanza.Session)
register_stanza_plugin(StreamFeatures, stanza.Session) register_stanza_plugin(StreamFeatures, stanza.Session)
@asyncio.coroutine
def _handle_start_session(self, features): def _handle_start_session(self, features):
""" """
Handle the start of the session. Handle the start of the session.
@@ -46,7 +44,7 @@ class FeatureSession(BasePlugin):
iq = self.xmpp.Iq() iq = self.xmpp.Iq()
iq['type'] = 'set' iq['type'] = 'set'
iq.enable('session') iq.enable('session')
yield from iq.send(callback=self._on_start_session_response) iq.send(callback=self._on_start_session_response)
def _on_start_session_response(self, response): def _on_start_session_response(self, response):
self.xmpp.features.add('session') self.xmpp.features.add('session')

View File

@@ -13,3 +13,7 @@ from slixmpp.features.feature_starttls.stanza import *
register_plugin(FeatureSTARTTLS) register_plugin(FeatureSTARTTLS)
# Retain some backwards compatibility
feature_starttls = FeatureSTARTTLS

View File

@@ -16,7 +16,7 @@ class STARTTLS(ElementBase):
name = 'starttls' name = 'starttls'
namespace = 'urn:ietf:params:xml:ns:xmpp-tls' namespace = 'urn:ietf:params:xml:ns:xmpp-tls'
interfaces = {'required'} interfaces = set(('required',))
plugin_attrib = name plugin_attrib = name
def get_required(self): def get_required(self):

View File

@@ -79,7 +79,7 @@ def _validate_node(node):
:returns: The local portion of a JID, as validated by nodeprep. :returns: The local portion of a JID, as validated by nodeprep.
""" """
if node is None: if node is None:
return '' return None
try: try:
node = nodeprep(node) node = nodeprep(node)
@@ -160,7 +160,7 @@ def _validate_resource(resource):
:returns: The local portion of a JID, as validated by resourceprep. :returns: The local portion of a JID, as validated by resourceprep.
""" """
if resource is None: if resource is None:
return '' return None
try: try:
resource = resourceprep(resource) resource = resourceprep(resource)
@@ -208,15 +208,16 @@ def _format_jid(local=None, domain=None, resource=None):
:return: A full or bare JID string. :return: A full or bare JID string.
""" """
if domain is None: result = []
return ''
if local is not None: if local is not None:
result = local + '@' + domain result.append(local)
else: result.append('@')
result = domain if domain is not None:
result.append(domain)
if resource is not None: if resource is not None:
result += '/' + resource result.append('/')
return result result.append(resource)
return ''.join(result)
class InvalidJID(ValueError): class InvalidJID(ValueError):
@@ -299,23 +300,19 @@ class JID:
:raises InvalidJID: :raises InvalidJID:
""" """
__slots__ = ('_node', '_domain', '_resource', '_bare', '_full') __slots__ = ('_node', '_domain', '_resource')
def __init__(self, jid=None): def __init__(self, jid=None):
if not jid: if not jid:
self._node = '' self._node = None
self._domain = '' self._domain = None
self._resource = '' self._resource = None
self._bare = ''
self._full = ''
return
elif not isinstance(jid, JID): elif not isinstance(jid, JID):
self._node, self._domain, self._resource = _parse_jid(jid) self._node, self._domain, self._resource = _parse_jid(jid)
else: else:
self._node = jid._node self._node = jid._node
self._domain = jid._domain self._domain = jid._domain
self._resource = jid._resource self._resource = jid._resource
self._update_bare_full()
def unescape(self): def unescape(self):
"""Return an unescaped JID object. """Return an unescaped JID object.
@@ -332,94 +329,77 @@ class JID:
self._domain, self._domain,
self._resource) self._resource)
def _update_bare_full(self):
"""Format the given JID into a bare and a full JID.
"""
self._bare = (self._node + '@' + self._domain
if self._node
else self._domain)
self._full = (self._bare + '/' + self._resource
if self._resource
else self._bare)
@property @property
def node(self): def node(self):
return self._node return self._node or ''
@property @property
def user(self): def user(self):
return self._node return self._node or ''
@property @property
def local(self): def local(self):
return self._node return self._node or ''
@property @property
def username(self): def username(self):
return self._node return self._node or ''
@property @property
def domain(self): def domain(self):
return self._domain return self._domain or ''
@property @property
def server(self): def server(self):
return self._domain return self._domain or ''
@property @property
def host(self): def host(self):
return self._domain return self._domain or ''
@property @property
def resource(self): def resource(self):
return self._resource return self._resource or ''
@property @property
def bare(self): def bare(self):
return self._bare return _format_jid(self._node, self._domain)
@property @property
def full(self): def full(self):
return self._full return _format_jid(self._node, self._domain, self._resource)
@property @property
def jid(self): def jid(self):
return self._full return _format_jid(self._node, self._domain, self._resource)
@node.setter @node.setter
def node(self, value): def node(self, value):
self._node = _validate_node(value) self._node = _validate_node(value)
self._update_bare_full()
@user.setter @user.setter
def user(self, value): def user(self, value):
self._node = _validate_node(value) self._node = _validate_node(value)
self._update_bare_full()
@local.setter @local.setter
def local(self, value): def local(self, value):
self._node = _validate_node(value) self._node = _validate_node(value)
self._update_bare_full()
@username.setter @username.setter
def username(self, value): def username(self, value):
self._node = _validate_node(value) self._node = _validate_node(value)
self._update_bare_full()
@domain.setter @domain.setter
def domain(self, value): def domain(self, value):
self._domain = _validate_domain(value) self._domain = _validate_domain(value)
self._update_bare_full()
@server.setter @server.setter
def server(self, value): def server(self, value):
self._domain = _validate_domain(value) self._domain = _validate_domain(value)
self._update_bare_full()
@host.setter @host.setter
def host(self, value): def host(self, value):
self._domain = _validate_domain(value) self._domain = _validate_domain(value)
self._update_bare_full()
@bare.setter @bare.setter
def bare(self, value): def bare(self, value):
@@ -427,30 +407,26 @@ class JID:
assert not resource assert not resource
self._node = node self._node = node
self._domain = domain self._domain = domain
self._update_bare_full()
@resource.setter @resource.setter
def resource(self, value): def resource(self, value):
self._resource = _validate_resource(value) self._resource = _validate_resource(value)
self._update_bare_full()
@full.setter @full.setter
def full(self, value): def full(self, value):
self._node, self._domain, self._resource = _parse_jid(value) self._node, self._domain, self._resource = _parse_jid(value)
self._update_bare_full()
@jid.setter @jid.setter
def jid(self, value): def jid(self, value):
self._node, self._domain, self._resource = _parse_jid(value) self._node, self._domain, self._resource = _parse_jid(value)
self._update_bare_full()
def __str__(self): def __str__(self):
"""Use the full JID as the string value.""" """Use the full JID as the string value."""
return self._full return _format_jid(self._node, self._domain, self._resource)
def __repr__(self): def __repr__(self):
"""Use the full JID as the representation.""" """Use the full JID as the representation."""
return self._full return _format_jid(self._node, self._domain, self._resource)
# pylint: disable=W0212 # pylint: disable=W0212
def __eq__(self, other): def __eq__(self, other):
@@ -470,4 +446,4 @@ class JID:
def __hash__(self): def __hash__(self):
"""Hash a JID based on the string version of its full JID.""" """Hash a JID based on the string version of its full JID."""
return hash(self._full) return hash(_format_jid(self._node, self._domain, self._resource))

View File

@@ -308,7 +308,7 @@ class BasePlugin(object):
if key in self.default_config: if key in self.default_config:
self.config[key] = value self.config[key] = value
else: else:
super().__setattr__(key, value) super(BasePlugin, self).__setattr__(key, value)
def _init(self): def _init(self):
"""Initialize plugin state, such as registering event handlers. """Initialize plugin state, such as registering event handlers.

View File

@@ -21,15 +21,15 @@ class GmailQuery(ElementBase):
namespace = 'google:mail:notify' namespace = 'google:mail:notify'
name = 'query' name = 'query'
plugin_attrib = 'gmail' plugin_attrib = 'gmail'
interfaces = {'newer-than-time', 'newer-than-tid', 'q', 'search'} interfaces = set(('newer-than-time', 'newer-than-tid', 'q', 'search'))
def get_search(self): def getSearch(self):
return self['q'] return self['q']
def set_search(self, search): def setSearch(self, search):
self['q'] = search self['q'] = search
def del_search(self): def delSearch(self):
del self['q'] del self['q']
@@ -37,20 +37,20 @@ class MailBox(ElementBase):
namespace = 'google:mail:notify' namespace = 'google:mail:notify'
name = 'mailbox' name = 'mailbox'
plugin_attrib = 'mailbox' plugin_attrib = 'mailbox'
interfaces = {'result-time', 'total-matched', 'total-estimate', interfaces = set(('result-time', 'total-matched', 'total-estimate',
'url', 'threads', 'matched', 'estimate'} 'url', 'threads', 'matched', 'estimate'))
def get_threads(self): def getThreads(self):
threads = [] threads = []
for threadXML in self.xml.findall('{%s}%s' % (MailThread.namespace, for threadXML in self.xml.findall('{%s}%s' % (MailThread.namespace,
MailThread.name)): MailThread.name)):
threads.append(MailThread(xml=threadXML, parent=None)) threads.append(MailThread(xml=threadXML, parent=None))
return threads return threads
def get_matched(self): def getMatched(self):
return self['total-matched'] return self['total-matched']
def get_estimate(self): def getEstimate(self):
return self['total-estimate'] == '1' return self['total-estimate'] == '1'
@@ -58,11 +58,11 @@ class MailThread(ElementBase):
namespace = 'google:mail:notify' namespace = 'google:mail:notify'
name = 'mail-thread-info' name = 'mail-thread-info'
plugin_attrib = 'thread' plugin_attrib = 'thread'
interfaces = {'tid', 'participation', 'messages', 'date', interfaces = set(('tid', 'participation', 'messages', 'date',
'senders', 'url', 'labels', 'subject', 'snippet'} 'senders', 'url', 'labels', 'subject', 'snippet'))
sub_interfaces = {'labels', 'subject', 'snippet'} sub_interfaces = set(('labels', 'subject', 'snippet'))
def get_senders(self): def getSenders(self):
senders = [] senders = []
sendersXML = self.xml.find('{%s}senders' % self.namespace) sendersXML = self.xml.find('{%s}senders' % self.namespace)
if sendersXML is not None: if sendersXML is not None:
@@ -75,12 +75,12 @@ class MailSender(ElementBase):
namespace = 'google:mail:notify' namespace = 'google:mail:notify'
name = 'sender' name = 'sender'
plugin_attrib = 'sender' plugin_attrib = 'sender'
interfaces = {'address', 'name', 'originator', 'unread'} interfaces = set(('address', 'name', 'originator', 'unread'))
def get_originator(self): def getOriginator(self):
return self.xml.attrib.get('originator', '0') == '1' return self.xml.attrib.get('originator', '0') == '1'
def get_unread(self): def getUnread(self):
return self.xml.attrib.get('unread', '0') == '1' return self.xml.attrib.get('unread', '0') == '1'

View File

@@ -13,7 +13,7 @@ class GoogleAuth(ElementBase):
name = 'auth' name = 'auth'
namespace = 'http://www.google.com/talk/protocol/auth' namespace = 'http://www.google.com/talk/protocol/auth'
plugin_attrib = 'google' plugin_attrib = 'google'
interfaces = {'client_uses_full_bind_result', 'service'} interfaces = set(['client_uses_full_bind_result', 'service'])
discovery_attr= '{%s}client-uses-full-bind-result' % namespace discovery_attr= '{%s}client-uses-full-bind-result' % namespace
service_attr= '{%s}service' % namespace service_attr= '{%s}service' % namespace

View File

@@ -14,7 +14,7 @@ class NoSave(ElementBase):
name = 'x' name = 'x'
namespace = 'google:nosave' namespace = 'google:nosave'
plugin_attrib = 'google_nosave' plugin_attrib = 'google_nosave'
interfaces = {'value'} interfaces = set(['value'])
def get_value(self): def get_value(self):
return self._get_attr('value', '') == 'enabled' return self._get_attr('value', '') == 'enabled'
@@ -35,7 +35,7 @@ class Item(ElementBase):
namespace = 'google:nosave' namespace = 'google:nosave'
plugin_attrib = 'item' plugin_attrib = 'item'
plugin_multi_attrib = 'items' plugin_multi_attrib = 'items'
interfaces = {'jid', 'source', 'value'} interfaces = set(['jid', 'source', 'value'])
def get_value(self): def get_value(self):
return self._get_attr('value', '') == 'enabled' return self._get_attr('value', '') == 'enabled'

View File

@@ -14,3 +14,9 @@ from slixmpp.plugins.xep_0004.dataforms import XEP_0004
register_plugin(XEP_0004) register_plugin(XEP_0004)
# Retain some backwards compatibility
xep_0004 = XEP_0004
xep_0004.makeForm = xep_0004.make_form
xep_0004.buildForm = xep_0004.build_form

View File

@@ -23,7 +23,7 @@ class XEP_0004(BasePlugin):
name = 'xep_0004' name = 'xep_0004'
description = 'XEP-0004: Data Forms' description = 'XEP-0004: Data Forms'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -14,21 +14,21 @@ class FormField(ElementBase):
name = 'field' name = 'field'
plugin_attrib = 'field' plugin_attrib = 'field'
plugin_multi_attrib = 'fields' plugin_multi_attrib = 'fields'
interfaces = {'answer', 'desc', 'required', 'value', interfaces = set(('answer', 'desc', 'required', 'value',
'label', 'type', 'var'} 'label', 'type', 'var'))
sub_interfaces = {'desc'} sub_interfaces = set(('desc',))
plugin_tag_map = {} plugin_tag_map = {}
plugin_attrib_map = {} plugin_attrib_map = {}
field_types = {'boolean', 'fixed', 'hidden', 'jid-multi', field_types = set(('boolean', 'fixed', 'hidden', 'jid-multi',
'jid-single', 'list-multi', 'list-single', 'jid-single', 'list-multi', 'list-single',
'text-multi', 'text-private', 'text-single'} 'text-multi', 'text-private', 'text-single'))
true_values = {True, '1', 'true'} true_values = set((True, '1', 'true'))
option_types = {'list-multi', 'list-single'} option_types = set(('list-multi', 'list-single'))
multi_line_types = {'hidden', 'text-multi'} multi_line_types = set(('hidden', 'text-multi'))
multi_value_types = {'hidden', 'jid-multi', multi_value_types = set(('hidden', 'jid-multi',
'list-multi', 'text-multi'} 'list-multi', 'text-multi'))
def setup(self, xml=None): def setup(self, xml=None):
if ElementBase.setup(self, xml): if ElementBase.setup(self, xml):
@@ -164,8 +164,8 @@ class FieldOption(ElementBase):
namespace = 'jabber:x:data' namespace = 'jabber:x:data'
name = 'option' name = 'option'
plugin_attrib = 'option' plugin_attrib = 'option'
interfaces = {'label', 'value'} interfaces = set(('label', 'value'))
sub_interfaces = {'value'} sub_interfaces = set(('value',))
plugin_multi_attrib = 'options' plugin_multi_attrib = 'options'

View File

@@ -24,8 +24,8 @@ class Form(ElementBase):
name = 'x' name = 'x'
plugin_attrib = 'form' plugin_attrib = 'form'
interfaces = OrderedSet(('instructions', 'reported', 'title', 'type', 'items', )) interfaces = OrderedSet(('instructions', 'reported', 'title', 'type', 'items', ))
sub_interfaces = {'title'} sub_interfaces = set(('title',))
form_types = {'cancel', 'form', 'result', 'submit'} form_types = set(('cancel', 'form', 'result', 'submit'))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
title = None title = None
@@ -81,6 +81,18 @@ class Form(ElementBase):
self.append(field) self.append(field)
return field return field
def getXML(self, type='submit'):
self['type'] = type
log.warning("Form.getXML() is deprecated API compatibility " + \
"with plugins/old_0004.py")
return self.xml
def fromXML(self, xml):
log.warning("Form.fromXML() is deprecated API compatibility " + \
"with plugins/old_0004.py")
n = Form(xml=xml)
return n
def add_item(self, values): def add_item(self, values):
itemXML = ET.Element('{%s}item' % self.namespace) itemXML = ET.Element('{%s}item' % self.namespace)
self.xml.append(itemXML) self.xml.append(itemXML)
@@ -184,13 +196,13 @@ class Form(ElementBase):
for var, field in fields: for var, field in fields:
field['var'] = var field['var'] = var
self.add_field( self.add_field(
var=field.get('var'), var = field.get('var'),
label=field.get('label'), label = field.get('label'),
desc=field.get('desc'), desc = field.get('desc'),
required=field.get('required'), required = field.get('required'),
value=field.get('value'), value = field.get('value'),
options=field.get('options'), options = field.get('options'),
type=field.get('type')) type = field.get('type'))
def set_instructions(self, instructions): def set_instructions(self, instructions):
del self['instructions'] del self['instructions']
@@ -209,7 +221,7 @@ class Form(ElementBase):
def set_reported(self, reported): def set_reported(self, reported):
""" """
This either needs a dictionary of dictionaries or a dictionary of form fields. This either needs a dictionary or dictionaries or a dictionary of form fields.
:param reported: :param reported:
:return: :return:
""" """

View File

@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0009.stanza import RPCQuery, MethodCall, MethodResponse
register_plugin(XEP_0009) register_plugin(XEP_0009)
# Retain some backwards compatibility
xep_0009 = XEP_0009

View File

@@ -25,7 +25,7 @@ def fault2xml(fault):
def xml2fault(params): def xml2fault(params):
vals = [] vals = []
for value in params.xml.findall('{%s}value' % _namespace): for value in params.findall('{%s}value' % _namespace):
vals.append(_xml2py(value)) vals.append(_xml2py(value))
fault = dict() fault = dict()
fault['code'] = vals[0]['faultCode'] fault['code'] = vals[0]['faultCode']
@@ -98,34 +98,33 @@ def xml2py(params):
def _xml2py(value): def _xml2py(value):
namespace = 'jabber:iq:rpc' namespace = 'jabber:iq:rpc'
find_value = value.find if value.find('{%s}nil' % namespace) is not None:
if find_value('{%s}nil' % namespace) is not None:
return None return None
if find_value('{%s}i4' % namespace) is not None: if value.find('{%s}i4' % namespace) is not None:
return int(find_value('{%s}i4' % namespace).text) return int(value.find('{%s}i4' % namespace).text)
if find_value('{%s}int' % namespace) is not None: if value.find('{%s}int' % namespace) is not None:
return int(find_value('{%s}int' % namespace).text) return int(value.find('{%s}int' % namespace).text)
if find_value('{%s}boolean' % namespace) is not None: if value.find('{%s}boolean' % namespace) is not None:
return bool(int(find_value('{%s}boolean' % namespace).text)) return bool(int(value.find('{%s}boolean' % namespace).text))
if find_value('{%s}string' % namespace) is not None: if value.find('{%s}string' % namespace) is not None:
return find_value('{%s}string' % namespace).text return value.find('{%s}string' % namespace).text
if find_value('{%s}double' % namespace) is not None: if value.find('{%s}double' % namespace) is not None:
return float(find_value('{%s}double' % namespace).text) return float(value.find('{%s}double' % namespace).text)
if find_value('{%s}base64' % namespace) is not None: if value.find('{%s}base64' % namespace) is not None:
return rpcbase64(find_value('{%s}base64' % namespace).text.encode()) return rpcbase64(value.find('{%s}base64' % namespace).text.encode())
if find_value('{%s}Base64' % namespace) is not None: if value.find('{%s}Base64' % namespace) is not None:
# Older versions of XEP-0009 used Base64 # Older versions of XEP-0009 used Base64
return rpcbase64(find_value('{%s}Base64' % namespace).text.encode()) return rpcbase64(value.find('{%s}Base64' % namespace).text.encode())
if find_value('{%s}dateTime.iso8601' % namespace) is not None: if value.find('{%s}dateTime.iso8601' % namespace) is not None:
return rpctime(find_value('{%s}dateTime.iso8601' % namespace).text) return rpctime(value.find('{%s}dateTime.iso8601' % namespace).text)
if find_value('{%s}struct' % namespace) is not None: if value.find('{%s}struct' % namespace) is not None:
struct = {} struct = {}
for member in find_value('{%s}struct' % namespace).findall('{%s}member' % namespace): for member in value.find('{%s}struct' % namespace).findall('{%s}member' % namespace):
struct[member.find('{%s}name' % namespace).text] = _xml2py(member.find('{%s}value' % namespace)) struct[member.find('{%s}name' % namespace).text] = _xml2py(member.find('{%s}value' % namespace))
return struct return struct
if find_value('{%s}array' % namespace) is not None: if value.find('{%s}array' % namespace) is not None:
array = [] array = []
for val in find_value('{%s}array' % namespace).find('{%s}data' % namespace).findall('{%s}value' % namespace): for val in value.find('{%s}array' % namespace).find('{%s}data' % namespace).findall('{%s}value' % namespace):
array.append(_xml2py(val)) array.append(_xml2py(val))
return array return array
raise ValueError() raise ValueError()

View File

@@ -163,7 +163,7 @@ class ACL:
@classmethod @classmethod
def _next_token(cls, expression, index): def _next_token(cls, expression, index):
new_index = expression.xml.find('*', index) new_index = expression.find('*', index)
if new_index == 0: if new_index == 0:
return '' return ''
else: else:
@@ -182,7 +182,7 @@ class ACL:
#! print "[TOKEN] '%s'" % token #! print "[TOKEN] '%s'" % token
size = len(token) size = len(token)
if size > 0: if size > 0:
token_index = value.xml.find(token, position) token_index = value.find(token, position)
if token_index == -1: if token_index == -1:
return False return False
else: else:

View File

@@ -24,7 +24,7 @@ class XEP_0009(BasePlugin):
name = 'xep_0009' name = 'xep_0009'
description = 'XEP-0009: Jabber-RPC' description = 'XEP-0009: Jabber-RPC'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):
@@ -121,7 +121,7 @@ class XEP_0009(BasePlugin):
def _recipient_unvailable(self, iq): def _recipient_unvailable(self, iq):
payload = iq.get_payload() payload = iq.get_payload()
iq = iq.reply() iq = iq.reply()
iq.error().set_payload(payload) error().set_payload(payload)
iq['error']['code'] = '404' iq['error']['code'] = '404'
iq['error']['type'] = 'wait' iq['error']['type'] = 'wait'
iq['error']['condition'] = 'recipient-unavailable' iq['error']['condition'] = 'recipient-unavailable'

View File

@@ -14,8 +14,8 @@ class RPCQuery(ElementBase):
name = 'query' name = 'query'
namespace = 'jabber:iq:rpc' namespace = 'jabber:iq:rpc'
plugin_attrib = 'rpc_query' plugin_attrib = 'rpc_query'
interfaces = {} interfaces = set(())
subinterfaces = {} subinterfaces = set(())
plugin_attrib_map = {} plugin_attrib_map = {}
plugin_tag_map = {} plugin_tag_map = {}
@@ -24,8 +24,8 @@ class MethodCall(ElementBase):
name = 'methodCall' name = 'methodCall'
namespace = 'jabber:iq:rpc' namespace = 'jabber:iq:rpc'
plugin_attrib = 'method_call' plugin_attrib = 'method_call'
interfaces = {'method_name', 'params'} interfaces = set(('method_name', 'params'))
subinterfaces = {} subinterfaces = set(())
plugin_attrib_map = {} plugin_attrib_map = {}
plugin_tag_map = {} plugin_tag_map = {}
@@ -46,8 +46,8 @@ class MethodResponse(ElementBase):
name = 'methodResponse' name = 'methodResponse'
namespace = 'jabber:iq:rpc' namespace = 'jabber:iq:rpc'
plugin_attrib = 'method_response' plugin_attrib = 'method_response'
interfaces = {'params', 'fault'} interfaces = set(('params', 'fault'))
subinterfaces = {} subinterfaces = set(())
plugin_attrib_map = {} plugin_attrib_map = {}
plugin_tag_map = {} plugin_tag_map = {}

View File

@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0012.last_activity import XEP_0012
register_plugin(XEP_0012) register_plugin(XEP_0012)
# Retain some backwards compatibility
xep_0004 = XEP_0012

View File

@@ -29,7 +29,7 @@ class XEP_0012(BasePlugin):
name = 'xep_0012' name = 'xep_0012'
description = 'XEP-0012: Last Activity' description = 'XEP-0012: Last Activity'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):
@@ -66,7 +66,7 @@ class XEP_0012(BasePlugin):
self.del_last_activity(jid) self.del_last_activity(jid)
def start_uptime(self, status=None): def start_uptime(self, status=None):
self.set_last_activity(None, 0, status) self.set_last_activity(jid, 0, status)
def set_last_activity(self, jid=None, seconds=None, status=None): def set_last_activity(self, jid=None, seconds=None, status=None):
self.api['set_last_activity'](jid, args={ self.api['set_last_activity'](jid, args={

View File

@@ -14,7 +14,7 @@ class LastActivity(ElementBase):
name = 'query' name = 'query'
namespace = 'jabber:iq:last' namespace = 'jabber:iq:last'
plugin_attrib = 'last_activity' plugin_attrib = 'last_activity'
interfaces = {'seconds', 'status'} interfaces = set(('seconds', 'status'))
def get_seconds(self): def get_seconds(self):
return int(self._get_attr('seconds')) return int(self._get_attr('seconds'))

View File

@@ -29,7 +29,7 @@ class XEP_0013(BasePlugin):
name = 'xep_0013' name = 'xep_0013'
description = 'XEP-0013: Flexible Offline Message Retrieval' description = 'XEP-0013: Flexible Offline Message Retrieval'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -14,7 +14,7 @@ class Offline(ElementBase):
name = 'offline' name = 'offline'
namespace = 'http://jabber.org/protocol/offline' namespace = 'http://jabber.org/protocol/offline'
plugin_attrib = 'offline' plugin_attrib = 'offline'
interfaces = {'fetch', 'purge', 'results'} interfaces = set(['fetch', 'purge', 'results'])
bool_interfaces = interfaces bool_interfaces = interfaces
def setup(self, xml=None): def setup(self, xml=None):
@@ -39,9 +39,9 @@ class Item(ElementBase):
name = 'item' name = 'item'
namespace = 'http://jabber.org/protocol/offline' namespace = 'http://jabber.org/protocol/offline'
plugin_attrib = 'item' plugin_attrib = 'item'
interfaces = {'action', 'node', 'jid'} interfaces = set(['action', 'node', 'jid'])
actions = {'view', 'remove'} actions = set(['view', 'remove'])
def get_jid(self): def get_jid(self):
return JID(self._get_attr('jid')) return JID(self._get_attr('jid'))

View File

@@ -17,7 +17,7 @@ class XEP_0016(BasePlugin):
name = 'xep_0016' name = 'xep_0016'
description = 'XEP-0016: Privacy Lists' description = 'XEP-0016: Privacy Lists'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -18,14 +18,14 @@ class Active(ElementBase):
name = 'active' name = 'active'
namespace = 'jabber:iq:privacy' namespace = 'jabber:iq:privacy'
plugin_attrib = name plugin_attrib = name
interfaces = {'name'} interfaces = set(['name'])
class Default(ElementBase): class Default(ElementBase):
name = 'default' name = 'default'
namespace = 'jabber:iq:privacy' namespace = 'jabber:iq:privacy'
plugin_attrib = name plugin_attrib = name
interfaces = {'name'} interfaces = set(['name'])
class List(ElementBase): class List(ElementBase):
@@ -33,7 +33,7 @@ class List(ElementBase):
namespace = 'jabber:iq:privacy' namespace = 'jabber:iq:privacy'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'lists' plugin_multi_attrib = 'lists'
interfaces = {'name'} interfaces = set(['name'])
def add_item(self, value, action, order, itype=None, iq=False, def add_item(self, value, action, order, itype=None, iq=False,
message=False, presence_in=False, presence_out=False): message=False, presence_in=False, presence_out=False):
@@ -55,9 +55,9 @@ class Item(ElementBase):
namespace = 'jabber:iq:privacy' namespace = 'jabber:iq:privacy'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'items' plugin_multi_attrib = 'items'
interfaces = {'type', 'value', 'action', 'order', 'iq', interfaces = set(['type', 'value', 'action', 'order', 'iq',
'message', 'presence_in', 'presence_out'} 'message', 'presence_in', 'presence_out'])
bool_interfaces = {'message', 'iq', 'presence_in', 'presence_out'} bool_interfaces = set(['message', 'iq', 'presence_in', 'presence_out'])
type_values = ('', 'jid', 'group', 'subscription') type_values = ('', 'jid', 'group', 'subscription')
action_values = ('allow', 'deny') action_values = ('allow', 'deny')

View File

@@ -24,7 +24,7 @@ class XEP_0020(BasePlugin):
name = 'xep_0020' name = 'xep_0020'
description = 'XEP-0020: Feature Negotiation' description = 'XEP-0020: Feature Negotiation'
dependencies = {'xep_0004', 'xep_0030'} dependencies = set(['xep_0004', 'xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -13,7 +13,7 @@ class Signed(ElementBase):
name = 'x' name = 'x'
namespace = 'jabber:x:signed' namespace = 'jabber:x:signed'
plugin_attrib = 'signed' plugin_attrib = 'signed'
interfaces = {'signed'} interfaces = set(['signed'])
is_extension = True is_extension = True
def set_signed(self, value): def set_signed(self, value):
@@ -33,7 +33,7 @@ class Encrypted(ElementBase):
name = 'x' name = 'x'
namespace = 'jabber:x:encrypted' namespace = 'jabber:x:encrypted'
plugin_attrib = 'encrypted' plugin_attrib = 'encrypted'
interfaces = {'encrypted'} interfaces = set(['encrypted'])
is_extension = True is_extension = True
def set_encrypted(self, value): def set_encrypted(self, value):

View File

@@ -15,3 +15,8 @@ from slixmpp.plugins.xep_0030.disco import XEP_0030
register_plugin(XEP_0030) register_plugin(XEP_0030)
# Retain some backwards compatibility
xep_0030 = XEP_0030
XEP_0030.getInfo = XEP_0030.get_info
XEP_0030.make_static = XEP_0030.restore_defaults

View File

@@ -71,8 +71,8 @@ class DiscoInfo(ElementBase):
name = 'query' name = 'query'
namespace = 'http://jabber.org/protocol/disco#info' namespace = 'http://jabber.org/protocol/disco#info'
plugin_attrib = 'disco_info' plugin_attrib = 'disco_info'
interfaces = {'node', 'features', 'identities'} interfaces = set(('node', 'features', 'identities'))
lang_interfaces = {'identities'} lang_interfaces = set(('identities',))
# Cache identities and features # Cache identities and features
_identities = set() _identities = set()
@@ -91,7 +91,7 @@ class DiscoInfo(ElementBase):
""" """
ElementBase.setup(self, xml) ElementBase.setup(self, xml)
self._identities = {id[0:3] for id in self['identities']} self._identities = set([id[0:3] for id in self['identities']])
self._features = self['features'] self._features = self['features']
def add_identity(self, category, itype, name=None, lang=None): def add_identity(self, category, itype, name=None, lang=None):
@@ -137,7 +137,7 @@ class DiscoInfo(ElementBase):
identity = (category, itype, lang) identity = (category, itype, lang)
if identity in self._identities: if identity in self._identities:
self._identities.remove(identity) self._identities.remove(identity)
for id_xml in self.xml.findall('{%s}identity' % self.namespace): for id_xml in self.findall('{%s}identity' % self.namespace):
id = (id_xml.attrib['category'], id = (id_xml.attrib['category'],
id_xml.attrib['type'], id_xml.attrib['type'],
id_xml.attrib.get('{%s}lang' % self.xml_ns, None)) id_xml.attrib.get('{%s}lang' % self.xml_ns, None))
@@ -163,7 +163,7 @@ class DiscoInfo(ElementBase):
identities = set() identities = set()
else: else:
identities = [] identities = []
for id_xml in self.xml.findall('{%s}identity' % self.namespace): for id_xml in self.findall('{%s}identity' % self.namespace):
xml_lang = id_xml.attrib.get('{%s}lang' % self.xml_ns, None) xml_lang = id_xml.attrib.get('{%s}lang' % self.xml_ns, None)
if lang is None or xml_lang == lang: if lang is None or xml_lang == lang:
id = (id_xml.attrib['category'], id = (id_xml.attrib['category'],
@@ -205,7 +205,7 @@ class DiscoInfo(ElementBase):
Arguments: Arguments:
lang -- Optional, standard xml:lang value. lang -- Optional, standard xml:lang value.
""" """
for id_xml in self.xml.findall('{%s}identity' % self.namespace): for id_xml in self.findall('{%s}identity' % self.namespace):
if lang is None: if lang is None:
self.xml.remove(id_xml) self.xml.remove(id_xml)
elif id_xml.attrib.get('{%s}lang' % self.xml_ns, None) == lang: elif id_xml.attrib.get('{%s}lang' % self.xml_ns, None) == lang:
@@ -239,7 +239,7 @@ class DiscoInfo(ElementBase):
""" """
if feature in self._features: if feature in self._features:
self._features.remove(feature) self._features.remove(feature)
for feature_xml in self.xml.findall('{%s}feature' % self.namespace): for feature_xml in self.findall('{%s}feature' % self.namespace):
if feature_xml.attrib['var'] == feature: if feature_xml.attrib['var'] == feature:
self.xml.remove(feature_xml) self.xml.remove(feature_xml)
return True return True
@@ -251,7 +251,7 @@ class DiscoInfo(ElementBase):
features = set() features = set()
else: else:
features = [] features = []
for feature_xml in self.xml.findall('{%s}feature' % self.namespace): for feature_xml in self.findall('{%s}feature' % self.namespace):
if dedupe: if dedupe:
features.add(feature_xml.attrib['var']) features.add(feature_xml.attrib['var'])
else: else:
@@ -272,5 +272,5 @@ class DiscoInfo(ElementBase):
def del_features(self): def del_features(self):
"""Remove all features.""" """Remove all features."""
self._features = set() self._features = set()
for feature_xml in self.xml.findall('{%s}feature' % self.namespace): for feature_xml in self.findall('{%s}feature' % self.namespace):
self.xml.remove(feature_xml) self.xml.remove(feature_xml)

View File

@@ -45,7 +45,7 @@ class DiscoItems(ElementBase):
name = 'query' name = 'query'
namespace = 'http://jabber.org/protocol/disco#items' namespace = 'http://jabber.org/protocol/disco#items'
plugin_attrib = 'disco_items' plugin_attrib = 'disco_items'
interfaces = {'node', 'items'} interfaces = set(('node', 'items'))
# Cache items # Cache items
_items = set() _items = set()
@@ -62,7 +62,7 @@ class DiscoItems(ElementBase):
xml -- Use an existing XML object for the stanza's values. xml -- Use an existing XML object for the stanza's values.
""" """
ElementBase.setup(self, xml) ElementBase.setup(self, xml)
self._items = {item[0:2] for item in self['items']} self._items = set([item[0:2] for item in self['items']])
def add_item(self, jid, node=None, name=None): def add_item(self, jid, node=None, name=None):
""" """
@@ -95,7 +95,7 @@ class DiscoItems(ElementBase):
node -- Optional extra identifying information. node -- Optional extra identifying information.
""" """
if (jid, node) in self._items: if (jid, node) in self._items:
for item_xml in self.xml.findall('{%s}item' % self.namespace): for item_xml in self.findall('{%s}item' % self.namespace):
item = (item_xml.attrib['jid'], item = (item_xml.attrib['jid'],
item_xml.attrib.get('node', None)) item_xml.attrib.get('node', None))
if item == (jid, node): if item == (jid, node):
@@ -138,7 +138,7 @@ class DiscoItem(ElementBase):
name = 'item' name = 'item'
namespace = 'http://jabber.org/protocol/disco#items' namespace = 'http://jabber.org/protocol/disco#items'
plugin_attrib = name plugin_attrib = name
interfaces = {'jid', 'node', 'name'} interfaces = set(('jid', 'node', 'name'))
def get_node(self): def get_node(self):
"""Return the item's node name or ``None``.""" """Return the item's node name or ``None``."""

View File

@@ -7,6 +7,7 @@
""" """
import logging import logging
import threading
from slixmpp import Iq from slixmpp import Iq
from slixmpp.exceptions import XMPPError, IqError, IqTimeout from slixmpp.exceptions import XMPPError, IqError, IqTimeout
@@ -47,6 +48,7 @@ class StaticDisco(object):
self.nodes = {} self.nodes = {}
self.xmpp = xmpp self.xmpp = xmpp
self.disco = disco self.disco = disco
self.lock = threading.RLock()
def add_node(self, jid=None, node=None, ifrom=None): def add_node(self, jid=None, node=None, ifrom=None):
""" """
@@ -57,45 +59,48 @@ class StaticDisco(object):
jid -- The JID that will own the new stanzas. jid -- The JID that will own the new stanzas.
node -- The node that will own the new stanzas. node -- The node that will own the new stanzas.
""" """
if jid is None: with self.lock:
jid = self.xmpp.boundjid.full if jid is None:
if node is None: jid = self.xmpp.boundjid.full
node = '' if node is None:
if ifrom is None: node = ''
ifrom = '' if ifrom is None:
if isinstance(ifrom, JID): ifrom = ''
ifrom = ifrom.full if isinstance(ifrom, JID):
if (jid, node, ifrom) not in self.nodes: ifrom = ifrom.full
self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(), if (jid, node, ifrom) not in self.nodes:
'items': DiscoItems()} self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(),
self.nodes[(jid, node, ifrom)]['info']['node'] = node 'items': DiscoItems()}
self.nodes[(jid, node, ifrom)]['items']['node'] = node self.nodes[(jid, node, ifrom)]['info']['node'] = node
self.nodes[(jid, node, ifrom)]['items']['node'] = node
def get_node(self, jid=None, node=None, ifrom=None): def get_node(self, jid=None, node=None, ifrom=None):
if jid is None: with self.lock:
jid = self.xmpp.boundjid.full if jid is None:
if node is None: jid = self.xmpp.boundjid.full
node = '' if node is None:
if ifrom is None: node = ''
ifrom = '' if ifrom is None:
if isinstance(ifrom, JID): ifrom = ''
ifrom = ifrom.full if isinstance(ifrom, JID):
if (jid, node, ifrom) not in self.nodes: ifrom = ifrom.full
self.add_node(jid, node, ifrom) if (jid, node, ifrom) not in self.nodes:
return self.nodes[(jid, node, ifrom)] self.add_node(jid, node, ifrom)
return self.nodes[(jid, node, ifrom)]
def node_exists(self, jid=None, node=None, ifrom=None): def node_exists(self, jid=None, node=None, ifrom=None):
if jid is None: with self.lock:
jid = self.xmpp.boundjid.full if jid is None:
if node is None: jid = self.xmpp.boundjid.full
node = '' if node is None:
if ifrom is None: node = ''
ifrom = '' if ifrom is None:
if isinstance(ifrom, JID): ifrom = ''
ifrom = ifrom.full if isinstance(ifrom, JID):
if (jid, node, ifrom) not in self.nodes: ifrom = ifrom.full
return False if (jid, node, ifrom) not in self.nodes:
return True return False
return True
# ================================================================= # =================================================================
# Node Handlers # Node Handlers
@@ -194,13 +199,14 @@ class StaticDisco(object):
The data parameter is not used. The data parameter is not used.
""" """
if not self.node_exists(jid, node): with self.lock:
if not node: if not self.node_exists(jid, node):
return DiscoInfo() if not node:
return DiscoInfo()
else:
raise XMPPError(condition='item-not-found')
else: else:
raise XMPPError(condition='item-not-found') return self.get_node(jid, node)['info']
else:
return self.get_node(jid, node)['info']
def set_info(self, jid, node, ifrom, data): def set_info(self, jid, node, ifrom, data):
""" """
@@ -208,8 +214,9 @@ class StaticDisco(object):
The data parameter is a disco#info substanza. The data parameter is a disco#info substanza.
""" """
self.add_node(jid, node) with self.lock:
self.get_node(jid, node)['info'] = data self.add_node(jid, node)
self.get_node(jid, node)['info'] = data
def del_info(self, jid, node, ifrom, data): def del_info(self, jid, node, ifrom, data):
""" """
@@ -217,8 +224,9 @@ class StaticDisco(object):
The data parameter is not used. The data parameter is not used.
""" """
if self.node_exists(jid, node): with self.lock:
self.get_node(jid, node)['info'] = DiscoInfo() if self.node_exists(jid, node):
self.get_node(jid, node)['info'] = DiscoInfo()
def get_items(self, jid, node, ifrom, data): def get_items(self, jid, node, ifrom, data):
""" """
@@ -226,13 +234,14 @@ class StaticDisco(object):
The data parameter is not used. The data parameter is not used.
""" """
if not self.node_exists(jid, node): with self.lock:
if not node: if not self.node_exists(jid, node):
return DiscoItems() if not node:
return DiscoItems()
else:
raise XMPPError(condition='item-not-found')
else: else:
raise XMPPError(condition='item-not-found') return self.get_node(jid, node)['items']
else:
return self.get_node(jid, node)['items']
def set_items(self, jid, node, ifrom, data): def set_items(self, jid, node, ifrom, data):
""" """
@@ -241,9 +250,10 @@ class StaticDisco(object):
The data parameter may provide: The data parameter may provide:
items -- A set of items in tuple format. items -- A set of items in tuple format.
""" """
items = data.get('items', set()) with self.lock:
self.add_node(jid, node) items = data.get('items', set())
self.get_node(jid, node)['items']['items'] = items self.add_node(jid, node)
self.get_node(jid, node)['items']['items'] = items
def del_items(self, jid, node, ifrom, data): def del_items(self, jid, node, ifrom, data):
""" """
@@ -251,8 +261,9 @@ class StaticDisco(object):
The data parameter is not used. The data parameter is not used.
""" """
if self.node_exists(jid, node): with self.lock:
self.get_node(jid, node)['items'] = DiscoItems() if self.node_exists(jid, node):
self.get_node(jid, node)['items'] = DiscoItems()
def add_identity(self, jid, node, ifrom, data): def add_identity(self, jid, node, ifrom, data):
""" """
@@ -264,12 +275,13 @@ class StaticDisco(object):
name -- Optional human readable name for this identity. name -- Optional human readable name for this identity.
lang -- Optional standard xml:lang value. lang -- Optional standard xml:lang value.
""" """
self.add_node(jid, node) with self.lock:
self.get_node(jid, node)['info'].add_identity( self.add_node(jid, node)
data.get('category', ''), self.get_node(jid, node)['info'].add_identity(
data.get('itype', ''), data.get('category', ''),
data.get('name', None), data.get('itype', ''),
data.get('lang', None)) data.get('name', None),
data.get('lang', None))
def set_identities(self, jid, node, ifrom, data): def set_identities(self, jid, node, ifrom, data):
""" """
@@ -279,9 +291,10 @@ class StaticDisco(object):
identities -- A list of identities in tuple form: identities -- A list of identities in tuple form:
(category, type, name, lang) (category, type, name, lang)
""" """
identities = data.get('identities', set()) with self.lock:
self.add_node(jid, node) identities = data.get('identities', set())
self.get_node(jid, node)['info']['identities'] = identities self.add_node(jid, node)
self.get_node(jid, node)['info']['identities'] = identities
def del_identity(self, jid, node, ifrom, data): def del_identity(self, jid, node, ifrom, data):
""" """
@@ -293,12 +306,13 @@ class StaticDisco(object):
name -- Optional human readable name for this identity. name -- Optional human readable name for this identity.
lang -- Optional, standard xml:lang value. lang -- Optional, standard xml:lang value.
""" """
if self.node_exists(jid, node): with self.lock:
self.get_node(jid, node)['info'].del_identity( if self.node_exists(jid, node):
data.get('category', ''), self.get_node(jid, node)['info'].del_identity(
data.get('itype', ''), data.get('category', ''),
data.get('name', None), data.get('itype', ''),
data.get('lang', None)) data.get('name', None),
data.get('lang', None))
def del_identities(self, jid, node, ifrom, data): def del_identities(self, jid, node, ifrom, data):
""" """
@@ -306,8 +320,9 @@ class StaticDisco(object):
The data parameter is not used. The data parameter is not used.
""" """
if self.node_exists(jid, node): with self.lock:
del self.get_node(jid, node)['info']['identities'] if self.node_exists(jid, node):
del self.get_node(jid, node)['info']['identities']
def add_feature(self, jid, node, ifrom, data): def add_feature(self, jid, node, ifrom, data):
""" """
@@ -316,9 +331,10 @@ class StaticDisco(object):
The data parameter should include: The data parameter should include:
feature -- The namespace of the supported feature. feature -- The namespace of the supported feature.
""" """
self.add_node(jid, node) with self.lock:
self.get_node(jid, node)['info'].add_feature( self.add_node(jid, node)
data.get('feature', '')) self.get_node(jid, node)['info'].add_feature(
data.get('feature', ''))
def set_features(self, jid, node, ifrom, data): def set_features(self, jid, node, ifrom, data):
""" """
@@ -327,9 +343,10 @@ class StaticDisco(object):
The data parameter should include: The data parameter should include:
features -- The new set of supported features. features -- The new set of supported features.
""" """
features = data.get('features', set()) with self.lock:
self.add_node(jid, node) features = data.get('features', set())
self.get_node(jid, node)['info']['features'] = features self.add_node(jid, node)
self.get_node(jid, node)['info']['features'] = features
def del_feature(self, jid, node, ifrom, data): def del_feature(self, jid, node, ifrom, data):
""" """
@@ -338,9 +355,10 @@ class StaticDisco(object):
The data parameter should include: The data parameter should include:
feature -- The namespace of the removed feature. feature -- The namespace of the removed feature.
""" """
if self.node_exists(jid, node): with self.lock:
self.get_node(jid, node)['info'].del_feature( if self.node_exists(jid, node):
data.get('feature', '')) self.get_node(jid, node)['info'].del_feature(
data.get('feature', ''))
def del_features(self, jid, node, ifrom, data): def del_features(self, jid, node, ifrom, data):
""" """
@@ -348,9 +366,10 @@ class StaticDisco(object):
The data parameter is not used. The data parameter is not used.
""" """
if not self.node_exists(jid, node): with self.lock:
return if not self.node_exists(jid, node):
del self.get_node(jid, node)['info']['features'] return
del self.get_node(jid, node)['info']['features']
def add_item(self, jid, node, ifrom, data): def add_item(self, jid, node, ifrom, data):
""" """
@@ -362,11 +381,12 @@ class StaticDisco(object):
non-addressable items. non-addressable items.
name -- Optional human readable name for the item. name -- Optional human readable name for the item.
""" """
self.add_node(jid, node) with self.lock:
self.get_node(jid, node)['items'].add_item( self.add_node(jid, node)
data.get('ijid', ''), self.get_node(jid, node)['items'].add_item(
node=data.get('inode', ''), data.get('ijid', ''),
name=data.get('name', '')) node=data.get('inode', ''),
name=data.get('name', ''))
def del_item(self, jid, node, ifrom, data): def del_item(self, jid, node, ifrom, data):
""" """
@@ -376,10 +396,11 @@ class StaticDisco(object):
ijid -- JID of the item to remove. ijid -- JID of the item to remove.
inode -- Optional extra identifying information. inode -- Optional extra identifying information.
""" """
if self.node_exists(jid, node): with self.lock:
self.get_node(jid, node)['items'].del_item( if self.node_exists(jid, node):
data.get('ijid', ''), self.get_node(jid, node)['items'].del_item(
node=data.get('inode', None)) data.get('ijid', ''),
node=data.get('inode', None))
def cache_info(self, jid, node, ifrom, data): def cache_info(self, jid, node, ifrom, data):
""" """
@@ -389,11 +410,12 @@ class StaticDisco(object):
containing the disco info to cache, or containing the disco info to cache, or
the disco#info substanza itself. the disco#info substanza itself.
""" """
if isinstance(data, Iq): with self.lock:
data = data['disco_info'] if isinstance(data, Iq):
data = data['disco_info']
self.add_node(jid, node, ifrom) self.add_node(jid, node, ifrom)
self.get_node(jid, node, ifrom)['info'] = data self.get_node(jid, node, ifrom)['info'] = data
def get_cached_info(self, jid, node, ifrom, data): def get_cached_info(self, jid, node, ifrom, data):
""" """
@@ -401,7 +423,8 @@ class StaticDisco(object):
The data parameter is not used. The data parameter is not used.
""" """
if not self.node_exists(jid, node, ifrom): with self.lock:
return None if not self.node_exists(jid, node, ifrom):
else: return None
return self.get_node(jid, node, ifrom)['info'] else:
return self.get_node(jid, node, ifrom)['info']

View File

@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0033.addresses import XEP_0033
register_plugin(XEP_0033) register_plugin(XEP_0033)
# Retain some backwards compatibility
xep_0033 = XEP_0033
Addresses.addAddress = Addresses.add_address

View File

@@ -22,7 +22,7 @@ class XEP_0033(BasePlugin):
name = 'xep_0033' name = 'xep_0033'
description = 'XEP-0033: Extended Stanza Addressing' description = 'XEP-0033: Extended Stanza Addressing'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -37,9 +37,9 @@ class Address(ElementBase):
name = 'address' name = 'address'
namespace = 'http://jabber.org/protocol/address' namespace = 'http://jabber.org/protocol/address'
plugin_attrib = 'address' plugin_attrib = 'address'
interfaces = {'type', 'jid', 'node', 'uri', 'desc', 'delivered'} interfaces = set(['type', 'jid', 'node', 'uri', 'desc', 'delivered'])
address_types = {'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'} address_types = set(('bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'))
def get_jid(self): def get_jid(self):
return JID(self._get_attr('jid')) return JID(self._get_attr('jid'))
@@ -117,12 +117,15 @@ for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'):
setattr(Addresses, "set_%s" % atype, set_multi) setattr(Addresses, "set_%s" % atype, set_multi)
setattr(Addresses, "del_%s" % atype, del_multi) setattr(Addresses, "del_%s" % atype, del_multi)
# To retain backwards compatibility:
setattr(Addresses, "get%s" % atype.title(), get_multi)
setattr(Addresses, "set%s" % atype.title(), set_multi)
setattr(Addresses, "del%s" % atype.title(), del_multi)
if atype == 'all': if atype == 'all':
Addresses.interfaces.add('addresses') Addresses.interfaces.add('addresses')
setattr(Addresses, "get_addresses", get_multi) setattr(Addresses, "getAddresses", get_multi)
setattr(Addresses, "set_addresses", set_multi) setattr(Addresses, "setAddresses", set_multi)
setattr(Addresses, "del_addresses", del_multi) setattr(Addresses, "delAddresses", del_multi)
register_stanza_plugin(Addresses, Address, iterable=True) register_stanza_plugin(Addresses, Address, iterable=True)

View File

@@ -25,86 +25,86 @@ class MUCPresence(ElementBase):
name = 'x' name = 'x'
namespace = 'http://jabber.org/protocol/muc#user' namespace = 'http://jabber.org/protocol/muc#user'
plugin_attrib = 'muc' plugin_attrib = 'muc'
interfaces = {'affiliation', 'role', 'jid', 'nick', 'room'} interfaces = set(('affiliation', 'role', 'jid', 'nick', 'room'))
affiliations = {'', } affiliations = set(('', ))
roles = {'', } roles = set(('', ))
def get_xml_item(self): def getXMLItem(self):
item = self.xml.find('{http://jabber.org/protocol/muc#user}item') item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
if item is None: if item is None:
item = ET.Element('{http://jabber.org/protocol/muc#user}item') item = ET.Element('{http://jabber.org/protocol/muc#user}item')
self.xml.append(item) self.xml.append(item)
return item return item
def get_affiliation(self): def getAffiliation(self):
#TODO if no affilation, set it to the default and return default #TODO if no affilation, set it to the default and return default
item = self.get_xml_item() item = self.getXMLItem()
return item.get('affiliation', '') return item.get('affiliation', '')
def set_affiliation(self, value): def setAffiliation(self, value):
item = self.get_xml_item() item = self.getXMLItem()
#TODO check for valid affiliation #TODO check for valid affiliation
item.attrib['affiliation'] = value item.attrib['affiliation'] = value
return self return self
def del_affiliation(self): def delAffiliation(self):
item = self.get_xml_item() item = self.getXMLItem()
#TODO set default affiliation #TODO set default affiliation
if 'affiliation' in item.attrib: del item.attrib['affiliation'] if 'affiliation' in item.attrib: del item.attrib['affiliation']
return self return self
def get_jid(self): def getJid(self):
item = self.get_xml_item() item = self.getXMLItem()
return JID(item.get('jid', '')) return JID(item.get('jid', ''))
def set_jid(self, value): def setJid(self, value):
item = self.get_xml_item() item = self.getXMLItem()
if not isinstance(value, str): if not isinstance(value, str):
value = str(value) value = str(value)
item.attrib['jid'] = value item.attrib['jid'] = value
return self return self
def del_jid(self): def delJid(self):
item = self.get_xml_item() item = self.getXMLItem()
if 'jid' in item.attrib: del item.attrib['jid'] if 'jid' in item.attrib: del item.attrib['jid']
return self return self
def get_role(self): def getRole(self):
item = self.get_xml_item() item = self.getXMLItem()
#TODO get default role, set default role if none #TODO get default role, set default role if none
return item.get('role', '') return item.get('role', '')
def set_role(self, value): def setRole(self, value):
item = self.get_xml_item() item = self.getXMLItem()
#TODO check for valid role #TODO check for valid role
item.attrib['role'] = value item.attrib['role'] = value
return self return self
def del_role(self): def delRole(self):
item = self.get_xml_item() item = self.getXMLItem()
#TODO set default role #TODO set default role
if 'role' in item.attrib: del item.attrib['role'] if 'role' in item.attrib: del item.attrib['role']
return self return self
def get_nick(self): def getNick(self):
return self.parent()['from'].resource return self.parent()['from'].resource
def get_room(self): def getRoom(self):
return self.parent()['from'].bare return self.parent()['from'].bare
def set_nick(self, value): def setNick(self, value):
log.warning("Cannot set nick through mucpresence plugin.") log.warning("Cannot set nick through mucpresence plugin.")
return self return self
def set_room(self, value): def setRoom(self, value):
log.warning("Cannot set room through mucpresence plugin.") log.warning("Cannot set room through mucpresence plugin.")
return self return self
def del_nick(self): def delNick(self):
log.warning("Cannot delete nick through mucpresence plugin.") log.warning("Cannot delete nick through mucpresence plugin.")
return self return self
def del_room(self): def delRoom(self):
log.warning("Cannot delete room through mucpresence plugin.") log.warning("Cannot delete room through mucpresence plugin.")
return self return self
@@ -117,11 +117,11 @@ class XEP_0045(BasePlugin):
name = 'xep_0045' name = 'xep_0045'
description = 'XEP-0045: Multi-User Chat' description = 'XEP-0045: Multi-User Chat'
dependencies = {'xep_0030', 'xep_0004'} dependencies = set(['xep_0030', 'xep_0004'])
def plugin_init(self): def plugin_init(self):
self.rooms = {} self.rooms = {}
self.our_nicks = {} self.ourNicks = {}
self.xep = '0045' self.xep = '0045'
# load MUC support in presence stanzas # load MUC support in presence stanzas
register_stanza_plugin(Presence, MUCPresence) register_stanza_plugin(Presence, MUCPresence)
@@ -160,7 +160,6 @@ class XEP_0045(BasePlugin):
got_online = False got_online = False
if pr['muc']['room'] not in self.rooms.keys(): if pr['muc']['room'] not in self.rooms.keys():
return return
self.xmpp.roster[pr['from']].ignore_updates = True
entry = pr['muc'].get_stanza_values() entry = pr['muc'].get_stanza_values()
entry['show'] = pr['show'] entry['show'] = pr['show']
entry['status'] = pr['status'] entry['status'] = pr['status']
@@ -201,28 +200,28 @@ class XEP_0045(BasePlugin):
""" """
self.xmpp.event('groupchat_subject', msg) self.xmpp.event('groupchat_subject', msg)
def jid_in_room(self, room, jid): def jidInRoom(self, room, jid):
for nick in self.rooms[room]: for nick in self.rooms[room]:
entry = self.rooms[room][nick] entry = self.rooms[room][nick]
if entry is not None and entry['jid'].full == jid: if entry is not None and entry['jid'].full == jid:
return True return True
return False return False
def get_nick(self, room, jid): def getNick(self, room, jid):
for nick in self.rooms[room]: for nick in self.rooms[room]:
entry = self.rooms[room][nick] entry = self.rooms[room][nick]
if entry is not None and entry['jid'].full == jid: if entry is not None and entry['jid'].full == jid:
return nick return nick
def configure_room(self, room, form=None, ifrom=None): def configureRoom(self, room, form=None, ifrom=None):
if form is None: if form is None:
form = self.get_room_config(room, ifrom=ifrom) form = self.getRoomConfig(room, ifrom=ifrom)
iq = self.xmpp.make_iq_set() iq = self.xmpp.make_iq_set()
iq['to'] = room iq['to'] = room
if ifrom is not None: if ifrom is not None:
iq['from'] = ifrom iq['from'] = ifrom
query = ET.Element('{http://jabber.org/protocol/muc#owner}query') query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
form['type'] = 'submit' form = form.getXML('submit')
query.append(form) query.append(form)
iq.append(query) iq.append(query)
# For now, swallow errors to preserve existing API # For now, swallow errors to preserve existing API
@@ -234,7 +233,7 @@ class XEP_0045(BasePlugin):
return False return False
return True return True
def join_muc(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None, pfrom=None): def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None, pfrom=None):
""" Join the specified room, requesting 'maxhistory' lines of history. """ Join the specified room, requesting 'maxhistory' lines of history.
""" """
stanza = self.xmpp.make_presence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow, pfrom=pfrom) stanza = self.xmpp.make_presence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow, pfrom=pfrom)
@@ -258,7 +257,7 @@ class XEP_0045(BasePlugin):
expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)}) expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)})
self.xmpp.send(stanza, expect) self.xmpp.send(stanza, expect)
self.rooms[room] = {} self.rooms[room] = {}
self.our_nicks[room] = nick self.ourNicks[room] = nick
def destroy(self, room, reason='', altroom = '', ifrom=None): def destroy(self, room, reason='', altroom = '', ifrom=None):
iq = self.xmpp.make_iq_set() iq = self.xmpp.make_iq_set()
@@ -283,7 +282,7 @@ class XEP_0045(BasePlugin):
return False return False
return True return True
def set_affiliation(self, room, jid=None, nick=None, affiliation='member', ifrom=None): def setAffiliation(self, room, jid=None, nick=None, affiliation='member', ifrom=None):
""" Change room affiliation.""" """ Change room affiliation."""
if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'): if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
raise TypeError raise TypeError
@@ -305,7 +304,7 @@ class XEP_0045(BasePlugin):
return False return False
return True return True
def set_role(self, room, nick, role): def setRole(self, room, nick, role):
""" Change role property of a nick in a room. """ Change role property of a nick in a room.
Typically, roles are temporary (they last only as long as you are in the Typically, roles are temporary (they last only as long as you are in the
room), whereas affiliations are permanent (they last across groupchat room), whereas affiliations are permanent (they last across groupchat
@@ -337,7 +336,7 @@ class XEP_0045(BasePlugin):
msg.append(x) msg.append(x)
self.xmpp.send(msg) self.xmpp.send(msg)
def leave_muc(self, room, nick, msg='', pfrom=None): def leaveMUC(self, room, nick, msg='', pfrom=None):
""" Leave the specified room. """ Leave the specified room.
""" """
if msg: if msg:
@@ -346,7 +345,7 @@ class XEP_0045(BasePlugin):
self.xmpp.send_presence(pshow='unavailable', pto="%s/%s" % (room, nick), pfrom=pfrom) self.xmpp.send_presence(pshow='unavailable', pto="%s/%s" % (room, nick), pfrom=pfrom)
del self.rooms[room] del self.rooms[room]
def get_room_config(self, room, ifrom=''): def getRoomConfig(self, room, ifrom=''):
iq = self.xmpp.make_iq_get('http://jabber.org/protocol/muc#owner') iq = self.xmpp.make_iq_get('http://jabber.org/protocol/muc#owner')
iq['to'] = room iq['to'] = room
iq['from'] = ifrom iq['from'] = ifrom
@@ -360,9 +359,9 @@ class XEP_0045(BasePlugin):
form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x') form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
if form is None: if form is None:
raise ValueError raise ValueError
return self.xmpp.plugin['xep_0004'].build_form(form) return self.xmpp.plugin['xep_0004'].buildForm(form)
def cancel_config(self, room, ifrom=None): def cancelConfig(self, room, ifrom=None):
query = ET.Element('{http://jabber.org/protocol/muc#owner}query') query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
x = ET.Element('{jabber:x:data}x', type='cancel') x = ET.Element('{jabber:x:data}x', type='cancel')
query.append(x) query.append(x)
@@ -371,40 +370,40 @@ class XEP_0045(BasePlugin):
iq['from'] = ifrom iq['from'] = ifrom
iq.send() iq.send()
def set_room_config(self, room, config, ifrom=''): def setRoomConfig(self, room, config, ifrom=''):
query = ET.Element('{http://jabber.org/protocol/muc#owner}query') query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
config['type'] = 'submit' x = config.getXML('submit')
query.append(config) query.append(x)
iq = self.xmpp.make_iq_set(query) iq = self.xmpp.make_iq_set(query)
iq['to'] = room iq['to'] = room
iq['from'] = ifrom iq['from'] = ifrom
iq.send() iq.send()
def get_joined_rooms(self): def getJoinedRooms(self):
return self.rooms.keys() return self.rooms.keys()
def get_our_jid_in_room(self, room_jid): def getOurJidInRoom(self, roomJid):
""" Return the jid we're using in a room. """ Return the jid we're using in a room.
""" """
return "%s/%s" % (room_jid, self.our_nicks[room_jid]) return "%s/%s" % (roomJid, self.ourNicks[roomJid])
def get_jid_property(self, room, nick, jid_property): def getJidProperty(self, room, nick, jidProperty):
""" Get the property of a nick in a room, such as its 'jid' or 'affiliation' """ Get the property of a nick in a room, such as its 'jid' or 'affiliation'
If not found, return None. If not found, return None.
""" """
if room in self.rooms and nick in self.rooms[room] and jid_property in self.rooms[room][nick]: if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]:
return self.rooms[room][nick][jid_property] return self.rooms[room][nick][jidProperty]
else: else:
return None return None
def get_roster(self, room): def getRoster(self, room):
""" Get the list of nicks in a room. """ Get the list of nicks in a room.
""" """
if room not in self.rooms.keys(): if room not in self.rooms.keys():
return None return None
return self.rooms[room].keys() return self.rooms[room].keys()
def get_users_by_affiliation(cls, room, affiliation='member', ifrom=None): def getUsersByAffiliation(cls, room, affiliation='member', ifrom=None):
if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'): if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
raise TypeError raise TypeError
query = ET.Element('{http://jabber.org/protocol/muc#admin}query') query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
@@ -415,4 +414,5 @@ class XEP_0045(BasePlugin):
return iq.send() return iq.send()
xep_0045 = XEP_0045
register_plugin(XEP_0045) register_plugin(XEP_0045)

View File

@@ -15,3 +15,7 @@ from slixmpp.plugins.xep_0047.ibb import XEP_0047
register_plugin(XEP_0047) register_plugin(XEP_0047)
# Retain some backwards compatibility
xep_0047 = XEP_0047

View File

@@ -18,7 +18,7 @@ class XEP_0047(BasePlugin):
name = 'xep_0047' name = 'xep_0047'
description = 'XEP-0047: In-band Bytestreams' description = 'XEP-0047: In-band Bytestreams'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
default_config = { default_config = {
'block_size': 4096, 'block_size': 4096,

View File

@@ -21,7 +21,7 @@ class Open(ElementBase):
name = 'open' name = 'open'
namespace = 'http://jabber.org/protocol/ibb' namespace = 'http://jabber.org/protocol/ibb'
plugin_attrib = 'ibb_open' plugin_attrib = 'ibb_open'
interfaces = {'block_size', 'sid', 'stanza'} interfaces = set(('block_size', 'sid', 'stanza'))
def get_block_size(self): def get_block_size(self):
return int(self._get_attr('block-size', '0')) return int(self._get_attr('block-size', '0'))
@@ -37,8 +37,8 @@ class Data(ElementBase):
name = 'data' name = 'data'
namespace = 'http://jabber.org/protocol/ibb' namespace = 'http://jabber.org/protocol/ibb'
plugin_attrib = 'ibb_data' plugin_attrib = 'ibb_data'
interfaces = {'seq', 'sid', 'data'} interfaces = set(('seq', 'sid', 'data'))
sub_interfaces = {'data'} sub_interfaces = set(['data'])
def get_seq(self): def get_seq(self):
return int(self._get_attr('seq', '0')) return int(self._get_attr('seq', '0'))
@@ -67,4 +67,4 @@ class Close(ElementBase):
name = 'close' name = 'close'
namespace = 'http://jabber.org/protocol/ibb' namespace = 'http://jabber.org/protocol/ibb'
plugin_attrib = 'ibb_close' plugin_attrib = 'ibb_close'
interfaces = {'sid'} interfaces = set(['sid'])

View File

@@ -24,7 +24,7 @@ class XEP_0048(BasePlugin):
name = 'xep_0048' name = 'xep_0048'
description = 'XEP-0048: Bookmarks' description = 'XEP-0048: Bookmarks'
dependencies = {'xep_0045', 'xep_0049', 'xep_0060', 'xep_0163', 'xep_0223'} dependencies = set(['xep_0045', 'xep_0049', 'xep_0060', 'xep_0163', 'xep_0223'])
stanza = stanza stanza = stanza
default_config = { default_config = {
'auto_join': False, 'auto_join': False,
@@ -59,7 +59,7 @@ class XEP_0048(BasePlugin):
for conf in bookmarks['conferences']: for conf in bookmarks['conferences']:
if conf['autojoin']: if conf['autojoin']:
log.debug('Auto joining %s as %s', conf['jid'], conf['nick']) log.debug('Auto joining %s as %s', conf['jid'], conf['nick'])
self.xmpp['xep_0045'].join_muc(conf['jid'], conf['nick'], self.xmpp['xep_0045'].joinMUC(conf['jid'], conf['nick'],
password=conf['password']) password=conf['password'])
def set_bookmarks(self, bookmarks, method=None, **iqargs): def set_bookmarks(self, bookmarks, method=None, **iqargs):

View File

@@ -40,8 +40,8 @@ class Conference(ElementBase):
namespace = 'storage:bookmarks' namespace = 'storage:bookmarks'
plugin_attrib = 'conference' plugin_attrib = 'conference'
plugin_multi_attrib = 'conferences' plugin_multi_attrib = 'conferences'
interfaces = {'nick', 'password', 'autojoin', 'jid', 'name'} interfaces = set(['nick', 'password', 'autojoin', 'jid', 'name'])
sub_interfaces = {'nick', 'password'} sub_interfaces = set(['nick', 'password'])
def get_autojoin(self): def get_autojoin(self):
value = self._get_attr('autojoin') value = self._get_attr('autojoin')
@@ -58,7 +58,7 @@ class URL(ElementBase):
namespace = 'storage:bookmarks' namespace = 'storage:bookmarks'
plugin_attrib = 'url' plugin_attrib = 'url'
plugin_multi_attrib = 'urls' plugin_multi_attrib = 'urls'
interfaces = {'url', 'name'} interfaces = set(['url', 'name'])
register_stanza_plugin(Bookmarks, Conference, iterable=True) register_stanza_plugin(Bookmarks, Conference, iterable=True)

View File

@@ -23,7 +23,7 @@ class XEP_0049(BasePlugin):
name = 'xep_0049' name = 'xep_0049'
description = 'XEP-0049: Private XML Storage' description = 'XEP-0049: Private XML Storage'
dependencies = {} dependencies = set([])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0050.adhoc import XEP_0050
register_plugin(XEP_0050) register_plugin(XEP_0050)
# Retain some backwards compatibility
xep_0050 = XEP_0050

View File

@@ -74,7 +74,7 @@ class XEP_0050(BasePlugin):
name = 'xep_0050' name = 'xep_0050'
description = 'XEP-0050: Ad-Hoc Commands' description = 'XEP-0050: Ad-Hoc Commands'
dependencies = {'xep_0030', 'xep_0004'} dependencies = set(['xep_0030', 'xep_0004'])
stanza = stanza stanza = stanza
default_config = { default_config = {
'session_db': None 'session_db': None
@@ -225,8 +225,8 @@ class XEP_0050(BasePlugin):
if len(payload) == 1: if len(payload) == 1:
payload = payload[0] payload = payload[0]
interfaces = {item.plugin_attrib for item in payload} interfaces = set([item.plugin_attrib for item in payload])
payload_classes = {item.__class__ for item in payload} payload_classes = set([item.__class__ for item in payload])
initial_session = {'id': sessionid, initial_session = {'id': sessionid,
'from': iq['from'], 'from': iq['from'],
@@ -322,8 +322,8 @@ class XEP_0050(BasePlugin):
interfaces = session.get('interfaces', set()) interfaces = session.get('interfaces', set())
payload_classes = session.get('payload_classes', set()) payload_classes = session.get('payload_classes', set())
interfaces.update({item.plugin_attrib for item in payload}) interfaces.update(set([item.plugin_attrib for item in payload]))
payload_classes.update({item.__class__ for item in payload}) payload_classes.update(set([item.__class__ for item in payload]))
session['interfaces'] = interfaces session['interfaces'] = interfaces
session['payload_classes'] = payload_classes session['payload_classes'] = payload_classes

View File

@@ -72,11 +72,11 @@ class Command(ElementBase):
name = 'command' name = 'command'
namespace = 'http://jabber.org/protocol/commands' namespace = 'http://jabber.org/protocol/commands'
plugin_attrib = 'command' plugin_attrib = 'command'
interfaces = {'action', 'sessionid', 'node', interfaces = set(('action', 'sessionid', 'node',
'status', 'actions', 'notes'} 'status', 'actions', 'notes'))
actions = {'cancel', 'complete', 'execute', 'next', 'prev'} actions = set(('cancel', 'complete', 'execute', 'next', 'prev'))
statuses = {'canceled', 'completed', 'executing'} statuses = set(('canceled', 'completed', 'executing'))
next_actions = {'prev', 'next', 'complete'} next_actions = set(('prev', 'next', 'complete'))
def get_action(self): def get_action(self):
""" """
@@ -100,7 +100,7 @@ class Command(ElementBase):
self.del_actions() self.del_actions()
if values: if values:
self._set_sub_text('{%s}actions' % self.namespace, '', True) self._set_sub_text('{%s}actions' % self.namespace, '', True)
actions = self.xml.find('{%s}actions' % self.namespace) actions = self.find('{%s}actions' % self.namespace)
for val in values: for val in values:
if val in self.next_actions: if val in self.next_actions:
action = ET.Element('{%s}%s' % (self.namespace, val)) action = ET.Element('{%s}%s' % (self.namespace, val))
@@ -111,7 +111,7 @@ class Command(ElementBase):
Return the set of allowable next actions. Return the set of allowable next actions.
""" """
actions = set() actions = set()
actions_xml = self.xml.find('{%s}actions' % self.namespace) actions_xml = self.find('{%s}actions' % self.namespace)
if actions_xml is not None: if actions_xml is not None:
for action in self.next_actions: for action in self.next_actions:
action_xml = actions_xml.find('{%s}%s' % (self.namespace, action_xml = actions_xml.find('{%s}%s' % (self.namespace,
@@ -136,7 +136,7 @@ class Command(ElementBase):
('error', 'The command ran, but had errors')] ('error', 'The command ran, but had errors')]
""" """
notes = [] notes = []
notes_xml = self.xml.findall('{%s}note' % self.namespace) notes_xml = self.findall('{%s}note' % self.namespace)
for note in notes_xml: for note in notes_xml:
notes.append((note.attrib.get('type', 'info'), notes.append((note.attrib.get('type', 'info'),
note.text)) note.text))
@@ -167,7 +167,7 @@ class Command(ElementBase):
""" """
Remove all notes associated with the command result. Remove all notes associated with the command result.
""" """
notes_xml = self.xml.findall('{%s}note' % self.namespace) notes_xml = self.findall('{%s}note' % self.namespace)
for note in notes_xml: for note in notes_xml:
self.xml.remove(note) self.xml.remove(note)

View File

@@ -10,15 +10,15 @@ class VCardTemp(ElementBase):
name = 'vCard' name = 'vCard'
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = 'vcard_temp' plugin_attrib = 'vcard_temp'
interfaces = {'FN', 'VERSION'} interfaces = set(['FN', 'VERSION'])
sub_interfaces = {'FN', 'VERSION'} sub_interfaces = set(['FN', 'VERSION'])
class Name(ElementBase): class Name(ElementBase):
name = 'N' name = 'N'
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
interfaces = {'FAMILY', 'GIVEN', 'MIDDLE', 'PREFIX', 'SUFFIX'} interfaces = set(['FAMILY', 'GIVEN', 'MIDDLE', 'PREFIX', 'SUFFIX'])
sub_interfaces = interfaces sub_interfaces = interfaces
def _set_component(self, name, value): def _set_component(self, name, value):
@@ -72,7 +72,7 @@ class Nickname(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'nicknames' plugin_multi_attrib = 'nicknames'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_nickname(self, value): def set_nickname(self, value):
@@ -95,9 +95,9 @@ class Email(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'emails' plugin_multi_attrib = 'emails'
interfaces = {'HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID'} interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID'])
sub_interfaces = {'USERID'} sub_interfaces = set(['USERID'])
bool_interfaces = {'HOME', 'WORK', 'INTERNET', 'PREF', 'X400'} bool_interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400'])
class Address(ElementBase): class Address(ElementBase):
@@ -105,12 +105,12 @@ class Address(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'addresses' plugin_multi_attrib = 'addresses'
interfaces = {'HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL', interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL',
'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY', 'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY',
'REGION', 'PCODE', 'CTRY'} 'REGION', 'PCODE', 'CTRY'])
sub_interfaces = {'POBOX', 'EXTADD', 'STREET', 'LOCALITY', sub_interfaces = set(['POBOX', 'EXTADD', 'STREET', 'LOCALITY',
'REGION', 'PCODE', 'CTRY'} 'REGION', 'PCODE', 'CTRY'])
bool_interfaces = {'HOME', 'WORK', 'DOM', 'INTL', 'PREF'} bool_interfaces = set(['HOME', 'WORK', 'DOM', 'INTL', 'PREF'])
class Telephone(ElementBase): class Telephone(ElementBase):
@@ -118,16 +118,16 @@ class Telephone(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'telephone_numbers' plugin_multi_attrib = 'telephone_numbers'
interfaces = {'HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG', interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG',
'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS', 'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS',
'PREF', 'NUMBER'} 'PREF', 'NUMBER'])
sub_interfaces = {'NUMBER'} sub_interfaces = set(['NUMBER'])
bool_interfaces = {'HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', bool_interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER',
'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM', 'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM',
'ISDN', 'PCS', 'PREF'} 'ISDN', 'PCS', 'PREF'])
def setup(self, xml=None): def setup(self, xml=None):
super().setup(xml=xml) super(Telephone, self).setup(xml=xml)
## this blanks out numbers received from server ## this blanks out numbers received from server
##self._set_sub_text('NUMBER', '', keep=True) ##self._set_sub_text('NUMBER', '', keep=True)
@@ -143,10 +143,10 @@ class Label(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'labels' plugin_multi_attrib = 'labels'
interfaces = {'HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT', interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT',
'PREF', 'lines'} 'PREF', 'lines'])
bool_interfaces = {'HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM',
'INT', 'PREF'} 'INT', 'PREF'])
def add_line(self, value): def add_line(self, value):
line = ET.Element('{%s}LINE' % self.namespace) line = ET.Element('{%s}LINE' % self.namespace)
@@ -177,7 +177,7 @@ class Geo(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'geolocations' plugin_multi_attrib = 'geolocations'
interfaces = {'LAT', 'LON'} interfaces = set(['LAT', 'LON'])
sub_interfaces = interfaces sub_interfaces = interfaces
@@ -186,8 +186,8 @@ class Org(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'organizations' plugin_multi_attrib = 'organizations'
interfaces = {'ORGNAME', 'ORGUNIT', 'orgunits'} interfaces = set(['ORGNAME', 'ORGUNIT', 'orgunits'])
sub_interfaces = {'ORGNAME', 'ORGUNIT'} sub_interfaces = set(['ORGNAME', 'ORGUNIT'])
def add_orgunit(self, value): def add_orgunit(self, value):
orgunit = ET.Element('{%s}ORGUNIT' % self.namespace) orgunit = ET.Element('{%s}ORGUNIT' % self.namespace)
@@ -218,7 +218,7 @@ class Photo(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'photos' plugin_multi_attrib = 'photos'
interfaces = {'TYPE', 'EXTVAL'} interfaces = set(['TYPE', 'EXTVAL'])
sub_interfaces = interfaces sub_interfaces = interfaces
@@ -227,7 +227,7 @@ class Logo(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'logos' plugin_multi_attrib = 'logos'
interfaces = {'TYPE', 'EXTVAL'} interfaces = set(['TYPE', 'EXTVAL'])
sub_interfaces = interfaces sub_interfaces = interfaces
@@ -236,7 +236,7 @@ class Sound(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'sounds' plugin_multi_attrib = 'sounds'
interfaces = {'PHONETC', 'EXTVAL'} interfaces = set(['PHONETC', 'EXTVAL'])
sub_interfaces = interfaces sub_interfaces = interfaces
@@ -244,7 +244,7 @@ class BinVal(ElementBase):
name = 'BINVAL' name = 'BINVAL'
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
interfaces = {'BINVAL'} interfaces = set(['BINVAL'])
is_extension = True is_extension = True
def setup(self, xml=None): def setup(self, xml=None):
@@ -275,7 +275,7 @@ class Classification(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'classifications' plugin_multi_attrib = 'classifications'
interfaces = {'PUBLIC', 'PRIVATE', 'CONFIDENTIAL'} interfaces = set(['PUBLIC', 'PRIVATE', 'CONFIDENTIAL'])
bool_interfaces = interfaces bool_interfaces = interfaces
@@ -284,7 +284,7 @@ class Categories(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'categories' plugin_multi_attrib = 'categories'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_categories(self, values): def set_categories(self, values):
@@ -314,7 +314,7 @@ class Birthday(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'birthdays' plugin_multi_attrib = 'birthdays'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_bday(self, value): def set_bday(self, value):
@@ -336,7 +336,7 @@ class Rev(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'revision_dates' plugin_multi_attrib = 'revision_dates'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_rev(self, value): def set_rev(self, value):
@@ -358,7 +358,7 @@ class Title(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'titles' plugin_multi_attrib = 'titles'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_title(self, value): def set_title(self, value):
@@ -373,7 +373,7 @@ class Role(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'roles' plugin_multi_attrib = 'roles'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_role(self, value): def set_role(self, value):
@@ -388,7 +388,7 @@ class Note(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'notes' plugin_multi_attrib = 'notes'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_note(self, value): def set_note(self, value):
@@ -403,7 +403,7 @@ class Desc(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'descriptions' plugin_multi_attrib = 'descriptions'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_desc(self, value): def set_desc(self, value):
@@ -418,7 +418,7 @@ class URL(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'urls' plugin_multi_attrib = 'urls'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_url(self, value): def set_url(self, value):
@@ -433,7 +433,7 @@ class UID(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'uids' plugin_multi_attrib = 'uids'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_uid(self, value): def set_uid(self, value):
@@ -448,7 +448,7 @@ class ProdID(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'product_ids' plugin_multi_attrib = 'product_ids'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_prodid(self, value): def set_prodid(self, value):
@@ -463,7 +463,7 @@ class Mailer(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'mailers' plugin_multi_attrib = 'mailers'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_mailer(self, value): def set_mailer(self, value):
@@ -478,7 +478,7 @@ class SortString(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = 'SORT_STRING' plugin_attrib = 'SORT_STRING'
plugin_multi_attrib = 'sort_strings' plugin_multi_attrib = 'sort_strings'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_sort_string(self, value): def set_sort_string(self, value):
@@ -493,7 +493,7 @@ class Agent(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'agents' plugin_multi_attrib = 'agents'
interfaces = {'EXTVAL'} interfaces = set(['EXTVAL'])
sub_interfaces = interfaces sub_interfaces = interfaces
@@ -502,7 +502,7 @@ class JabberID(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'jids' plugin_multi_attrib = 'jids'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_jabberid(self, value): def set_jabberid(self, value):
@@ -517,7 +517,7 @@ class TimeZone(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'timezones' plugin_multi_attrib = 'timezones'
interfaces = {name} interfaces = set([name])
is_extension = True is_extension = True
def set_tz(self, value): def set_tz(self, value):

View File

@@ -29,7 +29,7 @@ class XEP_0054(BasePlugin):
name = 'xep_0054' name = 'xep_0054'
description = 'XEP-0054: vcard-temp' description = 'XEP-0054: vcard-temp'
dependencies = {'xep_0030', 'xep_0082'} dependencies = set(['xep_0030', 'xep_0082'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -13,3 +13,6 @@ from slixmpp.plugins.xep_0059.rsm import ResultIterator, XEP_0059
register_plugin(XEP_0059) register_plugin(XEP_0059)
# Retain some backwards compatibility
xep_0059 = XEP_0059

View File

@@ -111,7 +111,7 @@ class XEP_0059(BasePlugin):
name = 'xep_0059' name = 'xep_0059'
description = 'XEP-0059: Result Set Management' description = 'XEP-0059: Result Set Management'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -64,13 +64,13 @@ class Set(ElementBase):
namespace = 'http://jabber.org/protocol/rsm' namespace = 'http://jabber.org/protocol/rsm'
name = 'set' name = 'set'
plugin_attrib = 'rsm' plugin_attrib = 'rsm'
sub_interfaces = {'first', 'after', 'before', 'count', sub_interfaces = set(('first', 'after', 'before', 'count',
'index', 'last', 'max'} 'index', 'last', 'max'))
interfaces = {'first_index', 'first', 'after', 'before', interfaces = set(('first_index', 'first', 'after', 'before',
'count', 'index', 'last', 'max'} 'count', 'index', 'last', 'max'))
def set_first_index(self, val): def set_first_index(self, val):
fi = self.xml.find("{%s}first" % (self.namespace)) fi = self.find("{%s}first" % (self.namespace))
if fi is not None: if fi is not None:
if val: if val:
fi.attrib['index'] = val fi.attrib['index'] = val
@@ -82,7 +82,7 @@ class Set(ElementBase):
self.xml.append(fi) self.xml.append(fi)
def get_first_index(self): def get_first_index(self):
fi = self.xml.find("{%s}first" % (self.namespace)) fi = self.find("{%s}first" % (self.namespace))
if fi is not None: if fi is not None:
return fi.attrib.get('index', '') return fi.attrib.get('index', '')

View File

@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0060 import stanza
register_plugin(XEP_0060) register_plugin(XEP_0060)
# Retain some backwards compatibility
xep_0060 = XEP_0060

View File

@@ -26,7 +26,7 @@ class XEP_0060(BasePlugin):
name = 'xep_0060' name = 'xep_0060'
description = 'XEP-0060: Publish-Subscribe' description = 'XEP-0060: Publish-Subscribe'
dependencies = {'xep_0030', 'xep_0004', 'xep_0082', 'xep_0131'} dependencies = set(['xep_0030', 'xep_0004', 'xep_0082', 'xep_0131'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -11,7 +11,7 @@ from slixmpp.xmlstream import ET
class OptionalSetting(object): class OptionalSetting(object):
interfaces = {'required'} interfaces = set(('required',))
def set_required(self, value): def set_required(self, value):
if value in (True, 'true', 'True', '1'): if value in (True, 'true', 'True', '1'):

View File

@@ -23,14 +23,14 @@ class Affiliations(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'affiliations' name = 'affiliations'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class Affiliation(ElementBase): class Affiliation(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'affiliation' name = 'affiliation'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'affiliation', 'jid'} interfaces = set(('node', 'affiliation', 'jid'))
def set_jid(self, value): def set_jid(self, value):
self._set_attr('jid', str(value)) self._set_attr('jid', str(value))
@@ -43,7 +43,7 @@ class Subscription(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'subscription' name = 'subscription'
plugin_attrib = name plugin_attrib = name
interfaces = {'jid', 'node', 'subscription', 'subid'} interfaces = set(('jid', 'node', 'subscription', 'subid'))
def set_jid(self, value): def set_jid(self, value):
self._set_attr('jid', str(value)) self._set_attr('jid', str(value))
@@ -56,21 +56,21 @@ class Subscriptions(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'subscriptions' name = 'subscriptions'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class SubscribeOptions(ElementBase, OptionalSetting): class SubscribeOptions(ElementBase, OptionalSetting):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'subscribe-options' name = 'subscribe-options'
plugin_attrib = 'suboptions' plugin_attrib = 'suboptions'
interfaces = {'required'} interfaces = set(('required',))
class Item(ElementBase): class Item(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'item' name = 'item'
plugin_attrib = name plugin_attrib = name
interfaces = {'id', 'payload'} interfaces = set(('id', 'payload'))
def set_payload(self, value): def set_payload(self, value):
del self['payload'] del self['payload']
@@ -95,7 +95,7 @@ class Items(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'items' name = 'items'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'max_items'} interfaces = set(('node', 'max_items'))
def set_max_items(self, value): def set_max_items(self, value):
self._set_attr('max_items', str(value)) self._set_attr('max_items', str(value))
@@ -105,14 +105,14 @@ class Create(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'create' name = 'create'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class Default(ElementBase): class Default(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'default' name = 'default'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'type'} interfaces = set(('node', 'type'))
def get_type(self): def get_type(self):
t = self._get_attr('type') t = self._get_attr('type')
@@ -125,14 +125,14 @@ class Publish(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'publish' name = 'publish'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class Retract(ElementBase): class Retract(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'retract' name = 'retract'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'notify'} interfaces = set(('node', 'notify'))
def get_notify(self): def get_notify(self):
notify = self._get_attr('notify') notify = self._get_attr('notify')
@@ -156,7 +156,7 @@ class Unsubscribe(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'unsubscribe' name = 'unsubscribe'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'jid', 'subid'} interfaces = set(('node', 'jid', 'subid'))
def set_jid(self, value): def set_jid(self, value):
self._set_attr('jid', str(value)) self._set_attr('jid', str(value))
@@ -169,7 +169,7 @@ class Subscribe(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'subscribe' name = 'subscribe'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'jid'} interfaces = set(('node', 'jid'))
def set_jid(self, value): def set_jid(self, value):
self._set_attr('jid', str(value)) self._set_attr('jid', str(value))
@@ -182,7 +182,7 @@ class Configure(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'configure' name = 'configure'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'type'} interfaces = set(('node', 'type'))
def getType(self): def getType(self):
t = self._get_attr('type') t = self._get_attr('type')
@@ -195,7 +195,7 @@ class Options(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'options' name = 'options'
plugin_attrib = name plugin_attrib = name
interfaces = {'jid', 'node', 'options'} interfaces = set(('jid', 'node', 'options'))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
ElementBase.__init__(self, *args, **kwargs) ElementBase.__init__(self, *args, **kwargs)
@@ -206,10 +206,7 @@ class Options(ElementBase):
return form return form
def set_options(self, value): def set_options(self, value):
if isinstance(value, ElementBase): self.xml.append(value.getXML())
self.xml.append(value.xml)
else:
self.xml.append(value)
return self return self
def del_options(self): def del_options(self):
@@ -227,7 +224,7 @@ class PublishOptions(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub' namespace = 'http://jabber.org/protocol/pubsub'
name = 'publish-options' name = 'publish-options'
plugin_attrib = 'publish_options' plugin_attrib = 'publish_options'
interfaces = {'publish_options'} interfaces = set(('publish_options',))
is_extension = True is_extension = True
def get_publish_options(self): def get_publish_options(self):
@@ -241,10 +238,7 @@ class PublishOptions(ElementBase):
if value is None: if value is None:
self.del_publish_options() self.del_publish_options()
else: else:
if isinstance(value, ElementBase): self.xml.append(value.getXML())
self.xml.append(value.xml)
else:
self.xml.append(value)
return self return self
def del_publish_options(self): def del_publish_options(self):

View File

@@ -13,18 +13,18 @@ from slixmpp.xmlstream import ElementBase, ET, register_stanza_plugin
class PubsubErrorCondition(ElementBase): class PubsubErrorCondition(ElementBase):
plugin_attrib = 'pubsub' plugin_attrib = 'pubsub'
interfaces = {'condition', 'unsupported'} interfaces = set(('condition', 'unsupported'))
plugin_attrib_map = {} plugin_attrib_map = {}
plugin_tag_map = {} plugin_tag_map = {}
conditions = {'closed-node', 'configuration-required', 'invalid-jid', conditions = set(('closed-node', 'configuration-required', 'invalid-jid',
'invalid-options', 'invalid-payload', 'invalid-subid', 'invalid-options', 'invalid-payload', 'invalid-subid',
'item-forbidden', 'item-required', 'jid-required', 'item-forbidden', 'item-required', 'jid-required',
'max-items-exceeded', 'max-nodes-exceeded', 'max-items-exceeded', 'max-nodes-exceeded',
'nodeid-required', 'not-in-roster-group', 'nodeid-required', 'not-in-roster-group',
'not-subscribed', 'payload-too-big', 'not-subscribed', 'payload-too-big',
'payload-required', 'pending-subscription', 'payload-required', 'pending-subscription',
'presence-subscription-required', 'subid-required', 'presence-subscription-required', 'subid-required',
'too-many-subscriptions', 'unsupported'} 'too-many-subscriptions', 'unsupported'))
condition_ns = 'http://jabber.org/protocol/pubsub#errors' condition_ns = 'http://jabber.org/protocol/pubsub#errors'
def setup(self, xml): def setup(self, xml):

View File

@@ -25,7 +25,7 @@ class EventItem(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'item' name = 'item'
plugin_attrib = name plugin_attrib = name
interfaces = {'id', 'payload', 'node', 'publisher'} interfaces = set(('id', 'payload', 'node', 'publisher'))
def set_payload(self, value): def set_payload(self, value):
self.xml.append(value) self.xml.append(value)
@@ -44,56 +44,56 @@ class EventRetract(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'retract' name = 'retract'
plugin_attrib = name plugin_attrib = name
interfaces = {'id'} interfaces = set(('id',))
class EventItems(ElementBase): class EventItems(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'items' name = 'items'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class EventCollection(ElementBase): class EventCollection(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'collection' name = 'collection'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class EventAssociate(ElementBase): class EventAssociate(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'associate' name = 'associate'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class EventDisassociate(ElementBase): class EventDisassociate(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'disassociate' name = 'disassociate'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class EventConfiguration(ElementBase): class EventConfiguration(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'configuration' name = 'configuration'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class EventPurge(ElementBase): class EventPurge(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'purge' name = 'purge'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class EventDelete(ElementBase): class EventDelete(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'delete' name = 'delete'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'redirect'} interfaces = set(('node', 'redirect'))
def set_redirect(self, uri): def set_redirect(self, uri):
del self['redirect'] del self['redirect']
@@ -117,7 +117,7 @@ class EventSubscription(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#event' namespace = 'http://jabber.org/protocol/pubsub#event'
name = 'subscription' name = 'subscription'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'expiry', 'jid', 'subid', 'subscription'} interfaces = set(('node', 'expiry', 'jid', 'subid', 'subscription'))
def get_expiry(self): def get_expiry(self):
expiry = self._get_attr('expiry') expiry = self._get_attr('expiry')

View File

@@ -25,7 +25,7 @@ class DefaultConfig(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
name = 'default' name = 'default'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'config'} interfaces = set(('node', 'config'))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
ElementBase.__init__(self, *args, **kwargs) ElementBase.__init__(self, *args, **kwargs)
@@ -41,7 +41,7 @@ class DefaultConfig(ElementBase):
class OwnerAffiliations(Affiliations): class OwnerAffiliations(Affiliations):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
interfaces = {'node'} interfaces = set(('node',))
def append(self, affiliation): def append(self, affiliation):
if not isinstance(affiliation, OwnerAffiliation): if not isinstance(affiliation, OwnerAffiliation):
@@ -51,40 +51,40 @@ class OwnerAffiliations(Affiliations):
class OwnerAffiliation(Affiliation): class OwnerAffiliation(Affiliation):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
interfaces = {'affiliation', 'jid'} interfaces = set(('affiliation', 'jid'))
class OwnerConfigure(Configure): class OwnerConfigure(Configure):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
name = 'configure' name = 'configure'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class OwnerDefault(OwnerConfigure): class OwnerDefault(OwnerConfigure):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
interfaces = {'node'} interfaces = set(('node',))
class OwnerDelete(ElementBase, OptionalSetting): class OwnerDelete(ElementBase, OptionalSetting):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
name = 'delete' name = 'delete'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class OwnerPurge(ElementBase, OptionalSetting): class OwnerPurge(ElementBase, OptionalSetting):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
name = 'purge' name = 'purge'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
class OwnerRedirect(ElementBase): class OwnerRedirect(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
name = 'redirect' name = 'redirect'
plugin_attrib = name plugin_attrib = name
interfaces = {'node', 'jid'} interfaces = set(('node', 'jid'))
def set_jid(self, value): def set_jid(self, value):
self._set_attr('jid', str(value)) self._set_attr('jid', str(value))
@@ -97,7 +97,7 @@ class OwnerSubscriptions(Subscriptions):
name = 'subscriptions' name = 'subscriptions'
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
plugin_attrib = name plugin_attrib = name
interfaces = {'node'} interfaces = set(('node',))
def append(self, subscription): def append(self, subscription):
if not isinstance(subscription, OwnerSubscription): if not isinstance(subscription, OwnerSubscription):
@@ -109,7 +109,7 @@ class OwnerSubscription(ElementBase):
namespace = 'http://jabber.org/protocol/pubsub#owner' namespace = 'http://jabber.org/protocol/pubsub#owner'
name = 'subscription' name = 'subscription'
plugin_attrib = name plugin_attrib = name
interfaces = {'jid', 'subscription'} interfaces = set(('jid', 'subscription'))
def set_jid(self, value): def set_jid(self, value):
self._set_attr('jid', str(value)) self._set_attr('jid', str(value))

View File

@@ -22,7 +22,7 @@ class XEP_0065(BasePlugin):
name = 'xep_0065' name = 'xep_0065'
description = "XEP-0065: SOCKS5 Bytestreams" description = "XEP-0065: SOCKS5 Bytestreams"
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
default_config = { default_config = {
'auto_accept': False 'auto_accept': False
} }

View File

@@ -6,8 +6,8 @@ class Socks5(ElementBase):
name = 'query' name = 'query'
namespace = 'http://jabber.org/protocol/bytestreams' namespace = 'http://jabber.org/protocol/bytestreams'
plugin_attrib = 'socks' plugin_attrib = 'socks'
interfaces = {'sid', 'activate'} interfaces = set(['sid', 'activate'])
sub_interfaces = {'activate'} sub_interfaces = set(['activate'])
def add_streamhost(self, jid, host, port): def add_streamhost(self, jid, host, port):
sh = StreamHost(parent=self) sh = StreamHost(parent=self)
@@ -21,7 +21,7 @@ class StreamHost(ElementBase):
namespace = 'http://jabber.org/protocol/bytestreams' namespace = 'http://jabber.org/protocol/bytestreams'
plugin_attrib = 'streamhost' plugin_attrib = 'streamhost'
plugin_multi_attrib = 'streamhosts' plugin_multi_attrib = 'streamhosts'
interfaces = {'host', 'jid', 'port'} interfaces = set(['host', 'jid', 'port'])
def set_jid(self, value): def set_jid(self, value):
return self._set_attr('jid', str(value)) return self._set_attr('jid', str(value))
@@ -34,7 +34,7 @@ class StreamHostUsed(ElementBase):
name = 'streamhost-used' name = 'streamhost-used'
namespace = 'http://jabber.org/protocol/bytestreams' namespace = 'http://jabber.org/protocol/bytestreams'
plugin_attrib = 'streamhost_used' plugin_attrib = 'streamhost_used'
interfaces = {'jid'} interfaces = set(['jid'])
def set_jid(self, value): def set_jid(self, value):
return self._set_attr('jid', str(value)) return self._set_attr('jid', str(value))

View File

@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0066.oob import XEP_0066
register_plugin(XEP_0066) register_plugin(XEP_0066)
# Retain some backwards compatibility
xep_0066 = XEP_0066

View File

@@ -44,7 +44,7 @@ class XEP_0066(BasePlugin):
name = 'xep_0066' name = 'xep_0066'
description = 'XEP-0066: Out of Band Data' description = 'XEP-0066: Out of Band Data'
dependencies = {'xep_0030'} dependencies = set(['xep_0030'])
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):

View File

@@ -17,8 +17,8 @@ class OOBTransfer(ElementBase):
name = 'query' name = 'query'
namespace = 'jabber:iq:oob' namespace = 'jabber:iq:oob'
plugin_attrib = 'oob_transfer' plugin_attrib = 'oob_transfer'
interfaces = {'url', 'desc', 'sid'} interfaces = set(('url', 'desc', 'sid'))
sub_interfaces = {'url', 'desc'} sub_interfaces = set(('url', 'desc'))
class OOB(ElementBase): class OOB(ElementBase):
@@ -29,5 +29,5 @@ class OOB(ElementBase):
name = 'x' name = 'x'
namespace = 'jabber:x:oob' namespace = 'jabber:x:oob'
plugin_attrib = 'oob' plugin_attrib = 'oob'
interfaces = {'url', 'desc'} interfaces = set(('url', 'desc'))
sub_interfaces = interfaces sub_interfaces = interfaces

View File

@@ -1,15 +0,0 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2015 Emmanuel Gil Peyrot
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from slixmpp.plugins.base import register_plugin
from slixmpp.plugins.xep_0070.stanza import Confirm
from slixmpp.plugins.xep_0070.confirm import XEP_0070
register_plugin(XEP_0070)

View File

@@ -1,86 +0,0 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2015 Emmanuel Gil Peyrot
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import asyncio
import logging
from uuid import uuid4
from slixmpp.plugins import BasePlugin, register_plugin
from slixmpp import future_wrapper, Iq, Message
from slixmpp.exceptions import XMPPError, IqError, IqTimeout
from slixmpp.jid import JID
from slixmpp.xmlstream import JID, register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins.xep_0070 import stanza, Confirm
log = logging.getLogger(__name__)
class XEP_0070(BasePlugin):
"""
XEP-0070 Verifying HTTP Requests via XMPP
"""
name = 'xep_0070'
description = 'XEP-0070: Verifying HTTP Requests via XMPP'
dependencies = {'xep_0030'}
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, Confirm)
register_stanza_plugin(Message, Confirm)
self.xmpp.register_handler(
Callback('Confirm',
StanzaPath('iq@type=get/confirm'),
self._handle_iq_confirm))
self.xmpp.register_handler(
Callback('Confirm',
StanzaPath('message/confirm'),
self._handle_message_confirm))
def plugin_end(self):
self.xmpp.remove_handler('Confirm')
self.xmpp['xep_0030'].del_feature(feature='http://jabber.org/protocol/http-auth')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('http://jabber.org/protocol/http-auth')
@future_wrapper
def ask_confirm(self, jid, id, url, method, *, ifrom=None, message=None):
jid = JID(jid)
if jid.resource:
stanza = self.xmpp.Iq()
stanza['type'] = 'get'
else:
stanza = self.xmpp.Message()
stanza['thread'] = uuid4().hex
stanza['from'] = ifrom
stanza['to'] = jid
stanza['confirm']['id'] = id
stanza['confirm']['url'] = url
stanza['confirm']['method'] = method
if not jid.resource:
if message is not None:
stanza['body'] = message.format(id=id, url=url, method=method)
stanza.send()
return stanza
else:
return stanza.send()
def _handle_iq_confirm(self, iq):
self.xmpp.event('http_confirm_iq', iq)
self.xmpp.event('http_confirm', iq)
def _handle_message_confirm(self, message):
self.xmpp.event('http_confirm_message', message)
self.xmpp.event('http_confirm', message)

View File

@@ -1,17 +0,0 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2015 Emmanuel Gil Peyrot
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from slixmpp.xmlstream import ElementBase
class Confirm(ElementBase):
name = 'confirm'
namespace = 'http://jabber.org/protocol/http-auth'
plugin_attrib = 'confirm'
interfaces = {'id', 'url', 'method'}

Some files were not shown because too many files have changed in this diff Show More