Merge branch 'master' into develop
This commit is contained in:
commit
a2c60a4911
4
setup.py
4
setup.py
@ -60,6 +60,7 @@ packages = [ 'sleekxmpp',
|
|||||||
'sleekxmpp/plugins/xep_0009',
|
'sleekxmpp/plugins/xep_0009',
|
||||||
'sleekxmpp/plugins/xep_0009/stanza',
|
'sleekxmpp/plugins/xep_0009/stanza',
|
||||||
'sleekxmpp/plugins/xep_0012',
|
'sleekxmpp/plugins/xep_0012',
|
||||||
|
'sleekxmpp/plugins/xep_0013',
|
||||||
'sleekxmpp/plugins/xep_0016',
|
'sleekxmpp/plugins/xep_0016',
|
||||||
'sleekxmpp/plugins/xep_0027',
|
'sleekxmpp/plugins/xep_0027',
|
||||||
'sleekxmpp/plugins/xep_0030',
|
'sleekxmpp/plugins/xep_0030',
|
||||||
@ -80,6 +81,7 @@ packages = [ 'sleekxmpp',
|
|||||||
'sleekxmpp/plugins/xep_0084',
|
'sleekxmpp/plugins/xep_0084',
|
||||||
'sleekxmpp/plugins/xep_0085',
|
'sleekxmpp/plugins/xep_0085',
|
||||||
'sleekxmpp/plugins/xep_0086',
|
'sleekxmpp/plugins/xep_0086',
|
||||||
|
'sleekxmpp/plugins/xep_0091',
|
||||||
'sleekxmpp/plugins/xep_0092',
|
'sleekxmpp/plugins/xep_0092',
|
||||||
'sleekxmpp/plugins/xep_0107',
|
'sleekxmpp/plugins/xep_0107',
|
||||||
'sleekxmpp/plugins/xep_0108',
|
'sleekxmpp/plugins/xep_0108',
|
||||||
@ -105,6 +107,8 @@ packages = [ 'sleekxmpp',
|
|||||||
'sleekxmpp/plugins/xep_0279',
|
'sleekxmpp/plugins/xep_0279',
|
||||||
'sleekxmpp/plugins/xep_0280',
|
'sleekxmpp/plugins/xep_0280',
|
||||||
'sleekxmpp/plugins/xep_0297',
|
'sleekxmpp/plugins/xep_0297',
|
||||||
|
'sleekxmpp/plugins/xep_0308',
|
||||||
|
'sleekxmpp/plugins/xep_0313',
|
||||||
'sleekxmpp/features',
|
'sleekxmpp/features',
|
||||||
'sleekxmpp/features/feature_mechanisms',
|
'sleekxmpp/features/feature_mechanisms',
|
||||||
'sleekxmpp/features/feature_mechanisms/stanza',
|
'sleekxmpp/features/feature_mechanisms/stanza',
|
||||||
|
@ -114,6 +114,17 @@ class BaseXMPP(XMLStream):
|
|||||||
#: ``'to'`` and ``'from'`` JIDs of stanzas.
|
#: ``'to'`` and ``'from'`` JIDs of stanzas.
|
||||||
self.is_component = False
|
self.is_component = False
|
||||||
|
|
||||||
|
#: Messages may optionally be tagged with ID values. Setting
|
||||||
|
#: :attr:`use_message_ids` to `True` will assign all outgoing
|
||||||
|
#: messages an ID. Some plugin features require enabling
|
||||||
|
#: this option.
|
||||||
|
self.use_message_ids = False
|
||||||
|
|
||||||
|
#: Presence updates may optionally be tagged with ID values.
|
||||||
|
#: Setting :attr:`use_message_ids` to `True` will assign all
|
||||||
|
#: outgoing messages an ID.
|
||||||
|
self.use_presence_ids = False
|
||||||
|
|
||||||
#: The API registry is a way to process callbacks based on
|
#: The API registry is a way to process callbacks based on
|
||||||
#: JID+node combinations. Each callback in the registry is
|
#: JID+node combinations. Each callback in the registry is
|
||||||
#: marked with:
|
#: marked with:
|
||||||
|
@ -18,6 +18,7 @@ __all__ = [
|
|||||||
'xep_0004', # Data Forms
|
'xep_0004', # Data Forms
|
||||||
'xep_0009', # Jabber-RPC
|
'xep_0009', # Jabber-RPC
|
||||||
'xep_0012', # Last Activity
|
'xep_0012', # Last Activity
|
||||||
|
'xep_0013', # Flexible Offline Message Retrieval
|
||||||
'xep_0016', # Privacy Lists
|
'xep_0016', # Privacy Lists
|
||||||
'xep_0027', # Current Jabber OpenPGP Usage
|
'xep_0027', # Current Jabber OpenPGP Usage
|
||||||
'xep_0030', # Service Discovery
|
'xep_0030', # Service Discovery
|
||||||
@ -38,6 +39,7 @@ __all__ = [
|
|||||||
'xep_0084', # User Avatar
|
'xep_0084', # User Avatar
|
||||||
'xep_0085', # Chat State Notifications
|
'xep_0085', # Chat State Notifications
|
||||||
'xep_0086', # Legacy Error Codes
|
'xep_0086', # Legacy Error Codes
|
||||||
|
'xep_0091', # Legacy Delayed Delivery
|
||||||
'xep_0092', # Software Version
|
'xep_0092', # Software Version
|
||||||
'xep_0106', # JID Escaping
|
'xep_0106', # JID Escaping
|
||||||
'xep_0107', # User Mood
|
'xep_0107', # User Mood
|
||||||
@ -72,4 +74,6 @@ __all__ = [
|
|||||||
'xep_0280', # Message Carbons
|
'xep_0280', # Message Carbons
|
||||||
'xep_0297', # Stanza Forwarding
|
'xep_0297', # Stanza Forwarding
|
||||||
'xep_0302', # XMPP Compliance Suites 2012
|
'xep_0302', # XMPP Compliance Suites 2012
|
||||||
|
'xep_0308', # Last Message Correction
|
||||||
|
'xep_0313', # Message Archive Management
|
||||||
]
|
]
|
||||||
|
15
sleekxmpp/plugins/xep_0013/__init__.py
Normal file
15
sleekxmpp/plugins/xep_0013/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.base import register_plugin
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0013.stanza import Offline
|
||||||
|
from sleekxmpp.plugins.xep_0013.offline import XEP_0013
|
||||||
|
|
||||||
|
|
||||||
|
register_plugin(XEP_0013)
|
134
sleekxmpp/plugins/xep_0013/offline.py
Normal file
134
sleekxmpp/plugins/xep_0013/offline.py
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
from sleekxmpp.stanza import Message, Iq
|
||||||
|
from sleekxmpp.exceptions import XMPPError
|
||||||
|
from sleekxmpp.xmlstream.handler import Collector
|
||||||
|
from sleekxmpp.xmlstream.matcher import StanzaPath
|
||||||
|
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||||
|
from sleekxmpp.plugins import BasePlugin
|
||||||
|
from sleekxmpp.plugins.xep_0013 import stanza
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class XEP_0013(BasePlugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0013 Flexible Offline Message Retrieval
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'xep_0013'
|
||||||
|
description = 'XEP-0013: Flexible Offline Message Retrieval'
|
||||||
|
dependencies = set(['xep_0030'])
|
||||||
|
stanza = stanza
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
register_stanza_plugin(Iq, stanza.Offline)
|
||||||
|
register_stanza_plugin(Message, stanza.Offline)
|
||||||
|
|
||||||
|
def get_count(self, **kwargs):
|
||||||
|
return self.xmpp['xep_0030'].get_info(
|
||||||
|
node='http://jabber.org/protocol/offline',
|
||||||
|
local=False,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def get_headers(self, **kwargs):
|
||||||
|
return self.xmpp['xep_0030'].get_items(
|
||||||
|
node='http://jabber.org/protocol/offline',
|
||||||
|
local=False,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def view(self, nodes, ifrom=None, block=True, timeout=None, callback=None):
|
||||||
|
if not isinstance(nodes, (list, set)):
|
||||||
|
nodes = [nodes]
|
||||||
|
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
iq['type'] = 'get'
|
||||||
|
iq['from'] = ifrom
|
||||||
|
offline = iq['offline']
|
||||||
|
for node in nodes:
|
||||||
|
item = stanza.Item()
|
||||||
|
item['node'] = node
|
||||||
|
item['action'] = 'view'
|
||||||
|
offline.append(item)
|
||||||
|
|
||||||
|
collector = Collector(
|
||||||
|
'Offline_Results_%s' % iq['id'],
|
||||||
|
StanzaPath('message/offline'))
|
||||||
|
self.xmpp.register_handler(collector)
|
||||||
|
|
||||||
|
if not block and callback is not None:
|
||||||
|
def wrapped_cb(iq):
|
||||||
|
results = collector.stop()
|
||||||
|
if iq['type'] == 'result':
|
||||||
|
iq['offline']['results'] = results
|
||||||
|
callback(iq)
|
||||||
|
return iq.send(block=block, timeout=timeout, callback=wrapped_cb)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
resp = iq.send(block=block, timeout=timeout, callback=callback)
|
||||||
|
resp['offline']['results'] = collector.stop()
|
||||||
|
return resp
|
||||||
|
except XMPPError as e:
|
||||||
|
collector.stop()
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def remove(self, nodes, ifrom=None, block=True, timeout=None, callback=None):
|
||||||
|
if not isinstance(nodes, (list, set)):
|
||||||
|
nodes = [nodes]
|
||||||
|
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
iq['type'] = 'set'
|
||||||
|
iq['from'] = ifrom
|
||||||
|
offline = iq['offline']
|
||||||
|
for node in nodes:
|
||||||
|
item = stanza.Item()
|
||||||
|
item['node'] = node
|
||||||
|
item['action'] = 'remove'
|
||||||
|
offline.append(item)
|
||||||
|
|
||||||
|
return iq.send(block=block, timeout=timeout, callback=callback)
|
||||||
|
|
||||||
|
def fetch(self, ifrom=None, block=True, timeout=None, callback=None):
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
iq['type'] = 'set'
|
||||||
|
iq['from'] = ifrom
|
||||||
|
iq['offline']['fetch'] = True
|
||||||
|
|
||||||
|
collector = Collector(
|
||||||
|
'Offline_Results_%s' % iq['id'],
|
||||||
|
StanzaPath('message/offline'))
|
||||||
|
self.xmpp.register_handler(collector)
|
||||||
|
|
||||||
|
if not block and callback is not None:
|
||||||
|
def wrapped_cb(iq):
|
||||||
|
results = collector.stop()
|
||||||
|
if iq['type'] == 'result':
|
||||||
|
iq['offline']['results'] = results
|
||||||
|
callback(iq)
|
||||||
|
return iq.send(block=block, timeout=timeout, callback=wrapped_cb)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
resp = iq.send(block=block, timeout=timeout, callback=callback)
|
||||||
|
resp['offline']['results'] = collector.stop()
|
||||||
|
return resp
|
||||||
|
except XMPPError as e:
|
||||||
|
collector.stop()
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def purge(self, ifrom=None, block=True, timeout=None, callback=None):
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
iq['type'] = 'set'
|
||||||
|
iq['from'] = ifrom
|
||||||
|
iq['offline']['purge'] = True
|
||||||
|
return iq.send(block=block, timeout=timeout, callback=callback)
|
53
sleekxmpp/plugins/xep_0013/stanza.py
Normal file
53
sleekxmpp/plugins/xep_0013/stanza.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.jid import JID
|
||||||
|
from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin
|
||||||
|
|
||||||
|
|
||||||
|
class Offline(ElementBase):
|
||||||
|
name = 'offline'
|
||||||
|
namespace = 'http://jabber.org/protocol/offline'
|
||||||
|
plugin_attrib = 'offline'
|
||||||
|
interfaces = set(['fetch', 'purge', 'results'])
|
||||||
|
bool_interfaces = interfaces
|
||||||
|
|
||||||
|
def setup(self, xml=None):
|
||||||
|
ElementBase.setup(self, xml)
|
||||||
|
self._results = []
|
||||||
|
|
||||||
|
# The results interface is meant only as an easy
|
||||||
|
# way to access the set of collected message responses
|
||||||
|
# from the query.
|
||||||
|
|
||||||
|
def get_results(self):
|
||||||
|
return self._results
|
||||||
|
|
||||||
|
def set_results(self, values):
|
||||||
|
self._results = values
|
||||||
|
|
||||||
|
def del_results(self):
|
||||||
|
self._results = []
|
||||||
|
|
||||||
|
|
||||||
|
class Item(ElementBase):
|
||||||
|
name = 'item'
|
||||||
|
namespace = 'http://jabber.org/protocol/offline'
|
||||||
|
plugin_attrib = 'item'
|
||||||
|
interfaces = set(['action', 'node', 'jid'])
|
||||||
|
|
||||||
|
actions = set(['view', 'remove'])
|
||||||
|
|
||||||
|
def get_jid(self):
|
||||||
|
return JID(self._get_attr('jid'))
|
||||||
|
|
||||||
|
def set_jid(self, value):
|
||||||
|
self._set_attr('jid', str(value))
|
||||||
|
|
||||||
|
|
||||||
|
register_stanza_plugin(Offline, Item, iterable=True)
|
@ -288,7 +288,7 @@ class XEP_0030(BasePlugin):
|
|||||||
'cached': cached}
|
'cached': cached}
|
||||||
return self.api['has_identity'](jid, node, ifrom, data)
|
return self.api['has_identity'](jid, node, ifrom, data)
|
||||||
|
|
||||||
def get_info(self, jid=None, node=None, local=False,
|
def get_info(self, jid=None, node=None, local=None,
|
||||||
cached=None, **kwargs):
|
cached=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Retrieve the disco#info results from a given JID/node combination.
|
Retrieve the disco#info results from a given JID/node combination.
|
||||||
@ -325,6 +325,7 @@ class XEP_0030(BasePlugin):
|
|||||||
received instead of blocking and waiting for
|
received instead of blocking and waiting for
|
||||||
the reply.
|
the reply.
|
||||||
"""
|
"""
|
||||||
|
if local is None:
|
||||||
if jid is not None and not isinstance(jid, JID):
|
if jid is not None and not isinstance(jid, JID):
|
||||||
jid = JID(jid)
|
jid = JID(jid)
|
||||||
if self.xmpp.is_component:
|
if self.xmpp.is_component:
|
||||||
@ -405,7 +406,7 @@ class XEP_0030(BasePlugin):
|
|||||||
the XEP-0059 plugin, if the plugin is loaded.
|
the XEP-0059 plugin, if the plugin is loaded.
|
||||||
Otherwise the parameter is ignored.
|
Otherwise the parameter is ignored.
|
||||||
"""
|
"""
|
||||||
if local or jid is None:
|
if local or local is None and jid is None:
|
||||||
items = self.api['get_items'](jid, node,
|
items = self.api['get_items'](jid, node,
|
||||||
kwargs.get('ifrom', None),
|
kwargs.get('ifrom', None),
|
||||||
kwargs)
|
kwargs)
|
||||||
|
@ -25,11 +25,14 @@ class ResultIterator():
|
|||||||
An iterator for Result Set Managment
|
An iterator for Result Set Managment
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, query, interface, amount=10, start=None, reverse=False):
|
def __init__(self, query, interface, results='substanzas', amount=10,
|
||||||
|
start=None, reverse=False):
|
||||||
"""
|
"""
|
||||||
Arguments:
|
Arguments:
|
||||||
query -- The template query
|
query -- The template query
|
||||||
interface -- The substanza of the query, for example disco_items
|
interface -- The substanza of the query, for example disco_items
|
||||||
|
results -- The query stanza's interface which provides a
|
||||||
|
countable list of query results.
|
||||||
amount -- The max amounts of items to request per iteration
|
amount -- The max amounts of items to request per iteration
|
||||||
start -- From which item id to start
|
start -- From which item id to start
|
||||||
reverse -- If True, page backwards through the results
|
reverse -- If True, page backwards through the results
|
||||||
@ -46,6 +49,7 @@ class ResultIterator():
|
|||||||
self.amount = amount
|
self.amount = amount
|
||||||
self.start = start
|
self.start = start
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
|
self.results = results
|
||||||
self.reverse = reverse
|
self.reverse = reverse
|
||||||
self._stop = False
|
self._stop = False
|
||||||
|
|
||||||
@ -85,7 +89,7 @@ class ResultIterator():
|
|||||||
r[self.interface]['rsm']['first_index']:
|
r[self.interface]['rsm']['first_index']:
|
||||||
count = int(r[self.interface]['rsm']['count'])
|
count = int(r[self.interface]['rsm']['count'])
|
||||||
first = int(r[self.interface]['rsm']['first_index'])
|
first = int(r[self.interface]['rsm']['first_index'])
|
||||||
num_items = len(r[self.interface]['substanzas'])
|
num_items = len(r[self.interface][self.results])
|
||||||
if first + num_items == count:
|
if first + num_items == count:
|
||||||
self._stop = True
|
self._stop = True
|
||||||
|
|
||||||
@ -123,7 +127,7 @@ class XEP_0059(BasePlugin):
|
|||||||
def session_bind(self, jid):
|
def session_bind(self, jid):
|
||||||
self.xmpp['xep_0030'].add_feature(Set.namespace)
|
self.xmpp['xep_0030'].add_feature(Set.namespace)
|
||||||
|
|
||||||
def iterate(self, stanza, interface):
|
def iterate(self, stanza, interface, results='substanzas'):
|
||||||
"""
|
"""
|
||||||
Create a new result set iterator for a given stanza query.
|
Create a new result set iterator for a given stanza query.
|
||||||
|
|
||||||
@ -135,5 +139,7 @@ class XEP_0059(BasePlugin):
|
|||||||
result set management stanza should be
|
result set management stanza should be
|
||||||
appended. For example, for disco#items queries
|
appended. For example, for disco#items queries
|
||||||
the interface 'disco_items' should be used.
|
the interface 'disco_items' should be used.
|
||||||
|
results -- The name of the interface containing the
|
||||||
|
query results (typically just 'substanzas').
|
||||||
"""
|
"""
|
||||||
return ResultIterator(stanza, interface)
|
return ResultIterator(stanza, interface, results)
|
||||||
|
16
sleekxmpp/plugins/xep_0091/__init__.py
Normal file
16
sleekxmpp/plugins/xep_0091/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.base import register_plugin
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0091 import stanza
|
||||||
|
from sleekxmpp.plugins.xep_0091.stanza import LegacyDelay
|
||||||
|
from sleekxmpp.plugins.xep_0091.legacy_delay import XEP_0091
|
||||||
|
|
||||||
|
|
||||||
|
register_plugin(XEP_0091)
|
29
sleekxmpp/plugins/xep_0091/legacy_delay.py
Normal file
29
sleekxmpp/plugins/xep_0091/legacy_delay.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from sleekxmpp.stanza import Message, Presence
|
||||||
|
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||||
|
from sleekxmpp.plugins import BasePlugin
|
||||||
|
from sleekxmpp.plugins.xep_0091 import stanza
|
||||||
|
|
||||||
|
|
||||||
|
class XEP_0091(BasePlugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0091: Legacy Delayed Delivery
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'xep_0091'
|
||||||
|
description = 'XEP-0091: Legacy Delayed Delivery'
|
||||||
|
dependencies = set()
|
||||||
|
stanza = stanza
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
register_stanza_plugin(Message, stanza.LegacyDelay)
|
||||||
|
register_stanza_plugin(Presence, stanza.LegacyDelay)
|
46
sleekxmpp/plugins/xep_0091/stanza.py
Normal file
46
sleekxmpp/plugins/xep_0091/stanza.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
|
from sleekxmpp.jid import JID
|
||||||
|
from sleekxmpp.xmlstream import ElementBase
|
||||||
|
from sleekxmpp.plugins import xep_0082
|
||||||
|
|
||||||
|
|
||||||
|
class LegacyDelay(ElementBase):
|
||||||
|
|
||||||
|
name = 'x'
|
||||||
|
namespace = 'jabber:x:delay'
|
||||||
|
plugin_attrib = 'legacy_delay'
|
||||||
|
interfaces = set(('from', 'stamp', 'text'))
|
||||||
|
|
||||||
|
def get_from(self):
|
||||||
|
return JID(self._get_attr('from'))
|
||||||
|
|
||||||
|
def set_from(self, value):
|
||||||
|
self._set_attr('from', str(value))
|
||||||
|
|
||||||
|
def get_stamp(self):
|
||||||
|
timestamp = self._get_attr('stamp')
|
||||||
|
return xep_0082.parse('%sZ' % timestamp)
|
||||||
|
|
||||||
|
def set_stamp(self, value):
|
||||||
|
if isinstance(value, dt.datetime):
|
||||||
|
value = value.astimezone(xep_0082.tzutc)
|
||||||
|
value = xep_0082.format_datetime(value)
|
||||||
|
self._set_attr('stamp', value[0:19].replace('-', ''))
|
||||||
|
|
||||||
|
def get_text(self):
|
||||||
|
return self.xml.text
|
||||||
|
|
||||||
|
def set_text(self, value):
|
||||||
|
self.xml.text = value
|
||||||
|
|
||||||
|
def del_text(self):
|
||||||
|
self.xml.text = ''
|
@ -14,14 +14,17 @@ from sleekxmpp.plugins import xep_0082
|
|||||||
|
|
||||||
class Delay(ElementBase):
|
class Delay(ElementBase):
|
||||||
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
name = 'delay'
|
name = 'delay'
|
||||||
namespace = 'urn:xmpp:delay'
|
namespace = 'urn:xmpp:delay'
|
||||||
plugin_attrib = 'delay'
|
plugin_attrib = 'delay'
|
||||||
interfaces = set(('from', 'stamp', 'text'))
|
interfaces = set(('from', 'stamp', 'text'))
|
||||||
|
|
||||||
|
def get_from(self):
|
||||||
|
return JID(self._get_attr('from'))
|
||||||
|
|
||||||
|
def set_from(self, value):
|
||||||
|
self._set_attr('from', str(value))
|
||||||
|
|
||||||
def get_stamp(self):
|
def get_stamp(self):
|
||||||
timestamp = self._get_attr('stamp')
|
timestamp = self._get_attr('stamp')
|
||||||
return xep_0082.parse(timestamp)
|
return xep_0082.parse(timestamp)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
SleekXMPP: The Sleek XMPP Library
|
SleekXMPP: The Sleek XMPP Library
|
||||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
This file is part of SleekXMPP.
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
See the file LICENSE for copying permissio
|
See the file LICENSE for copying permissio
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
SleekXMPP: The Sleek XMPP Library
|
SleekXMPP: The Sleek XMPP Library
|
||||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
This file is part of SleekXMPP.
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
See the file LICENSE for copying permissio
|
See the file LICENSE for copying permissio
|
||||||
|
@ -26,9 +26,14 @@ class XEP_0297(BasePlugin):
|
|||||||
|
|
||||||
def plugin_init(self):
|
def plugin_init(self):
|
||||||
register_stanza_plugin(Message, Forwarded)
|
register_stanza_plugin(Message, Forwarded)
|
||||||
register_stanza_plugin(Forwarded, Message)
|
|
||||||
register_stanza_plugin(Forwarded, Presence)
|
# While these are marked as iterable, that is just for
|
||||||
register_stanza_plugin(Forwarded, Iq)
|
# making it easier to extract the forwarded stanza. There
|
||||||
|
# still can be only a single forwarded stanza.
|
||||||
|
register_stanza_plugin(Forwarded, Message, iterable=True)
|
||||||
|
register_stanza_plugin(Forwarded, Presence, iterable=True)
|
||||||
|
register_stanza_plugin(Forwarded, Iq, iterable=True)
|
||||||
|
|
||||||
register_stanza_plugin(Forwarded, self.xmpp['xep_0203'].stanza.Delay)
|
register_stanza_plugin(Forwarded, self.xmpp['xep_0203'].stanza.Delay)
|
||||||
|
|
||||||
self.xmpp.register_handler(
|
self.xmpp.register_handler(
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
See the file LICENSE for copying permission.
|
See the file LICENSE for copying permission.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.stanza import Message, Presence, Iq
|
||||||
from sleekxmpp.xmlstream import ElementBase
|
from sleekxmpp.xmlstream import ElementBase
|
||||||
|
|
||||||
|
|
||||||
@ -16,12 +17,9 @@ class Forwarded(ElementBase):
|
|||||||
interfaces = set(['stanza'])
|
interfaces = set(['stanza'])
|
||||||
|
|
||||||
def get_stanza(self):
|
def get_stanza(self):
|
||||||
if self.xml.find('{jabber:client}message') is not None:
|
for stanza in self:
|
||||||
return self['message']
|
if isinstance(stanza, (Message, Presence, Iq)):
|
||||||
elif self.xml.find('{jabber:client}presence') is not None:
|
return stanza
|
||||||
return self['presence']
|
|
||||||
elif self.xml.find('{jabber:client}iq') is not None:
|
|
||||||
return self['iq']
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def set_stanza(self, value):
|
def set_stanza(self, value):
|
||||||
@ -29,6 +27,10 @@ class Forwarded(ElementBase):
|
|||||||
self.append(value)
|
self.append(value)
|
||||||
|
|
||||||
def del_stanza(self):
|
def del_stanza(self):
|
||||||
del self['message']
|
found_stanzas = []
|
||||||
del self['presence']
|
for stanza in self:
|
||||||
del self['iq']
|
if isinstance(stanza, (Message, Presence, Iq)):
|
||||||
|
found_stanzas.append(stanza)
|
||||||
|
for stanza in found_stanzas:
|
||||||
|
self.iterables.remove(stanza)
|
||||||
|
self.xml.remove(stanza.xml)
|
||||||
|
15
sleekxmpp/plugins/xep_0308/__init__.py
Normal file
15
sleekxmpp/plugins/xep_0308/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.base import register_plugin
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0308.stanza import Replace
|
||||||
|
from sleekxmpp.plugins.xep_0308.correction import XEP_0308
|
||||||
|
|
||||||
|
|
||||||
|
register_plugin(XEP_0308)
|
52
sleekxmpp/plugins/xep_0308/correction.py
Normal file
52
sleekxmpp/plugins/xep_0308/correction.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
from sleekxmpp.stanza import Message
|
||||||
|
from sleekxmpp.xmlstream.handler import Callback
|
||||||
|
from sleekxmpp.xmlstream.matcher import StanzaPath
|
||||||
|
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||||
|
from sleekxmpp.plugins import BasePlugin
|
||||||
|
from sleekxmpp.plugins.xep_0308 import stanza, Replace
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class XEP_0308(BasePlugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0308 Last Message Correction
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'xep_0308'
|
||||||
|
description = 'XEP-0308: Last Message Correction'
|
||||||
|
dependencies = set(['xep_0030'])
|
||||||
|
stanza = stanza
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
self.xmpp.register_handler(
|
||||||
|
Callback('Message Correction',
|
||||||
|
StanzaPath('message/replace'),
|
||||||
|
self._handle_correction))
|
||||||
|
|
||||||
|
register_stanza_plugin(Message, Replace)
|
||||||
|
|
||||||
|
self.xmpp.use_message_ids = True
|
||||||
|
|
||||||
|
def plugin_end(self):
|
||||||
|
self.xmpp.remove_handler('Message Correction')
|
||||||
|
self.xmpp.plugin['xep_0030'].del_feature(feature=Replace.namespace)
|
||||||
|
|
||||||
|
def session_bind(self, jid):
|
||||||
|
self.xmpp.plugin['xep_0030'].add_feature(Replace.namespace)
|
||||||
|
|
||||||
|
def _handle_correction(self, msg):
|
||||||
|
self.xmpp.event('message_correction', msg)
|
16
sleekxmpp/plugins/xep_0308/stanza.py
Normal file
16
sleekxmpp/plugins/xep_0308/stanza.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.xmlstream import ElementBase
|
||||||
|
|
||||||
|
|
||||||
|
class Replace(ElementBase):
|
||||||
|
name = 'replace'
|
||||||
|
namespace = 'urn:xmpp:message-correct:0'
|
||||||
|
plugin_attrib = 'replace'
|
||||||
|
interfaces = set(['id'])
|
15
sleekxmpp/plugins/xep_0313/__init__.py
Normal file
15
sleekxmpp/plugins/xep_0313/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.base import register_plugin
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0313.stanza import Result, MAM, Preferences
|
||||||
|
from sleekxmpp.plugins.xep_0313.mam import XEP_0313
|
||||||
|
|
||||||
|
|
||||||
|
register_plugin(XEP_0313)
|
92
sleekxmpp/plugins/xep_0313/mam.py
Normal file
92
sleekxmpp/plugins/xep_0313/mam.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
from sleekxmpp.stanza import Message, Iq
|
||||||
|
from sleekxmpp.exceptions import XMPPError
|
||||||
|
from sleekxmpp.xmlstream.handler import Collector
|
||||||
|
from sleekxmpp.xmlstream.matcher import StanzaPath
|
||||||
|
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||||
|
from sleekxmpp.plugins import BasePlugin
|
||||||
|
from sleekxmpp.plugins.xep_0313 import stanza
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class XEP_0313(BasePlugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0313 Message Archive Management
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'xep_0313'
|
||||||
|
description = 'XEP-0313: Message Archive Management'
|
||||||
|
dependencies = set(['xep_0030', 'xep_0050', 'xep_0059', 'xep_0297'])
|
||||||
|
stanza = stanza
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
register_stanza_plugin(Iq, stanza.MAM)
|
||||||
|
register_stanza_plugin(Iq, stanza.Preferences)
|
||||||
|
register_stanza_plugin(Message, stanza.Result)
|
||||||
|
register_stanza_plugin(stanza.MAM, self.xmpp['xep_0059'].stanza.Set)
|
||||||
|
|
||||||
|
def retrieve(self, jid=None, start=None, end=None, with_jid=None, ifrom=None,
|
||||||
|
block=True, timeout=None, callback=None, iterator=False):
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
query_id = iq['id']
|
||||||
|
|
||||||
|
iq['to'] = jid
|
||||||
|
iq['from'] = ifrom
|
||||||
|
iq['type'] = 'get'
|
||||||
|
iq['mam']['queryid'] = query_id
|
||||||
|
iq['mam']['start'] = start
|
||||||
|
iq['mam']['end'] = end
|
||||||
|
iq['mam']['with'] = with_jid
|
||||||
|
|
||||||
|
collector = Collector(
|
||||||
|
'MAM_Results_%s' % query_id,
|
||||||
|
StanzaPath('message/mam_result@queryid=%s' % query_id))
|
||||||
|
self.xmpp.register_handler(collector)
|
||||||
|
|
||||||
|
if iterator:
|
||||||
|
return self.xmpp['xep_0059'].iterate(iq, 'mam', 'results')
|
||||||
|
elif not block and callback is not None:
|
||||||
|
def wrapped_cb(iq):
|
||||||
|
results = collector.stop()
|
||||||
|
if iq['type'] == 'result':
|
||||||
|
iq['mam']['results'] = results
|
||||||
|
callback(iq)
|
||||||
|
return iq.send(block=block, timeout=timeout, callback=wrapped_cb)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
resp = iq.send(block=block, timeout=timeout, callback=callback)
|
||||||
|
resp['mam']['results'] = collector.stop()
|
||||||
|
return resp
|
||||||
|
except XMPPError as e:
|
||||||
|
collector.stop()
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def set_preferences(self, jid=None, default=None, always=None, never=None,
|
||||||
|
ifrom=None, block=True, timeout=None, callback=None):
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
iq['type'] = 'set'
|
||||||
|
iq['to'] = jid
|
||||||
|
iq['from'] = ifrom
|
||||||
|
iq['mam_prefs']['default'] = default
|
||||||
|
iq['mam_prefs']['always'] = always
|
||||||
|
iq['mam_prefs']['never'] = never
|
||||||
|
return iq.send(block=block, timeout=timeout, callback=callback)
|
||||||
|
|
||||||
|
def get_configuration_commands(self, jid, **kwargs):
|
||||||
|
return self.xmpp['xep_0030'].get_items(
|
||||||
|
jid=jid,
|
||||||
|
node='urn:xmpp:mam#configure',
|
||||||
|
**kwargs)
|
131
sleekxmpp/plugins/xep_0313/stanza.py
Normal file
131
sleekxmpp/plugins/xep_0313/stanza.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permissio
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
|
from sleekxmpp.jid import JID
|
||||||
|
from sleekxmpp.xmlstream import ElementBase, ET
|
||||||
|
from sleekxmpp.plugins import xep_0082
|
||||||
|
|
||||||
|
|
||||||
|
class MAM(ElementBase):
|
||||||
|
name = 'query'
|
||||||
|
namespace = 'urn:xmpp:mam:tmp'
|
||||||
|
plugin_attrib = 'mam'
|
||||||
|
interfaces = set(['queryid', 'start', 'end', 'with', 'results'])
|
||||||
|
sub_interfaces = set(['start', 'end', 'with'])
|
||||||
|
|
||||||
|
def setup(self, xml=None):
|
||||||
|
ElementBase.setup(self, xml)
|
||||||
|
self._results = []
|
||||||
|
|
||||||
|
def get_start(self):
|
||||||
|
timestamp = self._get_attr('start')
|
||||||
|
return xep_0082.parse(timestamp)
|
||||||
|
|
||||||
|
def set_start(self, value):
|
||||||
|
if isinstance(value, dt.datetime):
|
||||||
|
value = xep_0082.format_datetime(value)
|
||||||
|
self._set_attr('start', value)
|
||||||
|
|
||||||
|
def get_end(self):
|
||||||
|
timestamp = self._get_sub_text('end')
|
||||||
|
return xep_0082.parse(timestamp)
|
||||||
|
|
||||||
|
def set_end(self, value):
|
||||||
|
if isinstance(value, dt.datetime):
|
||||||
|
value = xep_0082.format_datetime(value)
|
||||||
|
self._set_sub_text('end', value)
|
||||||
|
|
||||||
|
def get_with(self):
|
||||||
|
return JID(self._get_sub_text('with'))
|
||||||
|
|
||||||
|
def set_with(self, value):
|
||||||
|
self._set_sub_text('with', str(value))
|
||||||
|
|
||||||
|
# The results interface is meant only as an easy
|
||||||
|
# way to access the set of collected message responses
|
||||||
|
# from the query.
|
||||||
|
|
||||||
|
def get_results(self):
|
||||||
|
return self._results
|
||||||
|
|
||||||
|
def set_results(self, values):
|
||||||
|
self._results = values
|
||||||
|
|
||||||
|
def del_results(self):
|
||||||
|
self._results = []
|
||||||
|
|
||||||
|
|
||||||
|
class Preferences(ElementBase):
|
||||||
|
name = 'prefs'
|
||||||
|
namespace = 'urn:xmpp:mam:tmp'
|
||||||
|
plugin_attrib = 'mam_prefs'
|
||||||
|
interfaces = set(['default', 'always', 'never'])
|
||||||
|
sub_interfaces = set(['always', 'never'])
|
||||||
|
|
||||||
|
def get_always(self):
|
||||||
|
results = set()
|
||||||
|
|
||||||
|
jids = self.xml.findall('{%s}always/{%s}jid' % (
|
||||||
|
self.namespace, self.namespace))
|
||||||
|
|
||||||
|
for jid in jids:
|
||||||
|
results.add(JID(jid.text))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def set_always(self, value):
|
||||||
|
self._set_sub_text('always', '', keep=True)
|
||||||
|
always = self.xml.find('{%s}always' % self.namespace)
|
||||||
|
always.clear()
|
||||||
|
|
||||||
|
if not isinstance(value, (list, set)):
|
||||||
|
value = [value]
|
||||||
|
|
||||||
|
for jid in value:
|
||||||
|
jid_xml = ET.Element('{%s}jid' % self.namespace)
|
||||||
|
jid_xml.text = str(jid)
|
||||||
|
always.append(jid_xml)
|
||||||
|
|
||||||
|
def get_never(self):
|
||||||
|
results = set()
|
||||||
|
|
||||||
|
jids = self.xml.findall('{%s}never/{%s}jid' % (
|
||||||
|
self.namespace, self.namespace))
|
||||||
|
|
||||||
|
for jid in jids:
|
||||||
|
results.add(JID(jid.text))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def set_never(self, value):
|
||||||
|
self._set_sub_text('never', '', keep=True)
|
||||||
|
never = self.xml.find('{%s}never' % self.namespace)
|
||||||
|
never.clear()
|
||||||
|
|
||||||
|
if not isinstance(value, (list, set)):
|
||||||
|
value = [value]
|
||||||
|
|
||||||
|
for jid in value:
|
||||||
|
jid_xml = ET.Element('{%s}jid' % self.namespace)
|
||||||
|
jid_xml.text = str(jid)
|
||||||
|
never.append(jid_xml)
|
||||||
|
|
||||||
|
|
||||||
|
class Result(ElementBase):
|
||||||
|
name = 'result'
|
||||||
|
namespace = 'urn:xmpp:mam:tmp'
|
||||||
|
plugin_attrib = 'mam_result'
|
||||||
|
interfaces = set(['forwarded', 'queryid', 'id'])
|
||||||
|
|
||||||
|
def get_forwarded(self):
|
||||||
|
return self.parent()['forwarded']
|
||||||
|
|
||||||
|
def del_forwarded(self):
|
||||||
|
del self.parent()['forwarded']
|
@ -63,6 +63,17 @@ class Message(RootStanza):
|
|||||||
lang_interfaces = sub_interfaces
|
lang_interfaces = sub_interfaces
|
||||||
types = set(['normal', 'chat', 'headline', 'error', 'groupchat'])
|
types = set(['normal', 'chat', 'headline', 'error', 'groupchat'])
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Initialize a new <message /> stanza with an optional 'id' value.
|
||||||
|
|
||||||
|
Overrides StanzaBase.__init__.
|
||||||
|
"""
|
||||||
|
StanzaBase.__init__(self, *args, **kwargs)
|
||||||
|
if self['id'] == '':
|
||||||
|
if self.stream is not None and self.stream.use_message_ids:
|
||||||
|
self['id'] = self.stream.new_id()
|
||||||
|
|
||||||
def get_type(self):
|
def get_type(self):
|
||||||
"""
|
"""
|
||||||
Return the message type.
|
Return the message type.
|
||||||
|
@ -72,6 +72,17 @@ class Presence(RootStanza):
|
|||||||
'subscribed', 'unsubscribe', 'unsubscribed'])
|
'subscribed', 'unsubscribe', 'unsubscribed'])
|
||||||
showtypes = set(['dnd', 'chat', 'xa', 'away'])
|
showtypes = set(['dnd', 'chat', 'xa', 'away'])
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Initialize a new <presence /> stanza with an optional 'id' value.
|
||||||
|
|
||||||
|
Overrides StanzaBase.__init__.
|
||||||
|
"""
|
||||||
|
StanzaBase.__init__(self, *args, **kwargs)
|
||||||
|
if self['id'] == '':
|
||||||
|
if self.stream is not None and self.stream.use_presence_ids:
|
||||||
|
self['id'] = self.stream.new_id()
|
||||||
|
|
||||||
def exception(self, e):
|
def exception(self, e):
|
||||||
"""
|
"""
|
||||||
Override exception passback for presence.
|
Override exception passback for presence.
|
||||||
|
@ -368,6 +368,11 @@ class SleekTest(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
for plugin in plugins:
|
for plugin in plugins:
|
||||||
self.xmpp.register_plugin(plugin)
|
self.xmpp.register_plugin(plugin)
|
||||||
|
|
||||||
|
# Some plugins require messages to have ID values. Set
|
||||||
|
# this to True in tests related to those plugins.
|
||||||
|
self.xmpp.use_message_ids = False
|
||||||
|
|
||||||
self.xmpp.process(threaded=True)
|
self.xmpp.process(threaded=True)
|
||||||
if skip:
|
if skip:
|
||||||
if socket != 'live':
|
if socket != 'live':
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from sleekxmpp.xmlstream.handler.callback import Callback
|
from sleekxmpp.xmlstream.handler.callback import Callback
|
||||||
|
from sleekxmpp.xmlstream.handler.collector import Collector
|
||||||
from sleekxmpp.xmlstream.handler.waiter import Waiter
|
from sleekxmpp.xmlstream.handler.waiter import Waiter
|
||||||
from sleekxmpp.xmlstream.handler.xmlcallback import XMLCallback
|
from sleekxmpp.xmlstream.handler.xmlcallback import XMLCallback
|
||||||
from sleekxmpp.xmlstream.handler.xmlwaiter import XMLWaiter
|
from sleekxmpp.xmlstream.handler.xmlwaiter import XMLWaiter
|
||||||
|
66
sleekxmpp/xmlstream/handler/collector.py
Normal file
66
sleekxmpp/xmlstream/handler/collector.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
sleekxmpp.xmlstream.handler.collector
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Part of SleekXMPP: The Sleek XMPP Library
|
||||||
|
|
||||||
|
:copyright: (c) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
:license: MIT, see LICENSE for more details
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from sleekxmpp.util import Queue, QueueEmpty
|
||||||
|
from sleekxmpp.xmlstream.handler.base import BaseHandler
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Collector(BaseHandler):
|
||||||
|
|
||||||
|
"""
|
||||||
|
The Collector handler allows for collecting a set of stanzas
|
||||||
|
that match a given pattern. Unlike the Waiter handler, a
|
||||||
|
Collector does not block execution, and will continue to
|
||||||
|
accumulate matching stanzas until told to stop.
|
||||||
|
|
||||||
|
:param string name: The name of the handler.
|
||||||
|
:param matcher: A :class:`~sleekxmpp.xmlstream.matcher.base.MatcherBase`
|
||||||
|
derived object for matching stanza objects.
|
||||||
|
:param stream: The :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream`
|
||||||
|
instance this handler should monitor.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, matcher, stream=None):
|
||||||
|
BaseHandler.__init__(self, name, matcher, stream=stream)
|
||||||
|
self._payload = Queue()
|
||||||
|
|
||||||
|
def prerun(self, payload):
|
||||||
|
"""Store the matched stanza when received during processing.
|
||||||
|
|
||||||
|
:param payload: The matched
|
||||||
|
:class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` object.
|
||||||
|
"""
|
||||||
|
self._payload.put(payload)
|
||||||
|
|
||||||
|
def run(self, payload):
|
||||||
|
"""Do not process this handler during the main event loop."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
Stop collection of matching stanzas, and return the ones that
|
||||||
|
have been stored so far.
|
||||||
|
"""
|
||||||
|
self._destroy = True
|
||||||
|
results = []
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
results.append(self._payload.get(False))
|
||||||
|
except QueueEmpty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.stream().remove_handler(self.name)
|
||||||
|
return results
|
@ -17,7 +17,7 @@ class TestStreamSet(SleekTest):
|
|||||||
def iter(self, rev=False):
|
def iter(self, rev=False):
|
||||||
q = self.xmpp.Iq()
|
q = self.xmpp.Iq()
|
||||||
q['type'] = 'get'
|
q['type'] = 'get'
|
||||||
it = ResultIterator(q, 'disco_items', '1', reverse=rev)
|
it = ResultIterator(q, 'disco_items', amount='1', reverse=rev)
|
||||||
for i in it:
|
for i in it:
|
||||||
for j in i['disco_items']['items']:
|
for j in i['disco_items']['items']:
|
||||||
self.items.append(j[0])
|
self.items.append(j[0])
|
||||||
|
Loading…
Reference in New Issue
Block a user