Compare commits
1 Commits
disco
...
sleek-merg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4512248901 |
@@ -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 Slixmpp’s 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.
|
||||
17
README.rst
17
README.rst
@@ -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
|
||||
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 can be found both inline in the code, and as a Sphinx project in ``/docs``.
|
||||
@@ -102,12 +93,8 @@ Slixmpp projects::
|
||||
Slixmpp Credits
|
||||
---------------
|
||||
|
||||
**Maintainers:**
|
||||
- Florent Le Coz (`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>`_)
|
||||
**Maintainer of the slixmpp fork:** Florent Le Coz
|
||||
`louiz@louiz.org <xmpp:louiz@louiz.org?message>`_,
|
||||
|
||||
Credits (SleekXMPP)
|
||||
-------------------
|
||||
|
||||
@@ -48,9 +48,9 @@ copyright = u'2011, Nathan Fritz, Lance Stout'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.1'
|
||||
version = '1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.1'
|
||||
release = '1.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -259,8 +259,8 @@ Event Index
|
||||
|
||||
Signal that a connection to the XMPP server has been lost and the current
|
||||
stream session has ended. Currently equivalent to :term:`disconnected`, but
|
||||
implementations of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
|
||||
distinguish between the two events.
|
||||
future implementation of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
|
||||
will distinguish the two events.
|
||||
|
||||
Plugins that maintain session-based state should clear themselves when
|
||||
this event is fired.
|
||||
|
||||
@@ -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
|
||||
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::
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ operation using these stanzas without doing any complex operations such as
|
||||
checking an ACL, etc.
|
||||
|
||||
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.
|
||||
|
||||
Creating a Node Handler
|
||||
@@ -162,7 +162,7 @@ item itself, and the JID and node that will own the item.
|
||||
parameters ``ijid`` and ``node``.
|
||||
|
||||
Performing Disco Queries
|
||||
------------------------
|
||||
-----------------------
|
||||
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
|
||||
sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()``
|
||||
|
||||
@@ -68,7 +68,7 @@ class CommandBot(slixmpp.ClientXMPP):
|
||||
session. Additional, custom data may be saved
|
||||
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.addField(var='greeting',
|
||||
ftype='text-single',
|
||||
|
||||
@@ -94,7 +94,7 @@ class CommandUserBot(slixmpp.ClientXMPP):
|
||||
# label="Your greeting" />
|
||||
# </x>
|
||||
|
||||
form = self['xep_0004'].make_form(ftype='submit')
|
||||
form = self['xep_0004'].makeForm(ftype='submit')
|
||||
form.addField(var='greeting',
|
||||
value=session['greeting'])
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -7,8 +7,7 @@
|
||||
"""
|
||||
|
||||
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
|
||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
:license: MIT, see LICENSE for more details
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from slixmpp import plugins, roster, stanza
|
||||
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.roster import Roster
|
||||
from slixmpp.stanza.nick import Nick
|
||||
|
||||
from slixmpp.xmlstream import XMLStream, JID
|
||||
from slixmpp.xmlstream import ET, register_stanza_plugin
|
||||
@@ -69,7 +70,7 @@ class BaseXMPP(XMLStream):
|
||||
#: redirections that will be followed before quitting.
|
||||
self.max_redirects = 5
|
||||
|
||||
self.session_bind_event = asyncio.Event()
|
||||
self.session_bind_event = threading.Event()
|
||||
|
||||
#: A dictionary mapping plugin names to plugins.
|
||||
self.plugin = PluginManager(self)
|
||||
@@ -193,6 +194,7 @@ class BaseXMPP(XMLStream):
|
||||
|
||||
# Initialize a few default stanza plugins.
|
||||
register_stanza_plugin(Iq, Roster)
|
||||
register_stanza_plugin(Message, Nick)
|
||||
|
||||
def start_stream_handler(self, xml):
|
||||
"""Save the stream ID once the streams have been established.
|
||||
@@ -685,6 +687,7 @@ class BaseXMPP(XMLStream):
|
||||
self.address = (host, port)
|
||||
self.default_domain = host
|
||||
self.dns_records = None
|
||||
self.reconnect_delay = None
|
||||
self.reconnect()
|
||||
|
||||
def _handle_message(self, msg):
|
||||
@@ -750,9 +753,6 @@ class BaseXMPP(XMLStream):
|
||||
|
||||
Update the roster with presence information.
|
||||
"""
|
||||
if self.roster[presence['from']].ignore_updates:
|
||||
return
|
||||
|
||||
if not self.is_component and not presence['to'].bare:
|
||||
presence['to'] = self.boundjid
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
:license: MIT, see LICENSE for more details
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from slixmpp.stanza import StreamFeatures
|
||||
@@ -20,7 +19,7 @@ from slixmpp.basexmpp import BaseXMPP
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp.xmlstream import XMLStream
|
||||
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.
|
||||
try:
|
||||
@@ -105,9 +104,9 @@ class ClientXMPP(BaseXMPP):
|
||||
self.register_stanza(StreamFeatures)
|
||||
|
||||
self.register_handler(
|
||||
CoroutineCallback('Stream Features',
|
||||
MatchXPath('{%s}features' % self.stream_ns),
|
||||
self._handle_stream_features))
|
||||
Callback('Stream Features',
|
||||
MatchXPath('{%s}features' % self.stream_ns),
|
||||
self._handle_stream_features))
|
||||
self.register_handler(
|
||||
Callback('Roster Update',
|
||||
StanzaPath('iq@type=set/roster'),
|
||||
@@ -250,7 +249,6 @@ class ClientXMPP(BaseXMPP):
|
||||
self.bindfail = False
|
||||
self.features = set()
|
||||
|
||||
@asyncio.coroutine
|
||||
def _handle_stream_features(self, features):
|
||||
"""Process the received stream features.
|
||||
|
||||
@@ -259,11 +257,7 @@ class ClientXMPP(BaseXMPP):
|
||||
for order, name in self._stream_feature_order:
|
||||
if name in features['features']:
|
||||
handler, restart = self._stream_feature_handlers[name]
|
||||
if asyncio.iscoroutinefunction(handler):
|
||||
result = yield from handler(features)
|
||||
else:
|
||||
result = handler(features)
|
||||
if result and restart:
|
||||
if handler(features) and restart:
|
||||
# Don't continue if the feature requires
|
||||
# restarting the XML stream.
|
||||
return True
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.features.feature_bind.stanza import Bind
|
||||
|
||||
|
||||
register_plugin(FeatureBind)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
feature_bind = FeatureBind
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from slixmpp.jid import JID
|
||||
@@ -35,7 +34,6 @@ class FeatureBind(BasePlugin):
|
||||
register_stanza_plugin(Iq, stanza.Bind)
|
||||
register_stanza_plugin(StreamFeatures, stanza.Bind)
|
||||
|
||||
@asyncio.coroutine
|
||||
def _handle_bind_resource(self, features):
|
||||
"""
|
||||
Handle requesting a specific resource.
|
||||
@@ -51,7 +49,7 @@ class FeatureBind(BasePlugin):
|
||||
if 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):
|
||||
self.xmpp.boundjid = JID(response['bind']['jid'])
|
||||
|
||||
@@ -16,3 +16,7 @@ from slixmpp.features.feature_mechanisms.stanza import Failure
|
||||
|
||||
|
||||
register_plugin(FeatureMechanisms)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
feature_mechanisms = FeatureMechanisms
|
||||
|
||||
@@ -29,7 +29,7 @@ class Mechanisms(ElementBase):
|
||||
"""
|
||||
"""
|
||||
results = []
|
||||
mechs = self.xml.findall('{%s}mechanism' % self.namespace)
|
||||
mechs = self.findall('{%s}mechanism' % self.namespace)
|
||||
if mechs:
|
||||
for mech in mechs:
|
||||
results.append(mech.text)
|
||||
@@ -47,7 +47,7 @@ class Mechanisms(ElementBase):
|
||||
def del_mechanisms(self):
|
||||
"""
|
||||
"""
|
||||
mechs = self.xml.findall('{%s}mechanism' % self.namespace)
|
||||
mechs = self.findall('{%s}mechanism' % self.namespace)
|
||||
if mechs:
|
||||
for mech in mechs:
|
||||
self.xml.remove(mech)
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.features.feature_rosterver.stanza import RosterVer
|
||||
|
||||
|
||||
register_plugin(FeatureRosterVer)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
feature_rosterver = FeatureRosterVer
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.features.feature_session.stanza import Session
|
||||
|
||||
|
||||
register_plugin(FeatureSession)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
feature_session = FeatureSession
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from slixmpp.stanza import Iq, StreamFeatures
|
||||
@@ -35,7 +34,6 @@ class FeatureSession(BasePlugin):
|
||||
register_stanza_plugin(Iq, stanza.Session)
|
||||
register_stanza_plugin(StreamFeatures, stanza.Session)
|
||||
|
||||
@asyncio.coroutine
|
||||
def _handle_start_session(self, features):
|
||||
"""
|
||||
Handle the start of the session.
|
||||
@@ -46,7 +44,7 @@ class FeatureSession(BasePlugin):
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'set'
|
||||
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):
|
||||
self.xmpp.features.add('session')
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.features.feature_starttls.stanza import *
|
||||
|
||||
|
||||
register_plugin(FeatureSTARTTLS)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
feature_starttls = FeatureSTARTTLS
|
||||
|
||||
@@ -208,15 +208,16 @@ def _format_jid(local=None, domain=None, resource=None):
|
||||
|
||||
:return: A full or bare JID string.
|
||||
"""
|
||||
if domain is None:
|
||||
return ''
|
||||
result = []
|
||||
if local is not None:
|
||||
result = local + '@' + domain
|
||||
else:
|
||||
result = domain
|
||||
result.append(local)
|
||||
result.append('@')
|
||||
if domain is not None:
|
||||
result.append(domain)
|
||||
if resource is not None:
|
||||
result += '/' + resource
|
||||
return result
|
||||
result.append('/')
|
||||
result.append(resource)
|
||||
return ''.join(result)
|
||||
|
||||
|
||||
class InvalidJID(ValueError):
|
||||
@@ -299,23 +300,19 @@ class JID:
|
||||
:raises InvalidJID:
|
||||
"""
|
||||
|
||||
__slots__ = ('_node', '_domain', '_resource', '_bare', '_full')
|
||||
__slots__ = ('_node', '_domain', '_resource')
|
||||
|
||||
def __init__(self, jid=None):
|
||||
if not jid:
|
||||
self._node = ''
|
||||
self._domain = ''
|
||||
self._resource = ''
|
||||
self._bare = ''
|
||||
self._full = ''
|
||||
return
|
||||
self._node = None
|
||||
self._domain = None
|
||||
self._resource = None
|
||||
elif not isinstance(jid, JID):
|
||||
self._node, self._domain, self._resource = _parse_jid(jid)
|
||||
else:
|
||||
self._node = jid._node
|
||||
self._domain = jid._domain
|
||||
self._resource = jid._resource
|
||||
self._update_bare_full()
|
||||
|
||||
def unescape(self):
|
||||
"""Return an unescaped JID object.
|
||||
@@ -332,94 +329,77 @@ class JID:
|
||||
self._domain,
|
||||
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
|
||||
def node(self):
|
||||
return self._node
|
||||
return self._node or ''
|
||||
|
||||
@property
|
||||
def user(self):
|
||||
return self._node
|
||||
return self._node or ''
|
||||
|
||||
@property
|
||||
def local(self):
|
||||
return self._node
|
||||
return self._node or ''
|
||||
|
||||
@property
|
||||
def username(self):
|
||||
return self._node
|
||||
return self._node or ''
|
||||
|
||||
@property
|
||||
def domain(self):
|
||||
return self._domain
|
||||
return self._domain or ''
|
||||
|
||||
@property
|
||||
def server(self):
|
||||
return self._domain
|
||||
return self._domain or ''
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
return self._domain
|
||||
return self._domain or ''
|
||||
|
||||
@property
|
||||
def resource(self):
|
||||
return self._resource
|
||||
return self._resource or ''
|
||||
|
||||
@property
|
||||
def bare(self):
|
||||
return self._bare
|
||||
return _format_jid(self._node, self._domain)
|
||||
|
||||
@property
|
||||
def full(self):
|
||||
return self._full
|
||||
return _format_jid(self._node, self._domain, self._resource)
|
||||
|
||||
@property
|
||||
def jid(self):
|
||||
return self._full
|
||||
return _format_jid(self._node, self._domain, self._resource)
|
||||
|
||||
@node.setter
|
||||
def node(self, value):
|
||||
self._node = _validate_node(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@user.setter
|
||||
def user(self, value):
|
||||
self._node = _validate_node(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@local.setter
|
||||
def local(self, value):
|
||||
self._node = _validate_node(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@username.setter
|
||||
def username(self, value):
|
||||
self._node = _validate_node(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@domain.setter
|
||||
def domain(self, value):
|
||||
self._domain = _validate_domain(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@server.setter
|
||||
def server(self, value):
|
||||
self._domain = _validate_domain(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@host.setter
|
||||
def host(self, value):
|
||||
self._domain = _validate_domain(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@bare.setter
|
||||
def bare(self, value):
|
||||
@@ -427,30 +407,26 @@ class JID:
|
||||
assert not resource
|
||||
self._node = node
|
||||
self._domain = domain
|
||||
self._update_bare_full()
|
||||
|
||||
@resource.setter
|
||||
def resource(self, value):
|
||||
self._resource = _validate_resource(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@full.setter
|
||||
def full(self, value):
|
||||
self._node, self._domain, self._resource = _parse_jid(value)
|
||||
self._update_bare_full()
|
||||
|
||||
@jid.setter
|
||||
def jid(self, value):
|
||||
self._node, self._domain, self._resource = _parse_jid(value)
|
||||
self._update_bare_full()
|
||||
|
||||
def __str__(self):
|
||||
"""Use the full JID as the string value."""
|
||||
return self._full
|
||||
return _format_jid(self._node, self._domain, self._resource)
|
||||
|
||||
def __repr__(self):
|
||||
"""Use the full JID as the representation."""
|
||||
return self._full
|
||||
return _format_jid(self._node, self._domain, self._resource)
|
||||
|
||||
# pylint: disable=W0212
|
||||
def __eq__(self, other):
|
||||
@@ -470,4 +446,4 @@ class JID:
|
||||
|
||||
def __hash__(self):
|
||||
"""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))
|
||||
|
||||
@@ -14,3 +14,9 @@ from slixmpp.plugins.xep_0004.dataforms import 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
|
||||
|
||||
@@ -81,6 +81,18 @@ class Form(ElementBase):
|
||||
self.append(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):
|
||||
itemXML = ET.Element('{%s}item' % self.namespace)
|
||||
self.xml.append(itemXML)
|
||||
@@ -184,13 +196,13 @@ class Form(ElementBase):
|
||||
for var, field in fields:
|
||||
field['var'] = var
|
||||
self.add_field(
|
||||
var=field.get('var'),
|
||||
label=field.get('label'),
|
||||
desc=field.get('desc'),
|
||||
required=field.get('required'),
|
||||
value=field.get('value'),
|
||||
options=field.get('options'),
|
||||
type=field.get('type'))
|
||||
var = field.get('var'),
|
||||
label = field.get('label'),
|
||||
desc = field.get('desc'),
|
||||
required = field.get('required'),
|
||||
value = field.get('value'),
|
||||
options = field.get('options'),
|
||||
type = field.get('type'))
|
||||
|
||||
def set_instructions(self, instructions):
|
||||
del self['instructions']
|
||||
@@ -209,7 +221,7 @@ class Form(ElementBase):
|
||||
|
||||
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:
|
||||
:return:
|
||||
"""
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0009.stanza import RPCQuery, MethodCall, MethodResponse
|
||||
|
||||
|
||||
register_plugin(XEP_0009)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0009 = XEP_0009
|
||||
|
||||
@@ -25,7 +25,7 @@ def fault2xml(fault):
|
||||
|
||||
def xml2fault(params):
|
||||
vals = []
|
||||
for value in params.xml.findall('{%s}value' % _namespace):
|
||||
for value in params.findall('{%s}value' % _namespace):
|
||||
vals.append(_xml2py(value))
|
||||
fault = dict()
|
||||
fault['code'] = vals[0]['faultCode']
|
||||
@@ -92,40 +92,39 @@ def _py2xml(*args):
|
||||
def xml2py(params):
|
||||
namespace = 'jabber:iq:rpc'
|
||||
vals = []
|
||||
for param in params.xml.findall('{%s}param' % namespace):
|
||||
for param in params.findall('{%s}param' % namespace):
|
||||
vals.append(_xml2py(param.find('{%s}value' % namespace)))
|
||||
return vals
|
||||
|
||||
def _xml2py(value):
|
||||
namespace = 'jabber:iq:rpc'
|
||||
find_value = value.xml.find
|
||||
if find_value('{%s}nil' % namespace) is not None:
|
||||
if value.find('{%s}nil' % namespace) is not None:
|
||||
return None
|
||||
if find_value('{%s}i4' % namespace) is not None:
|
||||
return int(find_value('{%s}i4' % namespace).text)
|
||||
if find_value('{%s}int' % namespace) is not None:
|
||||
return int(find_value('{%s}int' % namespace).text)
|
||||
if find_value('{%s}boolean' % namespace) is not None:
|
||||
return bool(int(find_value('{%s}boolean' % namespace).text))
|
||||
if find_value('{%s}string' % namespace) is not None:
|
||||
return find_value('{%s}string' % namespace).text
|
||||
if find_value('{%s}double' % namespace) is not None:
|
||||
return float(find_value('{%s}double' % namespace).text)
|
||||
if find_value('{%s}base64' % namespace) is not None:
|
||||
return rpcbase64(find_value('{%s}base64' % namespace).text.encode())
|
||||
if find_value('{%s}Base64' % namespace) is not None:
|
||||
if value.find('{%s}i4' % namespace) is not None:
|
||||
return int(value.find('{%s}i4' % namespace).text)
|
||||
if value.find('{%s}int' % namespace) is not None:
|
||||
return int(value.find('{%s}int' % namespace).text)
|
||||
if value.find('{%s}boolean' % namespace) is not None:
|
||||
return bool(int(value.find('{%s}boolean' % namespace).text))
|
||||
if value.find('{%s}string' % namespace) is not None:
|
||||
return value.find('{%s}string' % namespace).text
|
||||
if value.find('{%s}double' % namespace) is not None:
|
||||
return float(value.find('{%s}double' % namespace).text)
|
||||
if value.find('{%s}base64' % namespace) is not None:
|
||||
return rpcbase64(value.find('{%s}base64' % namespace).text.encode())
|
||||
if value.find('{%s}Base64' % namespace) is not None:
|
||||
# Older versions of XEP-0009 used Base64
|
||||
return rpcbase64(find_value('{%s}Base64' % namespace).text.encode())
|
||||
if find_value('{%s}dateTime.iso8601' % namespace) is not None:
|
||||
return rpctime(find_value('{%s}dateTime.iso8601' % namespace).text)
|
||||
if find_value('{%s}struct' % namespace) is not None:
|
||||
return rpcbase64(value.find('{%s}Base64' % namespace).text.encode())
|
||||
if value.find('{%s}dateTime.iso8601' % namespace) is not None:
|
||||
return rpctime(value.find('{%s}dateTime.iso8601' % namespace).text)
|
||||
if value.find('{%s}struct' % namespace) is not None:
|
||||
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))
|
||||
return struct
|
||||
if find_value('{%s}array' % namespace) is not None:
|
||||
if value.find('{%s}array' % namespace) is not None:
|
||||
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))
|
||||
return array
|
||||
raise ValueError()
|
||||
|
||||
@@ -163,7 +163,7 @@ class ACL:
|
||||
|
||||
@classmethod
|
||||
def _next_token(cls, expression, index):
|
||||
new_index = expression.xml.find('*', index)
|
||||
new_index = expression.find('*', index)
|
||||
if new_index == 0:
|
||||
return ''
|
||||
else:
|
||||
@@ -182,7 +182,7 @@ class ACL:
|
||||
#! print "[TOKEN] '%s'" % token
|
||||
size = len(token)
|
||||
if size > 0:
|
||||
token_index = value.xml.find(token, position)
|
||||
token_index = value.find(token, position)
|
||||
if token_index == -1:
|
||||
return False
|
||||
else:
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0012.last_activity import XEP_0012
|
||||
|
||||
|
||||
register_plugin(XEP_0012)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0004 = XEP_0012
|
||||
|
||||
@@ -66,7 +66,7 @@ class XEP_0012(BasePlugin):
|
||||
self.del_last_activity(jid)
|
||||
|
||||
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):
|
||||
self.api['set_last_activity'](jid, args={
|
||||
|
||||
@@ -15,3 +15,8 @@ from slixmpp.plugins.xep_0030.disco import 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
|
||||
|
||||
@@ -137,7 +137,7 @@ class DiscoInfo(ElementBase):
|
||||
identity = (category, itype, lang)
|
||||
if identity in self._identities:
|
||||
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_xml.attrib['type'],
|
||||
id_xml.attrib.get('{%s}lang' % self.xml_ns, None))
|
||||
@@ -163,7 +163,7 @@ class DiscoInfo(ElementBase):
|
||||
identities = set()
|
||||
else:
|
||||
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)
|
||||
if lang is None or xml_lang == lang:
|
||||
id = (id_xml.attrib['category'],
|
||||
@@ -205,7 +205,7 @@ class DiscoInfo(ElementBase):
|
||||
Arguments:
|
||||
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:
|
||||
self.xml.remove(id_xml)
|
||||
elif id_xml.attrib.get('{%s}lang' % self.xml_ns, None) == lang:
|
||||
@@ -239,7 +239,7 @@ class DiscoInfo(ElementBase):
|
||||
"""
|
||||
if feature in self._features:
|
||||
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:
|
||||
self.xml.remove(feature_xml)
|
||||
return True
|
||||
@@ -251,7 +251,7 @@ class DiscoInfo(ElementBase):
|
||||
features = set()
|
||||
else:
|
||||
features = []
|
||||
for feature_xml in self.xml.findall('{%s}feature' % self.namespace):
|
||||
for feature_xml in self.findall('{%s}feature' % self.namespace):
|
||||
if dedupe:
|
||||
features.add(feature_xml.attrib['var'])
|
||||
else:
|
||||
@@ -272,5 +272,5 @@ class DiscoInfo(ElementBase):
|
||||
def del_features(self):
|
||||
"""Remove all features."""
|
||||
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)
|
||||
|
||||
@@ -95,7 +95,7 @@ class DiscoItems(ElementBase):
|
||||
node -- Optional extra identifying information.
|
||||
"""
|
||||
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_xml.attrib.get('node', None))
|
||||
if item == (jid, node):
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"""
|
||||
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from slixmpp import Iq
|
||||
from slixmpp.exceptions import XMPPError, IqError, IqTimeout
|
||||
@@ -47,6 +48,7 @@ class StaticDisco(object):
|
||||
self.nodes = {}
|
||||
self.xmpp = xmpp
|
||||
self.disco = disco
|
||||
self.lock = threading.RLock()
|
||||
|
||||
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.
|
||||
node -- The node that will own the new stanzas.
|
||||
"""
|
||||
if jid is None:
|
||||
jid = self.xmpp.boundjid.full
|
||||
if node is None:
|
||||
node = ''
|
||||
if ifrom is None:
|
||||
ifrom = ''
|
||||
if isinstance(ifrom, JID):
|
||||
ifrom = ifrom.full
|
||||
if (jid, node, ifrom) not in self.nodes:
|
||||
self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(),
|
||||
'items': DiscoItems()}
|
||||
self.nodes[(jid, node, ifrom)]['info']['node'] = node
|
||||
self.nodes[(jid, node, ifrom)]['items']['node'] = node
|
||||
with self.lock:
|
||||
if jid is None:
|
||||
jid = self.xmpp.boundjid.full
|
||||
if node is None:
|
||||
node = ''
|
||||
if ifrom is None:
|
||||
ifrom = ''
|
||||
if isinstance(ifrom, JID):
|
||||
ifrom = ifrom.full
|
||||
if (jid, node, ifrom) not in self.nodes:
|
||||
self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(),
|
||||
'items': DiscoItems()}
|
||||
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):
|
||||
if jid is None:
|
||||
jid = self.xmpp.boundjid.full
|
||||
if node is None:
|
||||
node = ''
|
||||
if ifrom is None:
|
||||
ifrom = ''
|
||||
if isinstance(ifrom, JID):
|
||||
ifrom = ifrom.full
|
||||
if (jid, node, ifrom) not in self.nodes:
|
||||
self.add_node(jid, node, ifrom)
|
||||
return self.nodes[(jid, node, ifrom)]
|
||||
with self.lock:
|
||||
if jid is None:
|
||||
jid = self.xmpp.boundjid.full
|
||||
if node is None:
|
||||
node = ''
|
||||
if ifrom is None:
|
||||
ifrom = ''
|
||||
if isinstance(ifrom, JID):
|
||||
ifrom = ifrom.full
|
||||
if (jid, node, ifrom) not in self.nodes:
|
||||
self.add_node(jid, node, ifrom)
|
||||
return self.nodes[(jid, node, ifrom)]
|
||||
|
||||
def node_exists(self, jid=None, node=None, ifrom=None):
|
||||
if jid is None:
|
||||
jid = self.xmpp.boundjid.full
|
||||
if node is None:
|
||||
node = ''
|
||||
if ifrom is None:
|
||||
ifrom = ''
|
||||
if isinstance(ifrom, JID):
|
||||
ifrom = ifrom.full
|
||||
if (jid, node, ifrom) not in self.nodes:
|
||||
return False
|
||||
return True
|
||||
with self.lock:
|
||||
if jid is None:
|
||||
jid = self.xmpp.boundjid.full
|
||||
if node is None:
|
||||
node = ''
|
||||
if ifrom is None:
|
||||
ifrom = ''
|
||||
if isinstance(ifrom, JID):
|
||||
ifrom = ifrom.full
|
||||
if (jid, node, ifrom) not in self.nodes:
|
||||
return False
|
||||
return True
|
||||
|
||||
# =================================================================
|
||||
# Node Handlers
|
||||
@@ -194,13 +199,14 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
if not self.node_exists(jid, node):
|
||||
if not node:
|
||||
return DiscoInfo()
|
||||
with self.lock:
|
||||
if not self.node_exists(jid, node):
|
||||
if not node:
|
||||
return DiscoInfo()
|
||||
else:
|
||||
raise XMPPError(condition='item-not-found')
|
||||
else:
|
||||
raise XMPPError(condition='item-not-found')
|
||||
else:
|
||||
return self.get_node(jid, node)['info']
|
||||
return self.get_node(jid, node)['info']
|
||||
|
||||
def set_info(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -208,8 +214,9 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is a disco#info substanza.
|
||||
"""
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info'] = data
|
||||
with self.lock:
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info'] = data
|
||||
|
||||
def del_info(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -217,8 +224,9 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['info'] = DiscoInfo()
|
||||
with self.lock:
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['info'] = DiscoInfo()
|
||||
|
||||
def get_items(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -226,13 +234,14 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
if not self.node_exists(jid, node):
|
||||
if not node:
|
||||
return DiscoItems()
|
||||
with self.lock:
|
||||
if not self.node_exists(jid, node):
|
||||
if not node:
|
||||
return DiscoItems()
|
||||
else:
|
||||
raise XMPPError(condition='item-not-found')
|
||||
else:
|
||||
raise XMPPError(condition='item-not-found')
|
||||
else:
|
||||
return self.get_node(jid, node)['items']
|
||||
return self.get_node(jid, node)['items']
|
||||
|
||||
def set_items(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -241,9 +250,10 @@ class StaticDisco(object):
|
||||
The data parameter may provide:
|
||||
items -- A set of items in tuple format.
|
||||
"""
|
||||
items = data.get('items', set())
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['items']['items'] = items
|
||||
with self.lock:
|
||||
items = data.get('items', set())
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['items']['items'] = items
|
||||
|
||||
def del_items(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -251,8 +261,9 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['items'] = DiscoItems()
|
||||
with self.lock:
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['items'] = DiscoItems()
|
||||
|
||||
def add_identity(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -264,12 +275,13 @@ class StaticDisco(object):
|
||||
name -- Optional human readable name for this identity.
|
||||
lang -- Optional standard xml:lang value.
|
||||
"""
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info'].add_identity(
|
||||
data.get('category', ''),
|
||||
data.get('itype', ''),
|
||||
data.get('name', None),
|
||||
data.get('lang', None))
|
||||
with self.lock:
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info'].add_identity(
|
||||
data.get('category', ''),
|
||||
data.get('itype', ''),
|
||||
data.get('name', None),
|
||||
data.get('lang', None))
|
||||
|
||||
def set_identities(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -279,9 +291,10 @@ class StaticDisco(object):
|
||||
identities -- A list of identities in tuple form:
|
||||
(category, type, name, lang)
|
||||
"""
|
||||
identities = data.get('identities', set())
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info']['identities'] = identities
|
||||
with self.lock:
|
||||
identities = data.get('identities', set())
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info']['identities'] = identities
|
||||
|
||||
def del_identity(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -293,12 +306,13 @@ class StaticDisco(object):
|
||||
name -- Optional human readable name for this identity.
|
||||
lang -- Optional, standard xml:lang value.
|
||||
"""
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['info'].del_identity(
|
||||
data.get('category', ''),
|
||||
data.get('itype', ''),
|
||||
data.get('name', None),
|
||||
data.get('lang', None))
|
||||
with self.lock:
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['info'].del_identity(
|
||||
data.get('category', ''),
|
||||
data.get('itype', ''),
|
||||
data.get('name', None),
|
||||
data.get('lang', None))
|
||||
|
||||
def del_identities(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -306,8 +320,9 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
if self.node_exists(jid, node):
|
||||
del self.get_node(jid, node)['info']['identities']
|
||||
with self.lock:
|
||||
if self.node_exists(jid, node):
|
||||
del self.get_node(jid, node)['info']['identities']
|
||||
|
||||
def add_feature(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -316,9 +331,10 @@ class StaticDisco(object):
|
||||
The data parameter should include:
|
||||
feature -- The namespace of the supported feature.
|
||||
"""
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info'].add_feature(
|
||||
data.get('feature', ''))
|
||||
with self.lock:
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info'].add_feature(
|
||||
data.get('feature', ''))
|
||||
|
||||
def set_features(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -327,9 +343,10 @@ class StaticDisco(object):
|
||||
The data parameter should include:
|
||||
features -- The new set of supported features.
|
||||
"""
|
||||
features = data.get('features', set())
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info']['features'] = features
|
||||
with self.lock:
|
||||
features = data.get('features', set())
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['info']['features'] = features
|
||||
|
||||
def del_feature(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -338,9 +355,10 @@ class StaticDisco(object):
|
||||
The data parameter should include:
|
||||
feature -- The namespace of the removed feature.
|
||||
"""
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['info'].del_feature(
|
||||
data.get('feature', ''))
|
||||
with self.lock:
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['info'].del_feature(
|
||||
data.get('feature', ''))
|
||||
|
||||
def del_features(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -348,9 +366,10 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
if not self.node_exists(jid, node):
|
||||
return
|
||||
del self.get_node(jid, node)['info']['features']
|
||||
with self.lock:
|
||||
if not self.node_exists(jid, node):
|
||||
return
|
||||
del self.get_node(jid, node)['info']['features']
|
||||
|
||||
def add_item(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -362,11 +381,12 @@ class StaticDisco(object):
|
||||
non-addressable items.
|
||||
name -- Optional human readable name for the item.
|
||||
"""
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['items'].add_item(
|
||||
data.get('ijid', ''),
|
||||
node=data.get('inode', ''),
|
||||
name=data.get('name', ''))
|
||||
with self.lock:
|
||||
self.add_node(jid, node)
|
||||
self.get_node(jid, node)['items'].add_item(
|
||||
data.get('ijid', ''),
|
||||
node=data.get('inode', ''),
|
||||
name=data.get('name', ''))
|
||||
|
||||
def del_item(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -376,10 +396,11 @@ class StaticDisco(object):
|
||||
ijid -- JID of the item to remove.
|
||||
inode -- Optional extra identifying information.
|
||||
"""
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['items'].del_item(
|
||||
data.get('ijid', ''),
|
||||
node=data.get('inode', None))
|
||||
with self.lock:
|
||||
if self.node_exists(jid, node):
|
||||
self.get_node(jid, node)['items'].del_item(
|
||||
data.get('ijid', ''),
|
||||
node=data.get('inode', None))
|
||||
|
||||
def cache_info(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -389,11 +410,12 @@ class StaticDisco(object):
|
||||
containing the disco info to cache, or
|
||||
the disco#info substanza itself.
|
||||
"""
|
||||
if isinstance(data, Iq):
|
||||
data = data['disco_info']
|
||||
with self.lock:
|
||||
if isinstance(data, Iq):
|
||||
data = data['disco_info']
|
||||
|
||||
self.add_node(jid, node, ifrom)
|
||||
self.get_node(jid, node, ifrom)['info'] = data
|
||||
self.add_node(jid, node, ifrom)
|
||||
self.get_node(jid, node, ifrom)['info'] = data
|
||||
|
||||
def get_cached_info(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -401,7 +423,8 @@ class StaticDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
if not self.node_exists(jid, node, ifrom):
|
||||
return None
|
||||
else:
|
||||
return self.get_node(jid, node, ifrom)['info']
|
||||
with self.lock:
|
||||
if not self.node_exists(jid, node, ifrom):
|
||||
return None
|
||||
else:
|
||||
return self.get_node(jid, node, ifrom)['info']
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0033.addresses import XEP_0033
|
||||
|
||||
|
||||
register_plugin(XEP_0033)
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0033 = XEP_0033
|
||||
Addresses.addAddress = Addresses.add_address
|
||||
|
||||
@@ -118,8 +118,14 @@ for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'):
|
||||
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':
|
||||
Addresses.interfaces.add('addresses')
|
||||
setattr(Addresses, "getAddresses", get_multi)
|
||||
setattr(Addresses, "setAddresses", set_multi)
|
||||
setattr(Addresses, "delAddresses", del_multi)
|
||||
|
||||
|
||||
register_stanza_plugin(Addresses, Address, iterable=True)
|
||||
|
||||
@@ -160,7 +160,6 @@ class XEP_0045(BasePlugin):
|
||||
got_online = False
|
||||
if pr['muc']['room'] not in self.rooms.keys():
|
||||
return
|
||||
self.xmpp.roster[pr['from']].ignore_updates = True
|
||||
entry = pr['muc'].get_stanza_values()
|
||||
entry['show'] = pr['show']
|
||||
entry['status'] = pr['status']
|
||||
@@ -222,7 +221,7 @@ class XEP_0045(BasePlugin):
|
||||
if ifrom is not None:
|
||||
iq['from'] = ifrom
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
|
||||
form['type'] = 'submit'
|
||||
form = form.getXML('submit')
|
||||
query.append(form)
|
||||
iq.append(query)
|
||||
# For now, swallow errors to preserve existing API
|
||||
@@ -360,7 +359,7 @@ class XEP_0045(BasePlugin):
|
||||
form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
|
||||
if form is None:
|
||||
raise ValueError
|
||||
return self.xmpp.plugin['xep_0004'].build_form(form)
|
||||
return self.xmpp.plugin['xep_0004'].buildForm(form)
|
||||
|
||||
def cancelConfig(self, room, ifrom=None):
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
|
||||
@@ -373,8 +372,8 @@ class XEP_0045(BasePlugin):
|
||||
|
||||
def setRoomConfig(self, room, config, ifrom=''):
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
|
||||
config['type'] = 'submit'
|
||||
query.append(config)
|
||||
x = config.getXML('submit')
|
||||
query.append(x)
|
||||
iq = self.xmpp.make_iq_set(query)
|
||||
iq['to'] = room
|
||||
iq['from'] = ifrom
|
||||
|
||||
@@ -15,3 +15,7 @@ from slixmpp.plugins.xep_0047.ibb import XEP_0047
|
||||
|
||||
|
||||
register_plugin(XEP_0047)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0047 = XEP_0047
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0050.adhoc import XEP_0050
|
||||
|
||||
|
||||
register_plugin(XEP_0050)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0050 = XEP_0050
|
||||
|
||||
@@ -100,7 +100,7 @@ class Command(ElementBase):
|
||||
self.del_actions()
|
||||
if values:
|
||||
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:
|
||||
if val in self.next_actions:
|
||||
action = ET.Element('{%s}%s' % (self.namespace, val))
|
||||
@@ -111,7 +111,7 @@ class Command(ElementBase):
|
||||
Return the set of allowable next actions.
|
||||
"""
|
||||
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:
|
||||
for action in self.next_actions:
|
||||
action_xml = actions_xml.find('{%s}%s' % (self.namespace,
|
||||
|
||||
@@ -13,3 +13,6 @@ from slixmpp.plugins.xep_0059.rsm import ResultIterator, XEP_0059
|
||||
|
||||
|
||||
register_plugin(XEP_0059)
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0059 = XEP_0059
|
||||
|
||||
@@ -70,7 +70,7 @@ class Set(ElementBase):
|
||||
'count', 'index', 'last', 'max'))
|
||||
|
||||
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 val:
|
||||
fi.attrib['index'] = val
|
||||
@@ -82,7 +82,7 @@ class Set(ElementBase):
|
||||
self.xml.append(fi)
|
||||
|
||||
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:
|
||||
return fi.attrib.get('index', '')
|
||||
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0060 import stanza
|
||||
|
||||
|
||||
register_plugin(XEP_0060)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0060 = XEP_0060
|
||||
|
||||
@@ -206,7 +206,7 @@ class Options(ElementBase):
|
||||
return form
|
||||
|
||||
def set_options(self, value):
|
||||
self.xml.append(value)
|
||||
self.xml.append(value.getXML())
|
||||
return self
|
||||
|
||||
def del_options(self):
|
||||
@@ -238,7 +238,7 @@ class PublishOptions(ElementBase):
|
||||
if value is None:
|
||||
self.del_publish_options()
|
||||
else:
|
||||
self.xml.append(value)
|
||||
self.xml.append(value.getXML())
|
||||
return self
|
||||
|
||||
def del_publish_options(self):
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0066.oob import XEP_0066
|
||||
|
||||
|
||||
register_plugin(XEP_0066)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0066 = XEP_0066
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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'}
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0077.register import XEP_0077
|
||||
|
||||
|
||||
register_plugin(XEP_0077)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0077 = XEP_0077
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0078.legacyauth import XEP_0078
|
||||
|
||||
|
||||
register_plugin(XEP_0078)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0078 = XEP_0078
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0085.chat_states import XEP_0085
|
||||
|
||||
|
||||
register_plugin(XEP_0085)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0085 = XEP_0085
|
||||
|
||||
@@ -50,7 +50,7 @@ class ChatState(ElementBase):
|
||||
def get_chat_state(self):
|
||||
parent = self.parent()
|
||||
for state in self.states:
|
||||
state_xml = parent.xml.find('{%s}%s' % (self.namespace, state))
|
||||
state_xml = parent.find('{%s}%s' % (self.namespace, state))
|
||||
if state_xml is not None:
|
||||
self.xml = state_xml
|
||||
return state
|
||||
@@ -68,7 +68,7 @@ class ChatState(ElementBase):
|
||||
def del_chat_state(self):
|
||||
parent = self.parent()
|
||||
for state in self.states:
|
||||
state_xml = parent.xml.find('{%s}%s' % (self.namespace, state))
|
||||
state_xml = parent.find('{%s}%s' % (self.namespace, state))
|
||||
if state_xml is not None:
|
||||
self.xml = ET.Element('')
|
||||
parent.xml.remove(state_xml)
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0086.legacy_error import XEP_0086
|
||||
|
||||
|
||||
register_plugin(XEP_0086)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0086 = XEP_0086
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0092.version import XEP_0092
|
||||
|
||||
|
||||
register_plugin(XEP_0092)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0092 = XEP_0092
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0115.caps import XEP_0115
|
||||
|
||||
|
||||
register_plugin(XEP_0115)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0115 = XEP_0115
|
||||
|
||||
@@ -124,19 +124,23 @@ class StaticCaps(object):
|
||||
return None
|
||||
|
||||
def cache_caps(self, jid, node, ifrom, data):
|
||||
verstring = data.get('verstring', None)
|
||||
info = data.get('info', None)
|
||||
if not verstring or not info:
|
||||
return
|
||||
self.ver_cache[verstring] = info
|
||||
with self.static.lock:
|
||||
verstring = data.get('verstring', None)
|
||||
info = data.get('info', None)
|
||||
if not verstring or not info:
|
||||
return
|
||||
self.ver_cache[verstring] = info
|
||||
|
||||
def assign_verstring(self, jid, node, ifrom, data):
|
||||
if isinstance(jid, JID):
|
||||
jid = jid.full
|
||||
self.jid_vers[jid] = data.get('verstring', None)
|
||||
with self.static.lock:
|
||||
if isinstance(jid, JID):
|
||||
jid = jid.full
|
||||
self.jid_vers[jid] = data.get('verstring', None)
|
||||
|
||||
def get_verstring(self, jid, node, ifrom, data):
|
||||
return self.jid_vers.get(jid, None)
|
||||
with self.static.lock:
|
||||
return self.jid_vers.get(jid, None)
|
||||
|
||||
def get_caps(self, jid, node, ifrom, data):
|
||||
return self.ver_cache.get(data.get('verstring', None), None)
|
||||
with self.static.lock:
|
||||
return self.ver_cache.get(data.get('verstring', None), None)
|
||||
|
||||
@@ -5,3 +5,7 @@ from slixmpp.plugins.xep_0122.data_validation import XEP_0122
|
||||
|
||||
|
||||
register_plugin(XEP_0122)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0122 = XEP_0122
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0128.extended_disco import XEP_0128
|
||||
|
||||
|
||||
register_plugin(XEP_0128)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0128 = XEP_0128
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0184.receipt import XEP_0184
|
||||
|
||||
|
||||
register_plugin(XEP_0184)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0184 = XEP_0184
|
||||
|
||||
@@ -32,7 +32,7 @@ class Request(ElementBase):
|
||||
|
||||
def get_request_receipt(self):
|
||||
parent = self.parent()
|
||||
if parent.xml.find("{%s}request" % self.namespace) is not None:
|
||||
if parent.find("{%s}request" % self.namespace) is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -63,7 +63,7 @@ class Received(ElementBase):
|
||||
|
||||
def get_receipt(self):
|
||||
parent = self.parent()
|
||||
xml = parent.xml.find("{%s}received" % self.namespace)
|
||||
xml = parent.find("{%s}received" % self.namespace)
|
||||
if xml is not None:
|
||||
return xml.attrib.get('id', '')
|
||||
return ''
|
||||
|
||||
@@ -33,7 +33,7 @@ class XEP_0186(BasePlugin):
|
||||
iq['type'] = 'set'
|
||||
iq['from'] = ifrom
|
||||
iq.enable('invisible')
|
||||
return iq.send(callback=callback, timeout=timeout)
|
||||
iq.send(callback=callback, timeout=timeout)
|
||||
|
||||
def set_visible(self, ifrom=None, callback=None,
|
||||
timeout=None):
|
||||
@@ -41,4 +41,4 @@ class XEP_0186(BasePlugin):
|
||||
iq['type'] = 'set'
|
||||
iq['from'] = ifrom
|
||||
iq.enable('visible')
|
||||
return iq.send(callback=callback, timeout=timeout)
|
||||
iq.send(callback=callback, timeout=timeout)
|
||||
|
||||
@@ -99,7 +99,7 @@ class StreamManagement(ElementBase):
|
||||
interfaces = set(['required', 'optional'])
|
||||
|
||||
def get_required(self):
|
||||
return self.xml.find('{%s}required' % self.namespace) is not None
|
||||
return self.find('{%s}required' % self.namespace) is not None
|
||||
|
||||
def set_required(self, val):
|
||||
self.del_required()
|
||||
@@ -110,7 +110,7 @@ class StreamManagement(ElementBase):
|
||||
self._del_sub('required')
|
||||
|
||||
def get_optional(self):
|
||||
return self.xml.find('{%s}optional' % self.namespace) is not None
|
||||
return self.find('{%s}optional' % self.namespace) is not None
|
||||
|
||||
def set_optional(self, val):
|
||||
self.del_optional()
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import threading
|
||||
import collections
|
||||
|
||||
from slixmpp.stanza import Message, Presence, Iq, StreamFeatures
|
||||
@@ -70,10 +70,15 @@ class XEP_0198(BasePlugin):
|
||||
return
|
||||
|
||||
self.window_counter = self.window
|
||||
self.window_counter_lock = threading.Lock()
|
||||
|
||||
self.enabled = False
|
||||
self.enabled = threading.Event()
|
||||
self.unacked_queue = collections.deque()
|
||||
|
||||
self.seq_lock = threading.Lock()
|
||||
self.handled_lock = threading.Lock()
|
||||
self.ack_lock = threading.Lock()
|
||||
|
||||
register_stanza_plugin(StreamFeatures, stanza.StreamManagement)
|
||||
self.xmpp.register_stanza(stanza.Enable)
|
||||
self.xmpp.register_stanza(stanza.Enabled)
|
||||
@@ -156,7 +161,7 @@ class XEP_0198(BasePlugin):
|
||||
|
||||
def session_end(self, event):
|
||||
"""Reset stream management state."""
|
||||
self.enabled = False
|
||||
self.enabled.clear()
|
||||
self.unacked_queue.clear()
|
||||
self.sm_id = None
|
||||
self.handled = 0
|
||||
@@ -166,15 +171,15 @@ class XEP_0198(BasePlugin):
|
||||
def send_ack(self):
|
||||
"""Send the current ack count to the server."""
|
||||
ack = stanza.Ack(self.xmpp)
|
||||
ack['h'] = self.handled
|
||||
with self.handled_lock:
|
||||
ack['h'] = self.handled
|
||||
self.xmpp.send_raw(str(ack))
|
||||
|
||||
def request_ack(self, e=None):
|
||||
"""Request an ack from the server."""
|
||||
req = stanza.RequestAck(self.xmpp)
|
||||
self.xmpp.send_raw(str(req))
|
||||
self.xmpp.send_queue.put(str(req))
|
||||
|
||||
@asyncio.coroutine
|
||||
def _handle_sm_feature(self, features):
|
||||
"""
|
||||
Enable or resume stream management.
|
||||
@@ -191,21 +196,13 @@ class XEP_0198(BasePlugin):
|
||||
return False
|
||||
if not self.sm_id:
|
||||
if 'bind' in self.xmpp.features:
|
||||
self.enabled.set()
|
||||
enable = stanza.Enable(self.xmpp)
|
||||
enable['resume'] = self.allow_resume
|
||||
enable.send()
|
||||
self.enabled = True
|
||||
self.handled = 0
|
||||
self.unacked_queue.clear()
|
||||
|
||||
waiter = Waiter('enabled_or_failed',
|
||||
MatchMany([
|
||||
MatchXPath(stanza.Enabled.tag_name()),
|
||||
MatchXPath(stanza.Failed.tag_name())]))
|
||||
self.xmpp.register_handler(waiter)
|
||||
result = yield from waiter.wait()
|
||||
elif self.sm_id and self.allow_resume and 'bind' not in self.xmpp.features:
|
||||
self.enabled = True
|
||||
elif self.sm_id and self.allow_resume:
|
||||
self.enabled.set()
|
||||
resume = stanza.Resume(self.xmpp)
|
||||
resume['h'] = self.handled
|
||||
resume['previd'] = self.sm_id
|
||||
@@ -219,7 +216,7 @@ class XEP_0198(BasePlugin):
|
||||
MatchXPath(stanza.Resumed.tag_name()),
|
||||
MatchXPath(stanza.Failed.tag_name())]))
|
||||
self.xmpp.register_handler(waiter)
|
||||
result = yield from waiter.wait()
|
||||
result = waiter.wait()
|
||||
if result is not None and result.name == 'resumed':
|
||||
return True
|
||||
return False
|
||||
@@ -253,7 +250,7 @@ class XEP_0198(BasePlugin):
|
||||
|
||||
Raises an :term:`sm_failed` event.
|
||||
"""
|
||||
self.enabled = False
|
||||
self.enabled.clear()
|
||||
self.unacked_queue.clear()
|
||||
self.xmpp.event('sm_failed', stanza)
|
||||
|
||||
@@ -265,24 +262,21 @@ class XEP_0198(BasePlugin):
|
||||
if ack['h'] == self.last_ack:
|
||||
return
|
||||
|
||||
num_acked = (ack['h'] - self.last_ack) % MAX_SEQ
|
||||
num_unacked = len(self.unacked_queue)
|
||||
log.debug("Ack: %s, Last Ack: %s, " + \
|
||||
"Unacked: %s, Num Acked: %s, " + \
|
||||
"Remaining: %s",
|
||||
ack['h'],
|
||||
self.last_ack,
|
||||
num_unacked,
|
||||
num_acked,
|
||||
num_unacked - num_acked)
|
||||
if num_acked > len(self.unacked_queue) or num_acked < 0:
|
||||
log.error('Inconsistent sequence numbers from the server,'
|
||||
' ignoring and replacing ours with them.')
|
||||
num_acked = len(self.unacked_queue)
|
||||
for x in range(num_acked):
|
||||
seq, stanza = self.unacked_queue.popleft()
|
||||
self.xmpp.event('stanza_acked', stanza)
|
||||
self.last_ack = ack['h']
|
||||
with self.ack_lock:
|
||||
num_acked = (ack['h'] - self.last_ack) % MAX_SEQ
|
||||
num_unacked = len(self.unacked_queue)
|
||||
log.debug("Ack: %s, Last Ack: %s, " + \
|
||||
"Unacked: %s, Num Acked: %s, " + \
|
||||
"Remaining: %s",
|
||||
ack['h'],
|
||||
self.last_ack,
|
||||
num_unacked,
|
||||
num_acked,
|
||||
num_unacked - num_acked)
|
||||
for x in range(num_acked):
|
||||
seq, stanza = self.unacked_queue.popleft()
|
||||
self.xmpp.event('stanza_acked', stanza)
|
||||
self.last_ack = ack['h']
|
||||
|
||||
def _handle_request_ack(self, req):
|
||||
"""Handle an ack request by sending an ack."""
|
||||
@@ -290,27 +284,30 @@ class XEP_0198(BasePlugin):
|
||||
|
||||
def _handle_incoming(self, stanza):
|
||||
"""Increment the handled counter for each inbound stanza."""
|
||||
if not self.enabled:
|
||||
if not self.enabled.is_set():
|
||||
return stanza
|
||||
|
||||
if isinstance(stanza, (Message, Presence, Iq)):
|
||||
# Sequence numbers are mod 2^32
|
||||
self.handled = (self.handled + 1) % MAX_SEQ
|
||||
with self.handled_lock:
|
||||
# Sequence numbers are mod 2^32
|
||||
self.handled = (self.handled + 1) % MAX_SEQ
|
||||
return stanza
|
||||
|
||||
def _handle_outgoing(self, stanza):
|
||||
"""Store outgoing stanzas in a queue to be acked."""
|
||||
if not self.enabled:
|
||||
if not self.enabled.is_set():
|
||||
return stanza
|
||||
|
||||
if isinstance(stanza, (Message, Presence, Iq)):
|
||||
seq = None
|
||||
# Sequence numbers are mod 2^32
|
||||
self.seq = (self.seq + 1) % MAX_SEQ
|
||||
seq = self.seq
|
||||
with self.seq_lock:
|
||||
# Sequence numbers are mod 2^32
|
||||
self.seq = (self.seq + 1) % MAX_SEQ
|
||||
seq = self.seq
|
||||
self.unacked_queue.append((seq, stanza))
|
||||
self.window_counter -= 1
|
||||
if self.window_counter == 0:
|
||||
self.window_counter = self.window
|
||||
self.request_ack()
|
||||
with self.window_counter_lock:
|
||||
self.window_counter -= 1
|
||||
if self.window_counter == 0:
|
||||
self.window_counter = self.window
|
||||
self.request_ack()
|
||||
return stanza
|
||||
|
||||
@@ -13,3 +13,8 @@ from slixmpp.plugins.xep_0199.ping import XEP_0199
|
||||
|
||||
|
||||
register_plugin(XEP_0199)
|
||||
|
||||
|
||||
# Backwards compatibility for names
|
||||
xep_0199 = XEP_0199
|
||||
xep_0199.sendPing = xep_0199.send_ping
|
||||
|
||||
@@ -95,20 +95,18 @@ class XEP_0199(BasePlugin):
|
||||
self.timeout = timeout
|
||||
|
||||
self.keepalive = True
|
||||
handler = lambda event=None: asyncio.ensure_future(self._keepalive(event))
|
||||
self.xmpp.schedule('Ping keepalive',
|
||||
self.interval,
|
||||
handler,
|
||||
self._keepalive,
|
||||
repeat=True)
|
||||
|
||||
def disable_keepalive(self, event=None):
|
||||
self.xmpp.cancel_schedule('Ping keepalive')
|
||||
|
||||
@asyncio.coroutine
|
||||
def _keepalive(self, event=None):
|
||||
log.debug("Keepalive ping...")
|
||||
try:
|
||||
rtt = yield from self.ping(self.xmpp.boundjid.host, timeout=self.timeout)
|
||||
rtt = self.ping(self.xmpp.boundjid.host, timeout=self.timeout)
|
||||
except IqTimeout:
|
||||
log.debug("Did not recieve ping back in time." + \
|
||||
"Requesting Reconnect.")
|
||||
@@ -174,7 +172,8 @@ class XEP_0199(BasePlugin):
|
||||
|
||||
log.debug('Pinging %s' % jid)
|
||||
try:
|
||||
yield from self.send_ping(jid, ifrom=ifrom, timeout=timeout)
|
||||
yield from self.send_ping(jid, ifrom=ifrom, timeout=timeout,
|
||||
coroutine=True)
|
||||
except IqError as e:
|
||||
if own_host:
|
||||
rtt = time.time() - start
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0202.time import XEP_0202
|
||||
|
||||
|
||||
register_plugin(XEP_0202)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0202 = XEP_0202
|
||||
|
||||
@@ -14,3 +14,6 @@ from slixmpp.plugins.xep_0203.delay import XEP_0203
|
||||
|
||||
|
||||
register_plugin(XEP_0203)
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0203 = XEP_0203
|
||||
|
||||
@@ -14,3 +14,7 @@ from slixmpp.plugins.xep_0224.attention import XEP_0224
|
||||
|
||||
|
||||
register_plugin(XEP_0224)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0224 = XEP_0224
|
||||
|
||||
@@ -13,3 +13,7 @@ from slixmpp.plugins.xep_0249.invite import XEP_0249
|
||||
|
||||
|
||||
register_plugin(XEP_0249)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0249 = XEP_0249
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.plugins.base import register_plugin
|
||||
|
||||
from slixmpp.plugins.xep_0256.last_activity_presence import XEP_0256, LastActivity
|
||||
|
||||
register_plugin(XEP_0256)
|
||||
@@ -1,27 +0,0 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp import Presence
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.plugins.xep_0012 import stanza, LastActivity
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0256(BasePlugin):
|
||||
|
||||
name = 'xep_0256'
|
||||
description = 'XEP-0256: Last Activity in Presence'
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Presence, LastActivity)
|
||||
@@ -540,7 +540,7 @@ class XEP_0325(BasePlugin):
|
||||
fields = [f['name'] for f in iq['setResponse']['datas']]
|
||||
error_msg = None
|
||||
|
||||
if not iq['setResponse'].xml.find('error') is None and not iq['setResponse']['error']['text'] == "":
|
||||
if not iq['setResponse'].find('error') is None and not iq['setResponse']['error']['text'] == "":
|
||||
error_msg = iq['setResponse']['error']['text']
|
||||
|
||||
callback = self.sessions[seqnr]["callback"]
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
"""
|
||||
slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2016 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_0333.stanza import Markable, Received, Displayed, Acknowledged
|
||||
from slixmpp.plugins.xep_0333.hints import XEP_0333
|
||||
|
||||
register_plugin(XEP_0333)
|
||||
@@ -1,53 +0,0 @@
|
||||
"""
|
||||
slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2016 Emmanuel Gil Peyrot
|
||||
This file is part of slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp import Message
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.plugins.xep_0333 import stanza, Markable, Received, Displayed, Acknowledged
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class XEP_0333(BasePlugin):
|
||||
|
||||
name = 'xep_0333'
|
||||
description = 'XEP-0333: Chat Markers'
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Message, Markable)
|
||||
register_stanza_plugin(Message, Received)
|
||||
register_stanza_plugin(Message, Displayed)
|
||||
register_stanza_plugin(Message, Acknowledged)
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('Received Chat Marker',
|
||||
StanzaPath('message/received'),
|
||||
self._handle_received))
|
||||
self.xmpp.register_handler(
|
||||
Callback('Displayed Chat Marker',
|
||||
StanzaPath('message/displayed'),
|
||||
self._handle_displayed))
|
||||
self.xmpp.register_handler(
|
||||
Callback('Acknowledged Chat Marker',
|
||||
StanzaPath('message/acknowledged'),
|
||||
self._handle_acknowledged))
|
||||
|
||||
def _handle_received(self, message):
|
||||
self.xmpp.event('marker_received', message)
|
||||
self.xmpp.event('marker', message)
|
||||
|
||||
def _handle_displayed(self, message):
|
||||
self.xmpp.event('marker_displayed', message)
|
||||
self.xmpp.event('marker', message)
|
||||
|
||||
def _handle_acknowledged(self, message):
|
||||
self.xmpp.event('marker_acknowledged', message)
|
||||
self.xmpp.event('marker', message)
|
||||
@@ -1,32 +0,0 @@
|
||||
"""
|
||||
slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2016 Emmanuel Gil Peyrot
|
||||
This file is part of slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.xmlstream import ElementBase
|
||||
|
||||
class Markable(ElementBase):
|
||||
name = 'markable'
|
||||
plugin_attrib = 'markable'
|
||||
namespace = 'urn:xmpp:chat-markers:0'
|
||||
|
||||
class Received(ElementBase):
|
||||
name = 'received'
|
||||
plugin_attrib = 'received'
|
||||
namespace = 'urn:xmpp:chat-markers:0'
|
||||
interfaces = {'id'}
|
||||
|
||||
class Displayed(ElementBase):
|
||||
name = 'displayed'
|
||||
plugin_attrib = 'displayed'
|
||||
namespace = 'urn:xmpp:chat-markers:0'
|
||||
interfaces = {'id'}
|
||||
|
||||
class Acknowledged(ElementBase):
|
||||
name = 'acknowledged'
|
||||
plugin_attrib = 'acknowledged'
|
||||
namespace = 'urn:xmpp:chat-markers:0'
|
||||
interfaces = {'id'}
|
||||
@@ -1,14 +0,0 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.plugins.base import register_plugin
|
||||
|
||||
from slixmpp.plugins.xep_0334.stanza import Store, NoStore, NoPermanentStore, NoCopy
|
||||
from slixmpp.plugins.xep_0334.hints import XEP_0334
|
||||
|
||||
register_plugin(XEP_0334)
|
||||
@@ -1,28 +0,0 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2016 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp import Message
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.plugins.xep_0334 import stanza, Store, NoStore, NoPermanentStore, NoCopy
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class XEP_0334(BasePlugin):
|
||||
|
||||
name = 'xep_0334'
|
||||
description = 'XEP-0334: Message Processing Hints'
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Message, Store)
|
||||
register_stanza_plugin(Message, NoStore)
|
||||
register_stanza_plugin(Message, NoPermanentStore)
|
||||
register_stanza_plugin(Message, NoCopy)
|
||||
@@ -1,30 +0,0 @@
|
||||
"""
|
||||
slixmpp: The Slick XMPP Library
|
||||
Implementation of Message Processing Hints
|
||||
http://xmpp.org/extensions/xep-0334.html
|
||||
This file is part of slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.xmlstream import ElementBase
|
||||
|
||||
class Store(ElementBase):
|
||||
name = 'store'
|
||||
plugin_attrib = 'store'
|
||||
namespace = 'urn:xmpp:hints'
|
||||
|
||||
class NoPermanentStore(ElementBase):
|
||||
name = 'no-permanent-store'
|
||||
plugin_attrib = 'no-permanent-store'
|
||||
namespace = 'urn:xmpp:hints'
|
||||
|
||||
class NoStore(ElementBase):
|
||||
name = 'no-store'
|
||||
plugin_attrib = 'no-store'
|
||||
namespace = 'urn:xmpp:hints'
|
||||
|
||||
class NoCopy(ElementBase):
|
||||
name = 'no-copy'
|
||||
plugin_attrib = 'no-copy'
|
||||
namespace = 'urn:xmpp:hints'
|
||||
@@ -1,15 +0,0 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.plugins.base import register_plugin
|
||||
|
||||
from slixmpp.plugins.xep_0352.stanza import Active, Inactive, ClientStateIndication
|
||||
from slixmpp.plugins.xep_0352.csi import XEP_0352
|
||||
|
||||
|
||||
register_plugin(XEP_0352)
|
||||
@@ -1,76 +0,0 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp.stanza import StreamFeatures
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.plugins.base import BasePlugin
|
||||
from slixmpp.plugins.xep_0352 import stanza, Active, Inactive, ClientStateIndication
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0352(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0352: Client State Indication
|
||||
"""
|
||||
|
||||
name = 'xep_0352'
|
||||
description = 'XEP-0352: Client State Indication'
|
||||
dependencies = set()
|
||||
stanza = stanza
|
||||
default_config = {
|
||||
"order": 12000,
|
||||
}
|
||||
|
||||
def plugin_init(self):
|
||||
"""Start the XEP-0352 plugin."""
|
||||
|
||||
self.enabled = False
|
||||
|
||||
register_stanza_plugin(StreamFeatures, ClientStateIndication)
|
||||
self.xmpp.register_stanza(stanza.Active)
|
||||
self.xmpp.register_stanza(stanza.Inactive)
|
||||
|
||||
self.xmpp.register_feature('csi',
|
||||
self._handle_csi_feature,
|
||||
restart=False,
|
||||
order=self.order)
|
||||
|
||||
|
||||
def plugin_end(self):
|
||||
if self.xmpp.is_component:
|
||||
return
|
||||
|
||||
self.xmpp.unregister_feature('csi', self.order)
|
||||
self.xmpp.remove_stanza(stanza.Active)
|
||||
self.xmpp.remove_stanza(stanza.Inactive)
|
||||
|
||||
def send_active(self):
|
||||
"""Send an 'active' state"""
|
||||
if self.enabled:
|
||||
self.xmpp.send_raw(str(stanza.Active(self.xmpp)))
|
||||
|
||||
def send_inactive(self):
|
||||
"""Send an 'active' state"""
|
||||
if self.enabled:
|
||||
self.xmpp.send_raw(str(stanza.Inactive(self.xmpp)))
|
||||
|
||||
def _handle_csi_feature(self, features):
|
||||
"""
|
||||
Enable CSI
|
||||
"""
|
||||
if 'csi' in self.xmpp.features:
|
||||
log.debug('CSI already enabled')
|
||||
return False
|
||||
self.enabled = True
|
||||
self.xmpp.event('csi_enabled', features)
|
||||
return False
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.stanza import Error
|
||||
from slixmpp.xmlstream import ElementBase, StanzaBase
|
||||
|
||||
class ClientStateIndication(ElementBase):
|
||||
name = 'csi'
|
||||
namespace = 'urn:xmpp:csi:0'
|
||||
plugin_attrib = name
|
||||
|
||||
class Active(StanzaBase):
|
||||
name = 'active'
|
||||
plugin_attrib = 'active'
|
||||
namespace = 'urn:xmpp:csi:0'
|
||||
|
||||
def setup(self, xml):
|
||||
StanzaBase.setup(self, xml)
|
||||
self.xml.tag = self.tag_name()
|
||||
|
||||
class Inactive (StanzaBase):
|
||||
name = 'inactive'
|
||||
plugin_attrib = 'inactive'
|
||||
namespace = 'urn:xmpp:csi:0'
|
||||
|
||||
def setup(self, xml):
|
||||
StanzaBase.setup(self, xml)
|
||||
self.xml.tag = self.tag_name()
|
||||
@@ -56,7 +56,6 @@ class RosterNode(object):
|
||||
self.xmpp = xmpp
|
||||
self.jid = jid
|
||||
self.db = db
|
||||
self.ignore_updates = False
|
||||
self.auto_authorize = True
|
||||
self.auto_subscribe = True
|
||||
self.last_status = None
|
||||
|
||||
17
slixmpp/stanza/nick.py
Normal file
17
slixmpp/stanza/nick.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
# The nickname stanza has been moved to its own plugin, but the existing
|
||||
# references are kept for backwards compatibility.
|
||||
|
||||
from slixmpp.stanza import Message, Presence
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.plugins.xep_0172 import UserNick as Nick
|
||||
|
||||
register_stanza_plugin(Message, Nick)
|
||||
register_stanza_plugin(Presence, Nick)
|
||||
@@ -76,6 +76,12 @@ class Presence(RootStanza):
|
||||
if self.stream is not None and self.stream.use_presence_ids:
|
||||
self['id'] = self.stream.new_id()
|
||||
|
||||
def exception(self, e):
|
||||
"""
|
||||
Override exception passback for presence.
|
||||
"""
|
||||
pass
|
||||
|
||||
def set_show(self, show):
|
||||
"""
|
||||
Set the value of the <show> element.
|
||||
|
||||
@@ -340,6 +340,9 @@ class SlixTest(unittest.TestCase):
|
||||
self.xmpp.default_lang = None
|
||||
self.xmpp.peer_default_lang = None
|
||||
|
||||
# Simulate connecting for mock sockets.
|
||||
self.xmpp.auto_reconnect = False
|
||||
|
||||
# Must have the stream header ready for xmpp.process() to work.
|
||||
if not header:
|
||||
header = self.xmpp.stream_header
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import builtins
|
||||
import sys
|
||||
import hashlib
|
||||
|
||||
@@ -23,6 +22,7 @@ def bytes(text):
|
||||
if text is None:
|
||||
return b''
|
||||
|
||||
import builtins
|
||||
if isinstance(text, builtins.bytes):
|
||||
# We already have bytes, so do nothing
|
||||
return text
|
||||
@@ -80,9 +80,10 @@ def XOR(x, y):
|
||||
:param bytes y: A byte string
|
||||
:rtype: bytes
|
||||
"""
|
||||
# This operation is faster with a list comprehension than with a
|
||||
# generator, as of 2016 on python 3.5.
|
||||
return builtins.bytes([a ^ b for a, b in zip(x, y)])
|
||||
result = b''
|
||||
for a, b in zip(x, y):
|
||||
result += bytes([a ^ b])
|
||||
return result
|
||||
|
||||
|
||||
def hash(name):
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
# We don't want to have to import the entire library
|
||||
# just to get the version info for setup.py
|
||||
|
||||
__version__ = '1.1'
|
||||
__version_info__ = (1, 1)
|
||||
__version__ = '1.0'
|
||||
__version_info__ = (1, 0)
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
"""
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
from asyncio import Queue, wait_for, TimeoutError
|
||||
from queue import Queue, Empty
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.xmlstream.handler.base import BaseHandler
|
||||
|
||||
|
||||
@@ -44,13 +42,12 @@ class Waiter(BaseHandler):
|
||||
:param payload: The matched
|
||||
:class:`~slixmpp.xmlstream.stanzabase.ElementBase` object.
|
||||
"""
|
||||
self._payload.put_nowait(payload)
|
||||
self._payload.put(payload)
|
||||
|
||||
def run(self, payload):
|
||||
"""Do not process this handler during the main event loop."""
|
||||
pass
|
||||
|
||||
@asyncio.coroutine
|
||||
def wait(self, timeout=None):
|
||||
"""Block an event handler while waiting for a stanza to arrive.
|
||||
|
||||
@@ -66,13 +63,18 @@ class Waiter(BaseHandler):
|
||||
value.
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = slixmpp.xmlstream.RESPONSE_TIMEOUT
|
||||
timeout = self.stream().response_timeout
|
||||
|
||||
stanza = None
|
||||
try:
|
||||
stanza = yield from self._payload.get()
|
||||
except TimeoutError:
|
||||
log.warning("Timed out waiting for %s", self.name)
|
||||
elapsed_time = 0
|
||||
stanza = False
|
||||
while elapsed_time < timeout and not self.stream().stop.is_set():
|
||||
try:
|
||||
stanza = self._payload.get(True, 1)
|
||||
break
|
||||
except Empty:
|
||||
elapsed_time += 1
|
||||
if elapsed_time >= timeout:
|
||||
log.warning("Timed out waiting for %s", self.name)
|
||||
self.stream().remove_handler(self.name)
|
||||
return stanza
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ def get_AAAA(host, resolver=None, use_aiodns=True, loop=None):
|
||||
except Exception as e:
|
||||
log.debug('DNS: Exception while querying for %s AAAA records: %s', host, e)
|
||||
recs = []
|
||||
return [rec.host for rec in recs]
|
||||
return recs
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_SRV(host, port, service, proto='tcp', resolver=None, use_aiodns=True):
|
||||
|
||||
@@ -379,6 +379,20 @@ class ElementBase(object):
|
||||
#: .. versionadded:: 1.0-Beta5
|
||||
plugin_iterables = set()
|
||||
|
||||
#: A deprecated version of :attr:`plugin_iterables` that remains
|
||||
#: for backward compatibility. It required a parent stanza to
|
||||
#: know beforehand what stanza classes would be iterable::
|
||||
#:
|
||||
#: class DiscoItem(ElementBase):
|
||||
#: ...
|
||||
#:
|
||||
#: class DiscoInfo(ElementBase):
|
||||
#: subitem = (DiscoItem, )
|
||||
#: ...
|
||||
#:
|
||||
#: .. deprecated:: 1.0-Beta5
|
||||
subitem = set()
|
||||
|
||||
#: The default XML namespace: ``http://www.w3.org/XML/1998/namespace``.
|
||||
xml_ns = XML_NS
|
||||
|
||||
@@ -412,6 +426,10 @@ class ElementBase(object):
|
||||
else:
|
||||
self.parent = parent
|
||||
|
||||
if self.subitem is not None:
|
||||
for sub in self.subitem:
|
||||
self.plugin_iterables.add(sub)
|
||||
|
||||
if self.setup(xml):
|
||||
# If we generated our own XML, then everything is ready.
|
||||
return
|
||||
@@ -619,7 +637,7 @@ class ElementBase(object):
|
||||
plugin.values = value
|
||||
return self
|
||||
|
||||
def __getitem__(self, full_attrib):
|
||||
def __getitem__(self, attrib):
|
||||
"""Return the value of a stanza interface using dict-like syntax.
|
||||
|
||||
Example::
|
||||
@@ -646,16 +664,24 @@ class ElementBase(object):
|
||||
8. The plugin named ``'foo'``
|
||||
9. An empty string.
|
||||
|
||||
:param string full_attrib: The name of the requested stanza interface.
|
||||
:param string attrib: The name of the requested stanza interface.
|
||||
"""
|
||||
attrib, lang, *_ = ('%s|' % full_attrib).split('|')
|
||||
full_attrib = attrib
|
||||
attrib_lang = ('%s|' % attrib).split('|')
|
||||
attrib = attrib_lang[0]
|
||||
lang = attrib_lang[1] or None
|
||||
|
||||
kwargs = {'lang': lang} if lang and attrib in self.lang_interfaces else {}
|
||||
kwargs = {}
|
||||
if lang and attrib in self.lang_interfaces:
|
||||
kwargs['lang'] = lang
|
||||
|
||||
kwargs = OrderedDict(kwargs)
|
||||
|
||||
if attrib == 'substanzas':
|
||||
return self.iterables
|
||||
elif attrib in self.interfaces or attrib == 'lang':
|
||||
get_method = "get_%s" % attrib.lower()
|
||||
get_method2 = "get%s" % attrib.title()
|
||||
|
||||
if self.plugin_overrides:
|
||||
name = self.plugin_overrides.get(get_method, None)
|
||||
@@ -668,8 +694,7 @@ class ElementBase(object):
|
||||
|
||||
if hasattr(self, get_method):
|
||||
return getattr(self, get_method)(**kwargs)
|
||||
get_method2 = "get%s" % attrib.title()
|
||||
if hasattr(self, get_method2):
|
||||
elif hasattr(self, get_method2):
|
||||
return getattr(self, get_method2)(**kwargs)
|
||||
else:
|
||||
if attrib in self.sub_interfaces:
|
||||
@@ -1123,6 +1148,36 @@ class ElementBase(object):
|
||||
# Everything matched.
|
||||
return True
|
||||
|
||||
def find(self, xpath):
|
||||
"""Find an XML object in this stanza given an XPath expression.
|
||||
|
||||
Exposes ElementTree interface for backwards compatibility.
|
||||
|
||||
.. note::
|
||||
|
||||
Matching on attribute values is not supported in Python 2.6
|
||||
or Python 3.1
|
||||
|
||||
:param string xpath: An XPath expression matching a single
|
||||
desired element.
|
||||
"""
|
||||
return self.xml.find(xpath)
|
||||
|
||||
def findall(self, xpath):
|
||||
"""Find multiple XML objects in this stanza given an XPath expression.
|
||||
|
||||
Exposes ElementTree interface for backwards compatibility.
|
||||
|
||||
.. note::
|
||||
|
||||
Matching on attribute values is not supported in Python 2.6
|
||||
or Python 3.1.
|
||||
|
||||
:param string xpath: An XPath expression matching multiple
|
||||
desired elements.
|
||||
"""
|
||||
return self.xml.findall(xpath)
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""Return the value of a stanza interface.
|
||||
|
||||
@@ -1250,6 +1305,20 @@ class ElementBase(object):
|
||||
if attr in self.xml.attrib:
|
||||
del self.xml.attrib[attr]
|
||||
|
||||
@property
|
||||
def attrib(self):
|
||||
"""Return the stanza object itself.
|
||||
|
||||
Older implementations of stanza objects used XML objects directly,
|
||||
requiring the use of ``.attrib`` to access attribute values.
|
||||
|
||||
Use of the dictionary syntax with the stanza object itself for
|
||||
accessing stanza interfaces is preferred.
|
||||
|
||||
.. deprecated:: 1.0
|
||||
"""
|
||||
return self
|
||||
|
||||
def _fix_ns(self, xpath, split=False, propagate_ns=True):
|
||||
return fix_ns(xpath, split=split,
|
||||
propagate_ns=propagate_ns,
|
||||
|
||||
@@ -302,8 +302,7 @@ class XMLStream(asyncio.BaseProtocol):
|
||||
yield from self.loop.create_connection(lambda: self,
|
||||
self.address[0],
|
||||
self.address[1],
|
||||
ssl=self.use_ssl,
|
||||
server_hostname=self.default_domain if self.use_ssl else None)
|
||||
ssl=self.use_ssl)
|
||||
except Socket.gaierror as e:
|
||||
self.event('connection_failed',
|
||||
'No DNS record available for %s' % self.default_domain)
|
||||
@@ -349,7 +348,6 @@ class XMLStream(asyncio.BaseProtocol):
|
||||
self.socket = self.transport.get_extra_info("socket")
|
||||
self.init_parser()
|
||||
self.send_raw(self.stream_header)
|
||||
self.dns_answers = None
|
||||
|
||||
def data_received(self, data):
|
||||
"""Called when incoming data is received on the socket.
|
||||
|
||||
@@ -13,7 +13,7 @@ class TestAddresses(SlixTest):
|
||||
def testAddAddress(self):
|
||||
"""Testing adding extended stanza address."""
|
||||
msg = self.Message()
|
||||
msg['addresses'].add_address(atype='to', jid='to@header1.org')
|
||||
msg['addresses'].addAddress(atype='to', jid='to@header1.org')
|
||||
self.check(msg, """
|
||||
<message>
|
||||
<addresses xmlns="http://jabber.org/protocol/address">
|
||||
@@ -23,9 +23,9 @@ class TestAddresses(SlixTest):
|
||||
""")
|
||||
|
||||
msg = self.Message()
|
||||
msg['addresses'].add_address(atype='replyto',
|
||||
jid='replyto@header1.org',
|
||||
desc='Reply address')
|
||||
msg['addresses'].addAddress(atype='replyto',
|
||||
jid='replyto@header1.org',
|
||||
desc='Reply address')
|
||||
self.check(msg, """
|
||||
<message>
|
||||
<addresses xmlns="http://jabber.org/protocol/address">
|
||||
@@ -48,7 +48,7 @@ class TestAddresses(SlixTest):
|
||||
"""
|
||||
|
||||
msg = self.Message()
|
||||
msg['addresses'].set_addresses([
|
||||
msg['addresses'].setAddresses([
|
||||
{'type':'replyto',
|
||||
'jid':'replyto@header1.org',
|
||||
'desc':'Reply address'},
|
||||
@@ -69,9 +69,9 @@ class TestAddresses(SlixTest):
|
||||
"""Testing adding URI attribute to extended stanza address."""
|
||||
|
||||
msg = self.Message()
|
||||
addr = msg['addresses'].add_address(atype='to',
|
||||
jid='to@header1.org',
|
||||
node='foo')
|
||||
addr = msg['addresses'].addAddress(atype='to',
|
||||
jid='to@header1.org',
|
||||
node='foo')
|
||||
self.check(msg, """
|
||||
<message>
|
||||
<addresses xmlns="http://jabber.org/protocol/address">
|
||||
@@ -101,7 +101,7 @@ class TestAddresses(SlixTest):
|
||||
"""
|
||||
|
||||
msg = self.Message()
|
||||
addr = msg['addresses'].add_address(jid='to@header1.org', atype='to')
|
||||
addr = msg['addresses'].addAddress(jid='to@header1.org', atype='to')
|
||||
self.check(msg, xmlstring % '')
|
||||
|
||||
addr['delivered'] = True
|
||||
|
||||
@@ -205,8 +205,8 @@ class TestStreamDisco(SlixTest):
|
||||
handler=dynamic_jid)
|
||||
|
||||
|
||||
self.xmpp['xep_0030'].restore_defaults(jid='tester@localhost',
|
||||
node='testing')
|
||||
self.xmpp['xep_0030'].make_static(jid='tester@localhost',
|
||||
node='testing')
|
||||
|
||||
self.xmpp['xep_0030'].add_identity(jid='tester@localhost',
|
||||
node='testing',
|
||||
@@ -245,8 +245,8 @@ class TestStreamDisco(SlixTest):
|
||||
self.xmpp['xep_0030'].set_node_handler('get_info',
|
||||
handler=dynamic_global)
|
||||
|
||||
self.xmpp['xep_0030'].restore_defaults(jid='user@tester.localhost',
|
||||
node='testing')
|
||||
self.xmpp['xep_0030'].make_static(jid='user@tester.localhost',
|
||||
node='testing')
|
||||
|
||||
self.xmpp['xep_0030'].add_feature(jid='user@tester.localhost',
|
||||
node='testing',
|
||||
@@ -396,8 +396,8 @@ class TestStreamDisco(SlixTest):
|
||||
handler=dynamic_jid)
|
||||
|
||||
|
||||
self.xmpp['xep_0030'].restore_defaults(jid='tester@localhost',
|
||||
node='testing')
|
||||
self.xmpp['xep_0030'].make_static(jid='tester@localhost',
|
||||
node='testing')
|
||||
|
||||
self.xmpp['xep_0030'].add_item(ijid='tester@localhost',
|
||||
node='testing',
|
||||
@@ -436,8 +436,8 @@ class TestStreamDisco(SlixTest):
|
||||
self.xmpp['xep_0030'].set_node_handler('get_items',
|
||||
handler=dynamic_global)
|
||||
|
||||
self.xmpp['xep_0030'].restore_defaults(jid='user@tester.localhost',
|
||||
node='testing')
|
||||
self.xmpp['xep_0030'].make_static(jid='user@tester.localhost',
|
||||
node='testing')
|
||||
|
||||
self.xmpp['xep_0030'].add_item(ijid='user@tester.localhost',
|
||||
node='testing',
|
||||
|
||||
@@ -76,7 +76,7 @@ class TestAdHocCommands(SlixTest):
|
||||
"""Test running a command with no steps."""
|
||||
|
||||
def handle_command(iq, session):
|
||||
form = self.xmpp['xep_0004'].make_form(ftype='result')
|
||||
form = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||
form.addField(var='foo', ftype='text-single',
|
||||
label='Foo', value='bar')
|
||||
|
||||
@@ -122,7 +122,7 @@ class TestAdHocCommands(SlixTest):
|
||||
results.append(form.get_values()['foo'])
|
||||
session['payload'] = None
|
||||
|
||||
form = self.xmpp['xep_0004'].make_form('form')
|
||||
form = self.xmpp['xep_0004'].makeForm('form')
|
||||
form.addField(var='foo', ftype='text-single', label='Foo')
|
||||
|
||||
session['payload'] = form
|
||||
@@ -198,7 +198,7 @@ class TestAdHocCommands(SlixTest):
|
||||
def handle_step1(form, session):
|
||||
results.append(form.get_values()['foo'])
|
||||
|
||||
form = self.xmpp['xep_0004'].make_form('form')
|
||||
form = self.xmpp['xep_0004'].makeForm('form')
|
||||
form.addField(var='bar', ftype='text-single', label='Bar')
|
||||
|
||||
session['payload'] = form
|
||||
@@ -207,7 +207,7 @@ class TestAdHocCommands(SlixTest):
|
||||
|
||||
return session
|
||||
|
||||
form = self.xmpp['xep_0004'].make_form('form')
|
||||
form = self.xmpp['xep_0004'].makeForm('form')
|
||||
form.addField(var='foo', ftype='text-single', label='Foo')
|
||||
|
||||
session['payload'] = form
|
||||
@@ -312,7 +312,7 @@ class TestAdHocCommands(SlixTest):
|
||||
def handle_cancel(iq, session):
|
||||
results.append('canceled')
|
||||
|
||||
form = self.xmpp['xep_0004'].make_form('form')
|
||||
form = self.xmpp['xep_0004'].makeForm('form')
|
||||
form.addField(var='foo', ftype='text-single', label='Foo')
|
||||
|
||||
session['payload'] = form
|
||||
@@ -380,7 +380,7 @@ class TestAdHocCommands(SlixTest):
|
||||
"""Test adding notes to commands."""
|
||||
|
||||
def handle_command(iq, session):
|
||||
form = self.xmpp['xep_0004'].make_form(ftype='result')
|
||||
form = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||
form.addField(var='foo', ftype='text-single',
|
||||
label='Foo', value='bar')
|
||||
|
||||
@@ -431,11 +431,11 @@ class TestAdHocCommands(SlixTest):
|
||||
results.append(form.get_values()['FORM_TYPE'])
|
||||
session['payload'] = None
|
||||
|
||||
form1 = self.xmpp['xep_0004'].make_form('form')
|
||||
form1 = self.xmpp['xep_0004'].makeForm('form')
|
||||
form1.addField(var='FORM_TYPE', ftype='hidden', value='form_1')
|
||||
form1.addField(var='foo', ftype='text-single', label='Foo')
|
||||
|
||||
form2 = self.xmpp['xep_0004'].make_form('form')
|
||||
form2 = self.xmpp['xep_0004'].makeForm('form')
|
||||
form2.addField(var='FORM_TYPE', ftype='hidden', value='form_2')
|
||||
form2.addField(var='foo', ftype='text-single', label='Foo')
|
||||
|
||||
@@ -528,7 +528,7 @@ class TestAdHocCommands(SlixTest):
|
||||
results.append(item)
|
||||
|
||||
def handle_step2(iq, session):
|
||||
form = self.xmpp['xep_0004'].make_form(ftype='submit')
|
||||
form = self.xmpp['xep_0004'].makeForm(ftype='submit')
|
||||
form.addField(var='bar', value='123')
|
||||
|
||||
session['custom_data'].append('baz')
|
||||
@@ -537,7 +537,7 @@ class TestAdHocCommands(SlixTest):
|
||||
self.xmpp['xep_0050'].complete_command(session)
|
||||
|
||||
def handle_step1(iq, session):
|
||||
form = self.xmpp['xep_0004'].make_form(ftype='submit')
|
||||
form = self.xmpp['xep_0004'].makeForm(ftype='submit')
|
||||
form.addField(var='foo', value='42')
|
||||
|
||||
session['custom_data'].append('bar')
|
||||
|
||||
@@ -18,7 +18,7 @@ class TestStreamExtendedDisco(SlixTest):
|
||||
'xep_0004',
|
||||
'xep_0128'])
|
||||
|
||||
form = self.xmpp['xep_0004'].make_form(ftype='result')
|
||||
form = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||
form.addField(var='FORM_TYPE', ftype='hidden', value='testing')
|
||||
|
||||
info_ns = 'http://jabber.org/protocol/disco#info'
|
||||
@@ -57,10 +57,10 @@ class TestStreamExtendedDisco(SlixTest):
|
||||
'xep_0004',
|
||||
'xep_0128'])
|
||||
|
||||
form1 = self.xmpp['xep_0004'].make_form(ftype='result')
|
||||
form1 = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||
form1.addField(var='FORM_TYPE', ftype='hidden', value='testing')
|
||||
|
||||
form2 = self.xmpp['xep_0004'].make_form(ftype='result')
|
||||
form2 = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||
form2.addField(var='FORM_TYPE', ftype='hidden', value='testing_2')
|
||||
|
||||
info_ns = 'http://jabber.org/protocol/disco#info'
|
||||
|
||||
Reference in New Issue
Block a user