Compare commits
20 Commits
disco
...
slix-1.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36824379c3 | ||
|
|
a0a37c19ff | ||
|
|
1b5fe57a5e | ||
|
|
5da31db0c7 | ||
|
|
f8cea760b6 | ||
|
|
5ef01ecdd1 | ||
|
|
62aafe0ee7 | ||
|
|
cf3f36ac52 | ||
|
|
b88d2ecd77 | ||
|
|
e691850a2b | ||
|
|
d4bff8dee6 | ||
|
|
187c350805 | ||
|
|
96d1c26f90 | ||
|
|
46a90749f8 | ||
|
|
0c63a4bbda | ||
|
|
e4696e0471 | ||
|
|
8217dc5239 | ||
|
|
2586abc0d3 | ||
|
|
28f84ab3d9 | ||
|
|
813b45aded |
@@ -12,8 +12,8 @@ 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::
|
||||
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
|
||||
|
||||
@@ -108,6 +108,11 @@ Slixmpp Credits
|
||||
|
||||
**Contributors:**
|
||||
- Emmanuel Gil Peyrot (`Link mauve <xmpp:linkmauve@linkmauve.fr?message>`_)
|
||||
- Sam Whited (`Sam Whited <mailto:sam@samwhited.com>`_)
|
||||
- Dan Sully (`Dan Sully <mailto:daniel@electricalrain.com>`_)
|
||||
- Gasper Zejn (`Gasper Zejn <mailto:zejn@kiberpipa.org>`_)
|
||||
- Krzysztof Kotlenga (`Krzysztof Kotlenga <mailto:pocek@users.sf.net>`_)
|
||||
- Tsukasa Hiiragi (`Tsukasa Hiiragi <mailto:bakalolka@gmail.com>`_)
|
||||
|
||||
Credits (SleekXMPP)
|
||||
-------------------
|
||||
|
||||
@@ -70,7 +70,7 @@ as well.
|
||||
class EchoBot(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(EchoBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
Handling Session Start
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -83,7 +83,7 @@ started. To do that, we will register an event handler for the :term:`session_st
|
||||
.. code-block:: python
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(EchoBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.add_event_handler('session_start', self.start)
|
||||
|
||||
@@ -153,7 +153,7 @@ whenever a messsage is received.
|
||||
.. code-block:: python
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(EchoBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.add_event_handler('session_start', self.start)
|
||||
self.add_event_handler('message', self.message)
|
||||
|
||||
@@ -63,13 +63,13 @@ has been established:
|
||||
def start(self, event):
|
||||
self.get_roster()
|
||||
self.send_presence()
|
||||
self.plugin['xep_0045'].joinMUC(self.room,
|
||||
self.nick,
|
||||
wait=True)
|
||||
self.plugin['xep_0045'].join_muc(self.room,
|
||||
self.nick,
|
||||
wait=True)
|
||||
|
||||
Note that as in :ref:`echobot`, we need to include send an initial presence and request
|
||||
the roster. Next, we want to join the group chat, so we call the
|
||||
``joinMUC`` method of the MUC plugin.
|
||||
``join_muc`` method of the MUC plugin.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ for the JID that will receive our message, and the string content of the message
|
||||
class SendMsgBot(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password, recipient, msg):
|
||||
super(SendMsgBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.recipient = recipient
|
||||
self.msg = msg
|
||||
|
||||
@@ -67,11 +67,11 @@ class MUCBot(slixmpp.ClientXMPP):
|
||||
"""
|
||||
self.get_roster()
|
||||
self.send_presence()
|
||||
self.plugin['xep_0045'].joinMUC(self.room,
|
||||
self.nick,
|
||||
# If a room password is needed, use:
|
||||
# password=the_room_password,
|
||||
wait=True)
|
||||
self.plugin['xep_0045'].join_muc(self.room,
|
||||
self.nick,
|
||||
# If a room password is needed, use:
|
||||
# password=the_room_password,
|
||||
wait=True)
|
||||
|
||||
def muc_message(self, msg):
|
||||
"""
|
||||
|
||||
@@ -15,7 +15,7 @@ class PubsubClient(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password, server,
|
||||
node=None, action='nodes', data=''):
|
||||
super(PubsubClient, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.register_plugin('xep_0030')
|
||||
self.register_plugin('xep_0059')
|
||||
|
||||
@@ -14,7 +14,7 @@ from slixmpp.xmlstream.handler import Callback
|
||||
class PubsubEvents(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(PubsubEvents, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.register_plugin('xep_0030')
|
||||
self.register_plugin('xep_0059')
|
||||
|
||||
@@ -22,7 +22,7 @@ from slixmpp import ClientXMPP
|
||||
class LocationBot(ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(LocationBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.add_event_handler('session_start', self.start)
|
||||
self.add_event_handler('user_location_publish',
|
||||
|
||||
@@ -17,7 +17,7 @@ from slixmpp import ClientXMPP
|
||||
class TuneBot(ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(TuneBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
# Check for the current song every 5 seconds.
|
||||
self.schedule('Check Current Tune', 5, self._update_tune, repeat=True)
|
||||
|
||||
@@ -141,8 +141,11 @@ class ClientXMPP(BaseXMPP):
|
||||
will be used.
|
||||
|
||||
:param address: A tuple containing the server's host and port.
|
||||
:param use_tls: Indicates if TLS should be used for the
|
||||
connection. Defaults to ``True``.
|
||||
:param force_starttls: Indicates that negotiation should be aborted
|
||||
if the server does not advertise support for
|
||||
STARTTLS. Defaults to ``True``.
|
||||
:param disable_starttls: Disables TLS for the connection.
|
||||
Defaults to ``False``.
|
||||
:param use_ssl: Indicates if the older SSL connection method
|
||||
should be used. Defaults to ``False``.
|
||||
"""
|
||||
|
||||
@@ -77,7 +77,7 @@ class IqTimeout(XMPPError):
|
||||
"""
|
||||
|
||||
def __init__(self, iq):
|
||||
super(IqTimeout, self).__init__(
|
||||
super().__init__(
|
||||
condition='remote-server-timeout',
|
||||
etype='cancel')
|
||||
|
||||
@@ -94,7 +94,7 @@ class IqError(XMPPError):
|
||||
"""
|
||||
|
||||
def __init__(self, iq):
|
||||
super(IqError, self).__init__(
|
||||
super().__init__(
|
||||
condition=iq['error']['condition'],
|
||||
text=iq['error']['text'],
|
||||
etype=iq['error']['type'])
|
||||
|
||||
@@ -79,7 +79,7 @@ def _validate_node(node):
|
||||
:returns: The local portion of a JID, as validated by nodeprep.
|
||||
"""
|
||||
if node is None:
|
||||
return None
|
||||
return ''
|
||||
|
||||
try:
|
||||
node = nodeprep(node)
|
||||
@@ -160,7 +160,7 @@ def _validate_resource(resource):
|
||||
:returns: The local portion of a JID, as validated by resourceprep.
|
||||
"""
|
||||
if resource is None:
|
||||
return None
|
||||
return ''
|
||||
|
||||
try:
|
||||
resource = resourceprep(resource)
|
||||
|
||||
@@ -308,7 +308,7 @@ class BasePlugin(object):
|
||||
if key in self.default_config:
|
||||
self.config[key] = value
|
||||
else:
|
||||
super(BasePlugin, self).__setattr__(key, value)
|
||||
super().__setattr__(key, value)
|
||||
|
||||
def _init(self):
|
||||
"""Initialize plugin state, such as registering event handlers.
|
||||
|
||||
@@ -23,13 +23,13 @@ class GmailQuery(ElementBase):
|
||||
plugin_attrib = 'gmail'
|
||||
interfaces = set(('newer-than-time', 'newer-than-tid', 'q', 'search'))
|
||||
|
||||
def getSearch(self):
|
||||
def get_search(self):
|
||||
return self['q']
|
||||
|
||||
def setSearch(self, search):
|
||||
def set_search(self, search):
|
||||
self['q'] = search
|
||||
|
||||
def delSearch(self):
|
||||
def del_search(self):
|
||||
del self['q']
|
||||
|
||||
|
||||
@@ -40,17 +40,17 @@ class MailBox(ElementBase):
|
||||
interfaces = set(('result-time', 'total-matched', 'total-estimate',
|
||||
'url', 'threads', 'matched', 'estimate'))
|
||||
|
||||
def getThreads(self):
|
||||
def get_threads(self):
|
||||
threads = []
|
||||
for threadXML in self.xml.findall('{%s}%s' % (MailThread.namespace,
|
||||
MailThread.name)):
|
||||
threads.append(MailThread(xml=threadXML, parent=None))
|
||||
return threads
|
||||
|
||||
def getMatched(self):
|
||||
def get_matched(self):
|
||||
return self['total-matched']
|
||||
|
||||
def getEstimate(self):
|
||||
def get_estimate(self):
|
||||
return self['total-estimate'] == '1'
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class MailThread(ElementBase):
|
||||
'senders', 'url', 'labels', 'subject', 'snippet'))
|
||||
sub_interfaces = set(('labels', 'subject', 'snippet'))
|
||||
|
||||
def getSenders(self):
|
||||
def get_senders(self):
|
||||
senders = []
|
||||
sendersXML = self.xml.find('{%s}senders' % self.namespace)
|
||||
if sendersXML is not None:
|
||||
@@ -77,10 +77,10 @@ class MailSender(ElementBase):
|
||||
plugin_attrib = 'sender'
|
||||
interfaces = set(('address', 'name', 'originator', 'unread'))
|
||||
|
||||
def getOriginator(self):
|
||||
def get_originator(self):
|
||||
return self.xml.attrib.get('originator', '0') == '1'
|
||||
|
||||
def getUnread(self):
|
||||
def get_unread(self):
|
||||
return self.xml.attrib.get('unread', '0') == '1'
|
||||
|
||||
|
||||
|
||||
@@ -92,13 +92,13 @@ 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
|
||||
find_value = value.find
|
||||
if find_value('{%s}nil' % namespace) is not None:
|
||||
return None
|
||||
if find_value('{%s}i4' % namespace) is not None:
|
||||
|
||||
@@ -117,9 +117,12 @@ for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'):
|
||||
setattr(Addresses, "set_%s" % atype, set_multi)
|
||||
setattr(Addresses, "del_%s" % atype, del_multi)
|
||||
|
||||
# To retain backwards compatibility:
|
||||
if atype == 'all':
|
||||
Addresses.interfaces.add('addresses')
|
||||
setattr(Addresses, "get_addresses", get_multi)
|
||||
setattr(Addresses, "set_addresses", set_multi)
|
||||
setattr(Addresses, "del_addresses", del_multi)
|
||||
|
||||
|
||||
|
||||
register_stanza_plugin(Addresses, Address, iterable=True)
|
||||
|
||||
@@ -29,82 +29,82 @@ class MUCPresence(ElementBase):
|
||||
affiliations = set(('', ))
|
||||
roles = set(('', ))
|
||||
|
||||
def getXMLItem(self):
|
||||
def get_xml_item(self):
|
||||
item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
|
||||
if item is None:
|
||||
item = ET.Element('{http://jabber.org/protocol/muc#user}item')
|
||||
self.xml.append(item)
|
||||
return item
|
||||
|
||||
def getAffiliation(self):
|
||||
def get_affiliation(self):
|
||||
#TODO if no affilation, set it to the default and return default
|
||||
item = self.getXMLItem()
|
||||
item = self.get_xml_item()
|
||||
return item.get('affiliation', '')
|
||||
|
||||
def setAffiliation(self, value):
|
||||
item = self.getXMLItem()
|
||||
def set_affiliation(self, value):
|
||||
item = self.get_xml_item()
|
||||
#TODO check for valid affiliation
|
||||
item.attrib['affiliation'] = value
|
||||
return self
|
||||
|
||||
def delAffiliation(self):
|
||||
item = self.getXMLItem()
|
||||
def del_affiliation(self):
|
||||
item = self.get_xml_item()
|
||||
#TODO set default affiliation
|
||||
if 'affiliation' in item.attrib: del item.attrib['affiliation']
|
||||
return self
|
||||
|
||||
def getJid(self):
|
||||
item = self.getXMLItem()
|
||||
def get_jid(self):
|
||||
item = self.get_xml_item()
|
||||
return JID(item.get('jid', ''))
|
||||
|
||||
def setJid(self, value):
|
||||
item = self.getXMLItem()
|
||||
def set_jid(self, value):
|
||||
item = self.get_xml_item()
|
||||
if not isinstance(value, str):
|
||||
value = str(value)
|
||||
item.attrib['jid'] = value
|
||||
return self
|
||||
|
||||
def delJid(self):
|
||||
item = self.getXMLItem()
|
||||
def del_jid(self):
|
||||
item = self.get_xml_item()
|
||||
if 'jid' in item.attrib: del item.attrib['jid']
|
||||
return self
|
||||
|
||||
def getRole(self):
|
||||
item = self.getXMLItem()
|
||||
def get_role(self):
|
||||
item = self.get_xml_item()
|
||||
#TODO get default role, set default role if none
|
||||
return item.get('role', '')
|
||||
|
||||
def setRole(self, value):
|
||||
item = self.getXMLItem()
|
||||
def set_role(self, value):
|
||||
item = self.get_xml_item()
|
||||
#TODO check for valid role
|
||||
item.attrib['role'] = value
|
||||
return self
|
||||
|
||||
def delRole(self):
|
||||
item = self.getXMLItem()
|
||||
def del_role(self):
|
||||
item = self.get_xml_item()
|
||||
#TODO set default role
|
||||
if 'role' in item.attrib: del item.attrib['role']
|
||||
return self
|
||||
|
||||
def getNick(self):
|
||||
def get_nick(self):
|
||||
return self.parent()['from'].resource
|
||||
|
||||
def getRoom(self):
|
||||
def get_room(self):
|
||||
return self.parent()['from'].bare
|
||||
|
||||
def setNick(self, value):
|
||||
def set_nick(self, value):
|
||||
log.warning("Cannot set nick through mucpresence plugin.")
|
||||
return self
|
||||
|
||||
def setRoom(self, value):
|
||||
def set_room(self, value):
|
||||
log.warning("Cannot set room through mucpresence plugin.")
|
||||
return self
|
||||
|
||||
def delNick(self):
|
||||
def del_nick(self):
|
||||
log.warning("Cannot delete nick through mucpresence plugin.")
|
||||
return self
|
||||
|
||||
def delRoom(self):
|
||||
def del_room(self):
|
||||
log.warning("Cannot delete room through mucpresence plugin.")
|
||||
return self
|
||||
|
||||
@@ -121,7 +121,7 @@ class XEP_0045(BasePlugin):
|
||||
|
||||
def plugin_init(self):
|
||||
self.rooms = {}
|
||||
self.ourNicks = {}
|
||||
self.our_nicks = {}
|
||||
self.xep = '0045'
|
||||
# load MUC support in presence stanzas
|
||||
register_stanza_plugin(Presence, MUCPresence)
|
||||
@@ -201,22 +201,22 @@ class XEP_0045(BasePlugin):
|
||||
"""
|
||||
self.xmpp.event('groupchat_subject', msg)
|
||||
|
||||
def jidInRoom(self, room, jid):
|
||||
def jid_in_room(self, room, jid):
|
||||
for nick in self.rooms[room]:
|
||||
entry = self.rooms[room][nick]
|
||||
if entry is not None and entry['jid'].full == jid:
|
||||
return True
|
||||
return False
|
||||
|
||||
def getNick(self, room, jid):
|
||||
def get_nick(self, room, jid):
|
||||
for nick in self.rooms[room]:
|
||||
entry = self.rooms[room][nick]
|
||||
if entry is not None and entry['jid'].full == jid:
|
||||
return nick
|
||||
|
||||
def configureRoom(self, room, form=None, ifrom=None):
|
||||
def configure_room(self, room, form=None, ifrom=None):
|
||||
if form is None:
|
||||
form = self.getRoomConfig(room, ifrom=ifrom)
|
||||
form = self.get_room_config(room, ifrom=ifrom)
|
||||
iq = self.xmpp.make_iq_set()
|
||||
iq['to'] = room
|
||||
if ifrom is not None:
|
||||
@@ -234,7 +234,7 @@ class XEP_0045(BasePlugin):
|
||||
return False
|
||||
return True
|
||||
|
||||
def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None, pfrom=None):
|
||||
def join_muc(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None, pfrom=None):
|
||||
""" Join the specified room, requesting 'maxhistory' lines of history.
|
||||
"""
|
||||
stanza = self.xmpp.make_presence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow, pfrom=pfrom)
|
||||
@@ -258,7 +258,7 @@ class XEP_0045(BasePlugin):
|
||||
expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)})
|
||||
self.xmpp.send(stanza, expect)
|
||||
self.rooms[room] = {}
|
||||
self.ourNicks[room] = nick
|
||||
self.our_nicks[room] = nick
|
||||
|
||||
def destroy(self, room, reason='', altroom = '', ifrom=None):
|
||||
iq = self.xmpp.make_iq_set()
|
||||
@@ -283,7 +283,7 @@ class XEP_0045(BasePlugin):
|
||||
return False
|
||||
return True
|
||||
|
||||
def setAffiliation(self, room, jid=None, nick=None, affiliation='member', ifrom=None):
|
||||
def set_affiliation(self, room, jid=None, nick=None, affiliation='member', ifrom=None):
|
||||
""" Change room affiliation."""
|
||||
if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
|
||||
raise TypeError
|
||||
@@ -305,7 +305,7 @@ class XEP_0045(BasePlugin):
|
||||
return False
|
||||
return True
|
||||
|
||||
def setRole(self, room, nick, role):
|
||||
def set_role(self, room, nick, role):
|
||||
""" Change role property of a nick in a room.
|
||||
Typically, roles are temporary (they last only as long as you are in the
|
||||
room), whereas affiliations are permanent (they last across groupchat
|
||||
@@ -337,7 +337,7 @@ class XEP_0045(BasePlugin):
|
||||
msg.append(x)
|
||||
self.xmpp.send(msg)
|
||||
|
||||
def leaveMUC(self, room, nick, msg='', pfrom=None):
|
||||
def leave_muc(self, room, nick, msg='', pfrom=None):
|
||||
""" Leave the specified room.
|
||||
"""
|
||||
if msg:
|
||||
@@ -346,7 +346,7 @@ class XEP_0045(BasePlugin):
|
||||
self.xmpp.send_presence(pshow='unavailable', pto="%s/%s" % (room, nick), pfrom=pfrom)
|
||||
del self.rooms[room]
|
||||
|
||||
def getRoomConfig(self, room, ifrom=''):
|
||||
def get_room_config(self, room, ifrom=''):
|
||||
iq = self.xmpp.make_iq_get('http://jabber.org/protocol/muc#owner')
|
||||
iq['to'] = room
|
||||
iq['from'] = ifrom
|
||||
@@ -362,7 +362,7 @@ class XEP_0045(BasePlugin):
|
||||
raise ValueError
|
||||
return self.xmpp.plugin['xep_0004'].build_form(form)
|
||||
|
||||
def cancelConfig(self, room, ifrom=None):
|
||||
def cancel_config(self, room, ifrom=None):
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
|
||||
x = ET.Element('{jabber:x:data}x', type='cancel')
|
||||
query.append(x)
|
||||
@@ -371,7 +371,7 @@ class XEP_0045(BasePlugin):
|
||||
iq['from'] = ifrom
|
||||
iq.send()
|
||||
|
||||
def setRoomConfig(self, room, config, ifrom=''):
|
||||
def set_room_config(self, room, config, ifrom=''):
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
|
||||
config['type'] = 'submit'
|
||||
query.append(config)
|
||||
@@ -380,31 +380,31 @@ class XEP_0045(BasePlugin):
|
||||
iq['from'] = ifrom
|
||||
iq.send()
|
||||
|
||||
def getJoinedRooms(self):
|
||||
def get_joined_rooms(self):
|
||||
return self.rooms.keys()
|
||||
|
||||
def getOurJidInRoom(self, roomJid):
|
||||
def get_our_jid_in_room(self, room_jid):
|
||||
""" Return the jid we're using in a room.
|
||||
"""
|
||||
return "%s/%s" % (roomJid, self.ourNicks[roomJid])
|
||||
return "%s/%s" % (room_jid, self.our_nicks[room_jid])
|
||||
|
||||
def getJidProperty(self, room, nick, jidProperty):
|
||||
def get_jid_property(self, room, nick, jid_property):
|
||||
""" Get the property of a nick in a room, such as its 'jid' or 'affiliation'
|
||||
If not found, return None.
|
||||
"""
|
||||
if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]:
|
||||
return self.rooms[room][nick][jidProperty]
|
||||
if room in self.rooms and nick in self.rooms[room] and jid_property in self.rooms[room][nick]:
|
||||
return self.rooms[room][nick][jid_property]
|
||||
else:
|
||||
return None
|
||||
|
||||
def getRoster(self, room):
|
||||
def get_roster(self, room):
|
||||
""" Get the list of nicks in a room.
|
||||
"""
|
||||
if room not in self.rooms.keys():
|
||||
return None
|
||||
return self.rooms[room].keys()
|
||||
|
||||
def getUsersByAffiliation(cls, room, affiliation='member', ifrom=None):
|
||||
def get_users_by_affiliation(cls, room, affiliation='member', ifrom=None):
|
||||
if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
|
||||
raise TypeError
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
|
||||
@@ -415,5 +415,4 @@ class XEP_0045(BasePlugin):
|
||||
return iq.send()
|
||||
|
||||
|
||||
xep_0045 = XEP_0045
|
||||
register_plugin(XEP_0045)
|
||||
|
||||
@@ -59,7 +59,7 @@ class XEP_0048(BasePlugin):
|
||||
for conf in bookmarks['conferences']:
|
||||
if conf['autojoin']:
|
||||
log.debug('Auto joining %s as %s', conf['jid'], conf['nick'])
|
||||
self.xmpp['xep_0045'].joinMUC(conf['jid'], conf['nick'],
|
||||
self.xmpp['xep_0045'].join_muc(conf['jid'], conf['nick'],
|
||||
password=conf['password'])
|
||||
|
||||
def set_bookmarks(self, bookmarks, method=None, **iqargs):
|
||||
|
||||
@@ -136,7 +136,7 @@ class Command(ElementBase):
|
||||
('error', 'The command ran, but had errors')]
|
||||
"""
|
||||
notes = []
|
||||
notes_xml = self.findall('{%s}note' % self.namespace)
|
||||
notes_xml = self.xml.findall('{%s}note' % self.namespace)
|
||||
for note in notes_xml:
|
||||
notes.append((note.attrib.get('type', 'info'),
|
||||
note.text))
|
||||
@@ -167,7 +167,7 @@ class Command(ElementBase):
|
||||
"""
|
||||
Remove all notes associated with the command result.
|
||||
"""
|
||||
notes_xml = self.findall('{%s}note' % self.namespace)
|
||||
notes_xml = self.xml.findall('{%s}note' % self.namespace)
|
||||
for note in notes_xml:
|
||||
self.xml.remove(note)
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ class Telephone(ElementBase):
|
||||
'ISDN', 'PCS', 'PREF'])
|
||||
|
||||
def setup(self, xml=None):
|
||||
super(Telephone, self).setup(xml=xml)
|
||||
super().setup(xml=xml)
|
||||
## this blanks out numbers received from server
|
||||
##self._set_sub_text('NUMBER', '', keep=True)
|
||||
|
||||
|
||||
@@ -206,7 +206,10 @@ class Options(ElementBase):
|
||||
return form
|
||||
|
||||
def set_options(self, value):
|
||||
self.xml.append(value)
|
||||
if isinstance(value, ElementBase):
|
||||
self.xml.append(value.xml)
|
||||
else:
|
||||
self.xml.append(value)
|
||||
return self
|
||||
|
||||
def del_options(self):
|
||||
@@ -238,7 +241,10 @@ class PublishOptions(ElementBase):
|
||||
if value is None:
|
||||
self.del_publish_options()
|
||||
else:
|
||||
self.xml.append(value)
|
||||
if isinstance(value, ElementBase):
|
||||
self.xml.append(value.xml)
|
||||
else:
|
||||
self.xml.append(value)
|
||||
return self
|
||||
|
||||
def del_publish_options(self):
|
||||
|
||||
@@ -38,9 +38,8 @@ class StaticExtendedDisco(object):
|
||||
The data parameter may provide:
|
||||
data -- Either a single data form, or a list of data forms.
|
||||
"""
|
||||
with self.static.lock:
|
||||
self.del_extended_info(jid, node, ifrom, data)
|
||||
self.add_extended_info(jid, node, ifrom, data)
|
||||
self.del_extended_info(jid, node, ifrom, data)
|
||||
self.add_extended_info(jid, node, ifrom, data)
|
||||
|
||||
def add_extended_info(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -49,16 +48,15 @@ class StaticExtendedDisco(object):
|
||||
The data parameter may provide:
|
||||
data -- Either a single data form, or a list of data forms.
|
||||
"""
|
||||
with self.static.lock:
|
||||
self.static.add_node(jid, node)
|
||||
self.static.add_node(jid, node)
|
||||
|
||||
forms = data.get('data', [])
|
||||
if not isinstance(forms, list):
|
||||
forms = [forms]
|
||||
forms = data.get('data', [])
|
||||
if not isinstance(forms, list):
|
||||
forms = [forms]
|
||||
|
||||
info = self.static.get_node(jid, node)['info']
|
||||
for form in forms:
|
||||
info.append(form)
|
||||
info = self.static.get_node(jid, node)['info']
|
||||
for form in forms:
|
||||
info.append(form)
|
||||
|
||||
def del_extended_info(self, jid, node, ifrom, data):
|
||||
"""
|
||||
@@ -66,8 +64,7 @@ class StaticExtendedDisco(object):
|
||||
|
||||
The data parameter is not used.
|
||||
"""
|
||||
with self.static.lock:
|
||||
if self.static.node_exists(jid, node):
|
||||
info = self.static.get_node(jid, node)['info']
|
||||
for form in info['substanza']:
|
||||
info.xml.remove(form.xml)
|
||||
if self.static.node_exists(jid, node):
|
||||
info = self.static.get_node(jid, node)['info']
|
||||
for form in info['substanza']:
|
||||
info.xml.remove(form.xml)
|
||||
|
||||
@@ -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.2.1'
|
||||
__version_info__ = (1, 2, 1)
|
||||
|
||||
@@ -1,38 +1,10 @@
|
||||
"""
|
||||
A module that monkey patches the standard asyncio module to add an
|
||||
idle_call() method to the main loop. This method is used to execute a
|
||||
callback whenever the loop is not busy handling anything else. This means
|
||||
that it is a callback with lower priority than IO, timer, or even
|
||||
call_soon() ones. These callback are called only once each.
|
||||
asyncio-related utilities
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from asyncio import events
|
||||
from functools import wraps
|
||||
|
||||
import collections
|
||||
|
||||
def idle_call(self, callback):
|
||||
if asyncio.iscoroutinefunction(callback):
|
||||
raise TypeError("coroutines cannot be used with idle_call()")
|
||||
handle = events.Handle(callback, [], self)
|
||||
self._idle.append(handle)
|
||||
|
||||
def my_run_once(self):
|
||||
if self._idle:
|
||||
self._ready.append(events.Handle(lambda: None, (), self))
|
||||
real_run_once(self)
|
||||
if self._idle:
|
||||
handle = self._idle.popleft()
|
||||
handle._run()
|
||||
|
||||
cls = asyncio.get_event_loop().__class__
|
||||
|
||||
cls._idle = collections.deque()
|
||||
cls.idle_call = idle_call
|
||||
real_run_once = cls._run_once
|
||||
cls._run_once = my_run_once
|
||||
|
||||
def future_wrapper(func):
|
||||
"""
|
||||
Make sure the result of a function call is an asyncio.Future()
|
||||
|
||||
@@ -668,9 +668,6 @@ 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):
|
||||
return getattr(self, get_method2)(**kwargs)
|
||||
else:
|
||||
if attrib in self.sub_interfaces:
|
||||
return self._get_sub_text(attrib, lang=lang)
|
||||
@@ -733,7 +730,6 @@ class ElementBase(object):
|
||||
if attrib in self.interfaces or attrib == 'lang':
|
||||
if value is not None:
|
||||
set_method = "set_%s" % attrib.lower()
|
||||
set_method2 = "set%s" % attrib.title()
|
||||
|
||||
if self.plugin_overrides:
|
||||
name = self.plugin_overrides.get(set_method, None)
|
||||
@@ -746,8 +742,6 @@ class ElementBase(object):
|
||||
|
||||
if hasattr(self, set_method):
|
||||
getattr(self, set_method)(value, **kwargs)
|
||||
elif hasattr(self, set_method2):
|
||||
getattr(self, set_method2)(value, **kwargs)
|
||||
else:
|
||||
if attrib in self.sub_interfaces:
|
||||
if lang == '*':
|
||||
@@ -820,7 +814,6 @@ class ElementBase(object):
|
||||
|
||||
if attrib in self.interfaces or attrib == 'lang':
|
||||
del_method = "del_%s" % attrib.lower()
|
||||
del_method2 = "del%s" % attrib.title()
|
||||
|
||||
if self.plugin_overrides:
|
||||
name = self.plugin_overrides.get(del_method, None)
|
||||
@@ -833,8 +826,6 @@ class ElementBase(object):
|
||||
|
||||
if hasattr(self, del_method):
|
||||
getattr(self, del_method)(**kwargs)
|
||||
elif hasattr(self, del_method2):
|
||||
getattr(self, del_method2)(**kwargs)
|
||||
else:
|
||||
if attrib in self.sub_interfaces:
|
||||
return self._del_sub(attrib, lang=lang)
|
||||
@@ -916,11 +907,17 @@ class ElementBase(object):
|
||||
stanzas = self.xml.findall(name)
|
||||
if not stanzas:
|
||||
return default
|
||||
result = None
|
||||
for stanza in stanzas:
|
||||
if stanza.attrib.get('{%s}lang' % XML_NS, default_lang) == lang:
|
||||
if stanza.text is None:
|
||||
return default
|
||||
return stanza.text
|
||||
result = stanza.text
|
||||
break
|
||||
if stanza.text:
|
||||
result = stanza.text
|
||||
if result is not None:
|
||||
return result
|
||||
return default
|
||||
|
||||
def _get_all_sub_text(self, name, default='', lang=None):
|
||||
|
||||
@@ -256,9 +256,9 @@ class XMLStream(asyncio.BaseProtocol):
|
||||
TODO fix the comment
|
||||
:param force_starttls: If True, the connection will be aborted if
|
||||
the server does not initiate a STARTTLS
|
||||
negociation. If None, the connection will be
|
||||
negotiation. If None, the connection will be
|
||||
upgraded to TLS only if the server initiate
|
||||
the STARTTLS negociation, otherwise it will
|
||||
the STARTTLS negotiation, otherwise it will
|
||||
connect in clear. If False it will never
|
||||
upgrade to TLS, even if the server provides
|
||||
it. Use this for example if you’re on
|
||||
@@ -380,7 +380,7 @@ class XMLStream(asyncio.BaseProtocol):
|
||||
elif self.xml_depth == 1:
|
||||
# A stanza is an XML element that is a direct child of
|
||||
# the root element, hence the check of depth == 1
|
||||
self.loop.idle_call(functools.partial(self.__spawn_event, xml))
|
||||
self._spawn_event(xml)
|
||||
if self.xml_root is not None:
|
||||
# Keep the root element empty of children to
|
||||
# save on memory use.
|
||||
@@ -760,6 +760,9 @@ class XMLStream(asyncio.BaseProtocol):
|
||||
:param repeat: Flag indicating if the scheduled event should
|
||||
be reset and repeat after executing.
|
||||
"""
|
||||
if name in self.scheduled_events:
|
||||
raise ValueError(
|
||||
"There is already a scheduled event of name: %s" % name)
|
||||
if seconds is None:
|
||||
seconds = RESPONSE_TIMEOUT
|
||||
cb = functools.partial(callback, *args, **kwargs)
|
||||
@@ -769,7 +772,6 @@ class XMLStream(asyncio.BaseProtocol):
|
||||
else:
|
||||
handle = self.loop.call_later(seconds, self._execute_and_unschedule,
|
||||
name, cb)
|
||||
|
||||
# Save that handle, so we can just cancel this scheduled event by
|
||||
# canceling scheduled_events[name]
|
||||
self.scheduled_events[name] = handle
|
||||
@@ -891,7 +893,7 @@ class XMLStream(asyncio.BaseProtocol):
|
||||
stanza['lang'] = self.peer_default_lang
|
||||
return stanza
|
||||
|
||||
def __spawn_event(self, xml):
|
||||
def _spawn_event(self, xml):
|
||||
"""
|
||||
Analyze incoming XML stanzas and convert them into stanza
|
||||
objects if applicable and queue stream events to be processed
|
||||
|
||||
@@ -142,7 +142,7 @@ class TestElementBase(SlixTest):
|
||||
interfaces = set(('bar', 'baz', 'qux'))
|
||||
sub_interfaces = set(('baz',))
|
||||
|
||||
def getQux(self):
|
||||
def get_qux(self):
|
||||
return 'qux'
|
||||
|
||||
class TestStanzaPlugin(ElementBase):
|
||||
@@ -188,7 +188,7 @@ class TestElementBase(SlixTest):
|
||||
interfaces = set(('bar', 'baz', 'qux'))
|
||||
sub_interfaces = set(('baz',))
|
||||
|
||||
def setQux(self, value):
|
||||
def set_qux(self, value):
|
||||
pass
|
||||
|
||||
class TestStanzaPlugin(ElementBase):
|
||||
@@ -222,7 +222,7 @@ class TestElementBase(SlixTest):
|
||||
interfaces = set(('bar', 'baz', 'qux'))
|
||||
sub_interfaces = set(('bar',))
|
||||
|
||||
def delQux(self):
|
||||
def del_qux(self):
|
||||
pass
|
||||
|
||||
class TestStanzaPlugin(ElementBase):
|
||||
@@ -300,14 +300,14 @@ class TestElementBase(SlixTest):
|
||||
namespace = "foo"
|
||||
interfaces = set(('bar',))
|
||||
|
||||
def setBar(self, value):
|
||||
def set_bar(self, value):
|
||||
wrapper = ET.Element("{foo}wrapper")
|
||||
bar = ET.Element("{foo}bar")
|
||||
bar.text = value
|
||||
wrapper.append(bar)
|
||||
self.xml.append(wrapper)
|
||||
|
||||
def getBar(self):
|
||||
def get_bar(self):
|
||||
return self._get_sub_text("wrapper/bar", default="not found")
|
||||
|
||||
stanza = TestStanza()
|
||||
@@ -333,16 +333,16 @@ class TestElementBase(SlixTest):
|
||||
namespace = "foo"
|
||||
interfaces = set(('bar', 'baz'))
|
||||
|
||||
def setBaz(self, value):
|
||||
def set_baz(self, value):
|
||||
self._set_sub_text("wrapper/baz", text=value)
|
||||
|
||||
def getBaz(self):
|
||||
def get_baz(self):
|
||||
return self._get_sub_text("wrapper/baz")
|
||||
|
||||
def setBar(self, value):
|
||||
def set_bar(self, value):
|
||||
self._set_sub_text("wrapper/bar", text=value)
|
||||
|
||||
def getBar(self):
|
||||
def get_bar(self):
|
||||
return self._get_sub_text("wrapper/bar")
|
||||
|
||||
stanza = TestStanza()
|
||||
@@ -384,22 +384,22 @@ class TestElementBase(SlixTest):
|
||||
namespace = "foo"
|
||||
interfaces = set(('bar', 'baz'))
|
||||
|
||||
def setBar(self, value):
|
||||
def set_bar(self, value):
|
||||
self._set_sub_text("path/to/only/bar", value)
|
||||
|
||||
def getBar(self):
|
||||
def get_bar(self):
|
||||
return self._get_sub_text("path/to/only/bar")
|
||||
|
||||
def delBar(self):
|
||||
def del_bar(self):
|
||||
self._del_sub("path/to/only/bar")
|
||||
|
||||
def setBaz(self, value):
|
||||
def set_baz(self, value):
|
||||
self._set_sub_text("path/to/just/baz", value)
|
||||
|
||||
def getBaz(self):
|
||||
def get_baz(self):
|
||||
return self._get_sub_text("path/to/just/baz")
|
||||
|
||||
def delBaz(self):
|
||||
def del_baz(self):
|
||||
self._del_sub("path/to/just/baz")
|
||||
|
||||
stanza = TestStanza()
|
||||
@@ -466,10 +466,10 @@ class TestElementBase(SlixTest):
|
||||
interfaces = set(('bar','baz', 'qux'))
|
||||
sub_interfaces = set(('qux',))
|
||||
|
||||
def setQux(self, value):
|
||||
def set_qux(self, value):
|
||||
self._set_sub_text('qux', text=value)
|
||||
|
||||
def getQux(self):
|
||||
def get_qux(self):
|
||||
return self._get_sub_text('qux')
|
||||
|
||||
class TestStanzaPlugin(ElementBase):
|
||||
|
||||
@@ -20,12 +20,6 @@ class TestMessageStanzas(SlixTest):
|
||||
msg = msg.reply()
|
||||
self.failUnless(str(msg['to']) == 'room@someservice.someserver.tld')
|
||||
|
||||
def testAttribProperty(self):
|
||||
"Test attrib property returning self"
|
||||
msg = self.Message()
|
||||
msg.attrib.attrib.attrib['to'] = 'usr@server.tld'
|
||||
self.failUnless(str(msg['to']) == 'usr@server.tld')
|
||||
|
||||
def testHTMLPlugin(self):
|
||||
"Test message/html/body stanza"
|
||||
msg = self.Message()
|
||||
|
||||
@@ -136,11 +136,11 @@ class TestPubsubStanzas(SlixTest):
|
||||
iq = self.Iq()
|
||||
iq['pubsub_owner']['default']
|
||||
iq['pubsub_owner']['default']['node'] = 'mynode'
|
||||
iq['pubsub_owner']['default']['form'].addField('pubsub#title',
|
||||
iq['pubsub_owner']['default']['form'].add_field('pubsub#title',
|
||||
ftype='text-single',
|
||||
value='This thing is awesome')
|
||||
self.check(iq, """
|
||||
<iq id="0">
|
||||
<iq id="0">
|
||||
<pubsub xmlns="http://jabber.org/protocol/pubsub#owner">
|
||||
<default node="mynode">
|
||||
<x xmlns="jabber:x:data" type="form">
|
||||
@@ -161,7 +161,8 @@ class TestPubsubStanzas(SlixTest):
|
||||
iq['pubsub']['subscribe']['options']['node'] = 'cheese'
|
||||
iq['pubsub']['subscribe']['options']['jid'] = 'fritzy@netflint.net/slixmpp'
|
||||
form = xep_0004.Form()
|
||||
form.addField('pubsub#title', ftype='text-single', value='this thing is awesome')
|
||||
form['type'] = 'submit'
|
||||
form.add_field('pubsub#title', ftype='text-single', value='this thing is awesome')
|
||||
iq['pubsub']['subscribe']['options']['options'] = form
|
||||
self.check(iq, """
|
||||
<iq id="0">
|
||||
@@ -201,6 +202,7 @@ class TestPubsubStanzas(SlixTest):
|
||||
iq['pubsub']['publish'].append(item)
|
||||
iq['pubsub']['publish'].append(item2)
|
||||
form = xep_0004.Form()
|
||||
form['type'] = 'submit'
|
||||
form.addField('pubsub#description', ftype='text-single', value='this thing is awesome')
|
||||
iq['pubsub']['publish_options'] = form
|
||||
|
||||
@@ -253,7 +255,7 @@ class TestPubsubStanzas(SlixTest):
|
||||
pub = iq['pubsub']
|
||||
pub['create']['node'] = 'testnode2'
|
||||
pub['configure']['form']['type'] = 'submit'
|
||||
pub['configure']['form'].setFields([
|
||||
pub['configure']['form'].set_fields([
|
||||
('FORM_TYPE', {'type': 'hidden',
|
||||
'value': 'http://jabber.org/protocol/pubsub#node_config'}),
|
||||
('pubsub#node_type', {'type': 'list-single',
|
||||
|
||||
Reference in New Issue
Block a user