Git Product home page Git Product logo

sleekxmpp's Introduction

SleekXMPP

⚠️ Deprecated ------------SleekXMPP is deprecated in favor of Slixmpp, a fork which takes full advantage of Python 3 and asyncio.

Slixmpp Repo: https://lab.louiz.org/poezio/slixmpp

Github Mirror: https://github.com/poezio/slixmpp

About

SleekXMPP is an MIT licensed XMPP library for Python 2.7/3.4+, and is featured in examples in XMPP: The Definitive Guide by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived here from reading the Definitive Guide, please see the notes on updating the examples to the latest version of SleekXMPP.

SleekXMPP's design goals and philosphy are:

Low number of dependencies

Installing and using SleekXMPP should be as simple as possible, without having to deal with long dependency chains.

As part of reducing the number of dependencies, some third party modules are included with SleekXMPP in the thirdparty directory. Imports from this module first try to import an existing installed version before loading the packaged version, when possible.

Every XEP as a plugin

Following Python's "batteries included" approach, the goal is to provide support for all currently active XEPs (final and draft). Since adding XEP support is done through easy to create plugins, the hope is to also provide a solid base for implementing and creating experimental XEPs.

Rewarding to work with

As much as possible, SleekXMPP should allow things to "just work" using sensible defaults and appropriate abstractions. XML can be ugly to work with, but it doesn't have to be that way.

Get the Code

Get the latest stable version from PyPI:

pip install sleekxmpp

The latest source code for SleekXMPP may be found on Github. Releases can be found in the master branch, while the latest development version is in the develop branch.

Latest Release
Develop Releases

Installing DNSPython

If you are using Python3 and wish to use dnspython, you will have to checkout and install the python3 branch:

git clone http://github.com/rthalley/dnspython
cd dnspython
git checkout python3
python3 setup.py install

Discussion

A mailing list and XMPP chat room are available for discussing and getting help with SleekXMPP.

Mailing List

SleekXMPP Discussion on Google Groups

Chat

[email protected]

Documentation and Testing

Documentation can be found both inline in the code, and as a Sphinx project in /docs. To generate the Sphinx documentation, follow the commands below. The HTML output will be in docs/_build/html:

cd docs
make html
open _build/html/index.html

To run the test suite for SleekXMPP:

python testall.py

The SleekXMPP Boilerplate

Projects using SleekXMPP tend to follow a basic pattern for setting up client/component connections and configuration. Here is the gist of the boilerplate needed for a SleekXMPP based project. See the documetation or examples directory for more detailed archetypes for SleekXMPP projects:

import logging

from sleekxmpp import ClientXMPP
from sleekxmpp.exceptions import IqError, IqTimeout


class EchoBot(ClientXMPP):

    def __init__(self, jid, password):
        ClientXMPP.__init__(self, jid, password)

        self.add_event_handler("session_start", self.session_start)
        self.add_event_handler("message", self.message)

        # If you wanted more functionality, here's how to register plugins:
        # self.register_plugin('xep_0030') # Service Discovery
        # self.register_plugin('xep_0199') # XMPP Ping

        # Here's how to access plugins once you've registered them:
        # self['xep_0030'].add_feature('echo_demo')

        # If you are working with an OpenFire server, you will
        # need to use a different SSL version:
        # import ssl
        # self.ssl_version = ssl.PROTOCOL_SSLv3

    def session_start(self, event):
        self.send_presence()
        self.get_roster()

        # Most get_*/set_* methods from plugins use Iq stanzas, which
        # can generate IqError and IqTimeout exceptions
        #
        # try:
        #     self.get_roster()
        # except IqError as err:
        #     logging.error('There was an error getting the roster')
        #     logging.error(err.iq['error']['condition'])
        #     self.disconnect()
        # except IqTimeout:
        #     logging.error('Server is taking too long to respond')
        #     self.disconnect()

    def message(self, msg):
        if msg['type'] in ('chat', 'normal'):
            msg.reply("Thanks for sending\n%(body)s" % msg).send()


if __name__ == '__main__':
    # Ideally use optparse or argparse to get JID,
    # password, and log level.

    logging.basicConfig(level=logging.DEBUG,
                        format='%(levelname)-8s %(message)s')

    xmpp = EchoBot('[email protected]', 'use_getpass')
    xmpp.connect()
    xmpp.process(block=True)

Credits

Main Author: Nathan Fritz

[email protected], @fritzy

Nathan is also the author of XMPPHP and Seesmic-AS3-XMPP, and a former member of the XMPP Council.

Maintainer: Mike "Bear" Taylor

https://bear.im/

A special thanks to Bear for stewarding the project for the last few years of its life.

Co-Author: Lance Stout

[email protected], @lancestout

Contributors:

sleekxmpp's People

Contributors

4gra avatar anton-ryzhov avatar bear avatar biergaizi avatar correl avatar dannmartens avatar florianfieber avatar fritzy avatar globin avatar hildjj avatar jdowner avatar joachimlindborg avatar jpcaruana avatar legastero avatar louiz avatar mathieui avatar medecau avatar olegantonyan avatar oskaritimperi avatar pvicente avatar rchan1611 avatar rerobins avatar rhcarvalho avatar roger avatar sangeeths avatar skinkie avatar trusty avatar vijayp avatar waechtjn avatar whooo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sleekxmpp's Issues

Expanded plugin registration

Currently if you want to write a plugin for sleek it must reside in the the sleekxmpp/plugins package. We have a requirement that we must be able to load a sleekxmpp plugin regardless of package. I have a simple patch for this that preserves existing functionality while adding the option of specifying the full package of a plugin to allow loading from any package.

The patch can be found here:
http://github.com/macdiesel/SleekXMPP/blob/4e2df7d48a8ec4ef52473c2cfe6b5246212520a9/sleekxmpp/basexmpp.py#L90-100

ssl_version should be negotiated or able to be set

When trying to connect to an OpenFire server using 'example.py' the login hangs in xmlstream.py and never times out and never throws an exception:

self.socket.do_handshake()

If I change the SSL type from 'PROTOCOL_TLSv1' to 'PROTOCOL_SSLv3', the login works as expected. Here is the line in xmlstream.py:

self.socket = ssl.wrap_socket(self.socket, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False)

According to the ssl module documentation, the client should "adapt to the server's protocol version". I'm not sure how that's going to happen given the way self.socket.do_handshake() doesn't throw an exception. Until or unless that is fixed, it would be nice to be able to specify the version. Tested on a git clone from 1/29/2010 using Python 2.6.4.

Refactor state machine.

tomstrummer has done a lot of refactoring in order to create a solid state machine. This should fix a lot of bugs, but needs to be audited.

eventRunner thread stops responding after stream reconnect

I have a component that responds to Service Discovery requests. After a while, the stream disconnects and the server component reconnects. The stream is re-established, but as you can see in the logs below, the component stops responding.

I think the problem is with the eventRunner thread. It quits after the stream disconnects and is not restarted.

Is there a way to restart the eventRunner thread?

Correct behavior:

DEBUG RECV: <ns0:iq from="component.example.com" id="825-32823" to="msm.example.com" type="get" xmlns:ns0="jabber:component:accept"><ns1:query xmlns:ns1="http://jabber.org/protocol/disco#info" />/ns0:iq
DEBUG Info request from component.example.com
DEBUG SEND:

Behavior after the stream reconnects:

DEBUG RECV: <ns0:iq from="component.example.com" id="72-32824" to="msm.example.com" type="get" xmlns:ns0="jabber:component:accept"><ns1:query xmlns:ns1="http://jabber.org/protocol/disco#info" />/ns0:iq

Full logs below:

(msm)[root@host xmpp]# python service.py --debug
DEBUG Loaded Plugin (XEP-0030) Service Discovery
DEBUG Loaded Plugin (XEP-0009) Jabber-RPC
DEBUG Loaded Plugin (XEP-0199) XMPP Ping
DEBUG Connecting to xmpp.example.com:5275
DEBUG Loading event runner
DEBUG SEND: <stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='msm.example.com'>
DEBUG SEND: d0dae26cfb9af754a2152b8ded53ee556f3905c6
DEBUG RECV: <ns0:handshake xmlns:ns0="jabber:component:accept" />
DEBUG XMPP connected
DEBUG RECV: <ns0:iq from="component.example.com" id="825-32823" to="msm.example.com" type="get" xmlns:ns0="jabber:component:accept"><ns1:query xmlns:ns1="http://jabber.org/protocol/disco#info" />/ns0:iq
DEBUG Info request from component.example.com
DEBUG SEND:
DEBUG SEND: /stream:stream
DEBUG Connecting to xmpp.example.com:5275
Traceback (most recent call last):
File "/home/django/projects/msm/lib/python2.6/site-packages/sleekxmpp/xmlstream/xmlstream.py", line 171, in _process
while self.run and self.__readXML():
File "/home/django/projects/msm/lib/python2.6/site-packages/sleekxmpp/xmlstream/xmlstream.py", line 217, in __readXML
for (event, xmlobj) in cElementTree.iterparse(self.filesocket, (b'end', b'start')):
File "", line 61, in iter
File "/home/django/projects/msm/lib/python2.6/site-packages/sleekxmpp/xmlstream/filesocket.py", line 14, in read
data = self._sock.recv(size)
AttributeError: 'NoneType' object has no attribute 'recv'
DEBUG SEND: <stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='msm.example.com'>
WARNING Failed to send <stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='msm.example.com'>
ERROR Disconnected. Socket Error.
Traceback (most recent call last):
File "/home/django/projects/msm/lib/python2.6/site-packages/sleekxmpp/xmlstream/xmlstream.py", line 245, in _sendThread
self.socket.send(data.encode('utf-8'))
File "/usr/local/lib/python2.6/socket.py", line 165, in _dummy
raise error(EBADF, 'Bad file descriptor')
error: [Errno 9] Bad file descriptor
DEBUG SEND: /stream:stream
WARNING Failed to send /stream:stream
ERROR Disconnected. Socket Error.
Traceback (most recent call last):
File "/home/django/projects/msm/lib/python2.6/site-packages/sleekxmpp/xmlstream/xmlstream.py", line 245, in _sendThread
self.socket.send(data.encode('utf-8'))
File "/usr/local/lib/python2.6/socket.py", line 165, in _dummy
raise error(EBADF, 'Bad file descriptor')
error: [Errno 9] Bad file descriptor
DEBUG Quitting eventRunner thread
DEBUG Connecting to xmpp.example.com:5275
DEBUG SEND: <stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='msm.example.com'>
DEBUG SEND: 61c82993e70ab4dd263ee962637ab8d5168732af
DEBUG RECV: <ns0:handshake xmlns:ns0="jabber:component:accept" />
DEBUG RECV: <ns0:iq from="component.example.com" id="72-32824" to="msm.example.com" type="get" xmlns:ns0="jabber:component:accept"><ns1:query xmlns:ns1="http://jabber.org/protocol/disco#info" />/ns0:iq
DEBUG SEND: /stream:stream

htmlim.py / XEP-0071

I was looking for a way to send HTML without it being escaped, and it looks like XEP-0071 is what I'd need to implement. While browsing the source I came across htmlim.py which seems to be a good start. Is this an XEP-0071 implementation, and if so, how can I use it to send HTML in a message?

P.S. Is there a mailing list or someplace else to ask questions like this?

ClientXMPP does not shut down cleanly

If you quit by pressing Ctrl+C, the program hangs (at least the example does). This appears to be because the send thread does not quit. Replacing the while clause in XMLStream._sendThread (while True:) with

    while self.run or not self.sendqueue.empty():

appears to fix the issue

socket monkey-patch appears to break other socket-using code

For instance, urllib2:
--------------------------------------------------------------------------------------------- Traceback (most recent call last):
File "/home/test/py26/lib/python2.6/site-packages/test/core.py", line 978, in http_get
handle = urllib2.urlopen(req)
File "/usr/lib/python2.6/urllib2.py", line 124, in urlopen
return _opener.open(url, data, timeout)
File "/usr/lib/python2.6/urllib2.py", line 395, in open
response = meth(req, response)
File "/usr/lib/python2.6/urllib2.py", line 508, in http_response
'http', request, response, code, msg, hdrs)
File "/usr/lib/python2.6/urllib2.py", line 427, in error
result = self._call_chain(_args)
File "/usr/lib/python2.6/urllib2.py", line 367, in _call_chain
result = func(_args)
File "/usr/lib/python2.6/urllib2.py", line 600, in http_error_302
fp.read()
File "/home/test/py26/lib/python2.6/site-packages/sleekxmpp/xmlstream/filesocket.py", line 6, in read
data = self._sock.recv(size)
File "/usr/lib/python2.6/httplib.py", line 538, in read
s = self.fp.read(amt)
File "/home/test/py26/lib/python2.6/site-packages/sleekxmpp/xmlstream/filesocket.py", line 6, in read
data = self._sock.recv(size)
ValueError: negative buffersize in recv


(cf. http://dpaste.com/150310/)

There is a lot of duplicate code for JID parsing

This should all be done by the JID class. The JID class should probably reside somewhere other than stanzabase. Also, the JID class should be used instead of self.domain, self.fulljid, etc.

Message Reply

It is preferable for message stanzas to be sent without a 'from' attribute because an XMPP server can either simply replace an incorrect or missing 'from' value, or reject the message entirely. A correct 'from' value is the full JID of the sending agent.

GTalk servers in particular are strict in that 'from' values that are just the bare JID are rejected.

Thus, using the reply method on message objects (which just swaps the 'to' and 'from' attributes) fails to correctly send messages in all cases when the message being replied to was sent only to a bare JID.

A good solution would be to simply drop the 'from' attribute when creating a reply.

Delete Event Handlers

There is currently no provided way to remove event handlers once they have been added.

Why remove event handlers? For some applications (like one I'm working on) it is necessary for the program to change 'roles' and respond to different types of events. One solution would be to add extra state information to each handler that will be turned on and off. However, that can get messy quickly, and having one place that can set the proper event handlers can be simpler.

I have a patch available at http://github.com/legastero/SleekXMPP/commit/ce7ff9f4539d09cc91bf140606f3e394c7df3794 that implements such a method for BaseXMPP.

Circular reference in stanzabase.py causing memory leak

After using SleekXMPP for a bot, we noticed that it was leaking memory, and believe we have narrowed it down to at least this circular reference in the ElementBase constructor in stanzabase.py:

self.attrib = self # backwards compatibility hack

We are still monitoring memory usage, but so far unsetting this variable has appeared to improve the memory usage for us.

UTF-8 characters don't work in 2.6

I need to do a conditional import to get utf-8 chars to work in 2.6. For now, 3.x is the only supported way to run SleekXMPP until this is fixed.

xep_0045 roster bug

xep_0045 plugin does not provide reliable roster list, I believe this line fixes the issue:

--- a/sleekxmpp/plugins/xep_0045.py
+++ b/sleekxmpp/plugins/xep_0045.py
@@ -136,7 +136,7 @@ class xep_0045(base.base_plugin):
                        return
                entry = pr['muc'].getValues()
                if pr['type'] == 'unavailable':
-                       self.rooms[entry['room']][entry['nick']] = None
+                       del self.rooms[entry['room']][entry['nick']]
                else:
                        self.rooms[entry['room']][entry['nick']] = entry
                logging.debug("MUC presence from %s/%s : %s" % (entry['room'],entry['nick'], entry))

HackFest for 1.0

Lance, Angela, and I will add issues here with their score. The person with the highest score gets first prize. There may also be a prize for 2nd and 3rd place.

Multiple license issue

I believe this project is now on the MIT license (yay) but there are still references to the GNU GPL2+ in some of the headers of the files. (xep_0199 being one example).

First I wanted to confirm that the project is now on the MIT license. If so I can go back and add ensure the correct header information is on all files so the licensing for the project is correct.

Auto-Reconnect State

I suspect that auto-reconnect currently puts SleekXMPP in a bad state. I need to investigate and fix this if necessary.

SRV Lookup fails because of Unicode

When I try to use SRV Lookups on Python 2.6 I get the following error:
DEBUG Loaded Plugin (XEP-0004) Data Forms
DEBUG Loaded Plugin (XEP-0030) Service Discovery
DEBUG Loaded Plugin (XEP-0060) Publish-Subscribe
DEBUG Loaded Plugin (XEP-0199) XMPP Ping
DEBUG Since no address is supplied, attempting SRV lookup.
Traceback (most recent call last):
File "example.py", line 82, in
if xmpp.connect():
File "/Users/mikef/source/SleekXMPP/sleekxmpp/init.py", line 99, in connect
answers = dns.resolver.query("_xmpp-client._tcp.%s" % self.server, "SRV")
File "/Library/Python/2.6/site-packages/dns/resolver.py", line 732, in query
return get_default_resolver().query(qname, rdtype, rdclass, tcp, source)
File "/Library/Python/2.6/site-packages/dns/resolver.py", line 617, in query
source=source)
File "/Library/Python/2.6/site-packages/dns/query.py", line 113, in udp
wire = q.to_wire()
File "/Library/Python/2.6/site-packages/dns/message.py", line 404, in to_wire
r.add_question(rrset.name, rrset.rdtype, rrset.rdclass)
File "/Library/Python/2.6/site-packages/dns/renderer.py", line 152, in add_question
self.output.write(struct.pack("!HH", rdtype, rdclass))
TypeError: unsupported operand type(s) for &: 'unicode' and 'long'


Encoding the "SRV" string back to ASCII fixes the problem.

Line 99 of init.py looks like this:
answers = dns.resolver.query("_xmpp-client._tcp.%s" % self.server, "SRV")
Change to this:
answers = dns.resolver.query("_xmpp-client._tcp.%s" % self.server, "SRV".encode('ascii', 'replace'))

EDIT: It looks like Tom Nichols (tomstrummer) came up with a much better solution.

http://github.com/tomstrummer/SleekXMPP/commit/de4d611d3053f2c4fb5029ba5214996cf3821e02

Roster not updated correctly in ClientXMPP._handleRoster

The line that's supposed to do the update does not work. Fix:

def _handleRoster(self, iq):
    for jid, data in iq['roster']['items'].iteritems():
        if not jid.bare in self.roster:
            self.roster[jid.bare] = {'groups': [], 'name': '', 'subscription': 'none', 'presence': {}, 'in_roster': True}
        self.roster[jid.bare].update(data)
    if iq['type'] == 'set':
        self.send(self.Iq().setValues({'type': 'result', 'id': iq['id']}).enable('roster'))
    self.event("roster_update", iq)

Automatic Subscription Handling

A gotcha that I spent this afternoon figuring out.

The _handlePresenceSubscribe method of the basexmpp class currently assumes that if the program does not wish to automatically authorize every subscription request (by using self.auto_authorize=False) then all subscription requests should be automatically rejected.

For programs which need more control over subscription authorizations, the issue can be resolved by setting:
self.event_handlers['presence_subscribe'] = []

The benefit of the current method is that the requesting entity always receives a reply. One possible way to keep this outcome is to automatically send the unsubscribed presence only if there are no registered event handlers for 'presence_subscribe' or 'changed_subscription'.

sdist tarball fails to install - missing file error

"python setup.py sdist" created tarball sleekxmpp-0.2.3.1.tar.gz and that tarball, when run with python2.6 setup.py install generates the following output:

(testsleek)moz:sleekxmpp-0.2.3.1 bear$ python setup.py install
running install
running build
running build_py
creating build
creating build/lib
creating build/lib/sleekxmpp
copying sleekxmpp/init.py -> build/lib/sleekxmpp
copying sleekxmpp/basexmpp.py -> build/lib/sleekxmpp
creating build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/init.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/base.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/gmail_notify.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0004.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0009.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0030.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0045.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0050.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0060.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0078.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0086.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0092.py -> build/lib/sleekxmpp/plugins
copying sleekxmpp/plugins/xep_0199.py -> build/lib/sleekxmpp/plugins
creating build/lib/sleekxmpp/stanza
copying sleekxmpp/stanza/init.py -> build/lib/sleekxmpp/stanza
copying sleekxmpp/stanza/iq.py -> build/lib/sleekxmpp/stanza
copying sleekxmpp/stanza/message.py -> build/lib/sleekxmpp/stanza
copying sleekxmpp/stanza/presence.py -> build/lib/sleekxmpp/stanza
creating build/lib/sleekxmpp/xmlstream
copying sleekxmpp/xmlstream/init.py -> build/lib/sleekxmpp/xmlstream
copying sleekxmpp/xmlstream/stanzabase.py -> build/lib/sleekxmpp/xmlstream
copying sleekxmpp/xmlstream/statemachine.py -> build/lib/sleekxmpp/xmlstream
copying sleekxmpp/xmlstream/test.py -> build/lib/sleekxmpp/xmlstream
copying sleekxmpp/xmlstream/testclient.py -> build/lib/sleekxmpp/xmlstream
copying sleekxmpp/xmlstream/xmlstream.py -> build/lib/sleekxmpp/xmlstream
creating build/lib/sleekxmpp/xmlstream/matcher
copying sleekxmpp/xmlstream/matcher/init.py -> build/lib/sleekxmpp/xmlstream/matcher
copying sleekxmpp/xmlstream/matcher/base.py -> build/lib/sleekxmpp/xmlstream/matcher
copying sleekxmpp/xmlstream/matcher/many.py -> build/lib/sleekxmpp/xmlstream/matcher
copying sleekxmpp/xmlstream/matcher/xmlmask.py -> build/lib/sleekxmpp/xmlstream/matcher
copying sleekxmpp/xmlstream/matcher/xpath.py -> build/lib/sleekxmpp/xmlstream/matcher
creating build/lib/sleekxmpp/xmlstream/handler
copying sleekxmpp/xmlstream/handler/init.py -> build/lib/sleekxmpp/xmlstream/handler
copying sleekxmpp/xmlstream/handler/base.py -> build/lib/sleekxmpp/xmlstream/handler
copying sleekxmpp/xmlstream/handler/callback.py -> build/lib/sleekxmpp/xmlstream/handler
copying sleekxmpp/xmlstream/handler/waiter.py -> build/lib/sleekxmpp/xmlstream/handler
copying sleekxmpp/xmlstream/handler/xmlcallback.py -> build/lib/sleekxmpp/xmlstream/handler
copying sleekxmpp/xmlstream/handler/xmlwaiter.py -> build/lib/sleekxmpp/xmlstream/handler
error: package directory 'sleekxmpp/xmlstream/tostring26' does not exist

StanzaBase not setting the correct namespace

I encountered this issue while running an XMPP server component and have included the patch below.

As you can see below, the iq namespace is incorrectly set to jabber:client.

2010-05-27 15:04:48,107 DEBUG Loaded Plugin (XEP-0030) Service Discovery
2010-05-27 15:04:48,158 DEBUG Loaded Plugin (XEP-0009) Jabber-RPC
2010-05-27 15:04:48,159 DEBUG Loaded Plugin (XEP-0199) XMPP Ping
2010-05-27 15:04:48,159 DEBUG Connecting to xmpp.example.com:5275
2010-05-27 15:04:48,171 DEBUG Loading event runner
2010-05-27 15:04:48,172 DEBUG SEND: <stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='msm.example.com'>
2010-05-27 15:04:48,177 DEBUG SEND: 9c51ead22f174354980c7f8eaeeb5ca3a3c6904a
2010-05-27 15:04:48,181 DEBUG RECV: <ns0:handshake xmlns:ns0="jabber:component:accept" />
2010-05-27 15:04:48,182 DEBUG XMPP connected
2010-05-27 15:04:48,214 DEBUG RECV: <ns0:iq from="component.example.com" id="738-33951" to="msm.example.com" type="get" xmlns:ns0="jabber:component:accept"><ns1:query xmlns:ns1="http://jabber.org/protocol/disco#info" />/ns0:iq
2010-05-27 15:04:48,245 DEBUG Info request from component.example.com
2010-05-27 15:04:48,245 DEBUG SEND:

The correct response is:

2010-05-27 15:13:40,517 DEBUG Loaded Plugin (XEP-0030) Service Discovery
2010-05-27 15:13:40,558 DEBUG Loaded Plugin (XEP-0009) Jabber-RPC
2010-05-27 15:13:40,558 DEBUG Loaded Plugin (XEP-0199) XMPP Ping
2010-05-27 15:13:40,558 DEBUG Connecting to xmpp.example.com:5275
2010-05-27 15:13:40,563 DEBUG Loading event runner
2010-05-27 15:13:40,563 DEBUG SEND: <stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='msm.example.com'>
2010-05-27 15:13:40,569 DEBUG SEND: f5e5bcabe197da1d798f0929b16c625d83b0778e
2010-05-27 15:13:40,573 DEBUG RECV: <ns0:handshake xmlns:ns0="jabber:component:accept" />
2010-05-27 15:13:40,574 DEBUG XMPP connected
2010-05-27 15:13:40,609 DEBUG RECV: <ns0:iq from="component.example.com" id="161-33961" to="msm.example.com" type="get" xmlns:ns0="jabber:component:accept"><ns1:query xmlns:ns1="http://jabber.org/protocol/disco#info" />/ns0:iq
2010-05-27 15:13:40,637 DEBUG SEND:

This patch fixes the issue:

diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py
index 3f3f5e0..dbec802 100644
--- a/sleekxmpp/xmlstream/stanzabase.py
+++ b/sleekxmpp/xmlstream/stanzabase.py
@@ -319,6 +319,9 @@ class StanzaBase(ElementBase):

def __init__(self, stream=None, xml=None, stype=None, sto=None, sfrom=None, sid=None):
    self.stream = stream
  •   if stream is not None:
    
  •       self.namespace = stream.default_ns
    
  •   self.tag = "{%s}%s" % (self.namespace, self.name)
    ElementBase.**init**(self, xml)
    if stype is not None:
        self['type'] = stype
    

    @@ -326,9 +329,6 @@ class StanzaBase(ElementBase):
    self['to'] = sto
    if sfrom is not None:
    self['from'] = sfrom

  •   if stream is not None:
    
  •       self.namespace = stream.default_ns
    
  •   self.tag = "{%s}%s" % (self.namespace, self.name)
    

    def setType(self, value):
    if value in self.types:

Stream Handler Callback Matching on Outgoing Stream

Here is a short code example that demonstrates the behavior. Send a message from a regular chat client that sends chat state notifications to the agent running this. Messages will be printed out for both incoming and outgoing streams that contain chat states, but only the incoming messages should be printed

# coding=utf8

import sleekxmpp
import logging
from optparse import OptionParser
import time

import sys

from sleekxmpp.xmlstream.handler.callback import Callback
from sleekxmpp.xmlstream.matcher.xpath import MatchXPath
from sleekxmpp.xmlstream.stanzabase import ElementBase, ET, JID

class Test(sleekxmpp.ClientXMPP):   
    def __init__(self, jid, password):
        sleekxmpp.ClientXMPP.__init__(self, jid, password)
        self.add_event_handler("session_start", self.start)
        self.add_event_handler("message", self.message)
        self.test_ns = 'http://jabber.org/protocol/chatstates'
        self.registerPlugin('xep_0030')
        self.plugin['xep_0030'].add_feature(self.test_ns)
        self.registerHandler(
            Callback('Test Stream', 
                 MatchXPath("{%s}message/{%s}%s" % (self.default_ns, 
                                self.test_ns,
                                'active')),
                 self.handle_chatstate))

    def start(self, event):
        self.getRoster()
        self.sendPresence()

    def message(self, msg):
        # These reply messages will be caught by handle_chatstate
        msg.reply("Thanks for sending\n%(body)s" % msg).send()

    def handle_chatstate(self, msg):
        # Will print out both received message with chat states and
        # messages sent with chat states.
        print msg
        msg.reply()
        msg.append(ET.Element('{%s}composing' % self.test_ns))
        msg.send()

if __name__ == '__main__':
    #parse command line arguements
    optp = OptionParser()
    optp.add_option('-q','--quiet', help='set logging to ERROR', action='store_const', dest='loglevel', const=logging.ERROR, default=logging.INFO)
    optp.add_option('-d','--debug', help='set logging to DEBUG', action='store_const', dest='loglevel', const=logging.DEBUG, default=logging.INFO)
    optp.add_option('-v','--verbose', help='set logging to COMM', action='store_const', dest='loglevel', const=5, default=logging.INFO)
    optp.add_option("-c","--config", dest="configfile", default="config.xml", help="set config file to use")
    opts,args = optp.parse_args()

    logging.basicConfig(level=opts.loglevel, format='%(levelname)-8s %(message)s')
    xmpp = Test('manager@localhost/sleekxmpp', 'manager')
    xmpp.registerPlugin('xep_0030')
    xmpp.registerPlugin('xep_0004')
    xmpp.registerPlugin('xep_0060')
    xmpp.registerPlugin('xep_0199')
    if xmpp.connect(('localhost', 5222)):
        xmpp.process(threaded=False)
        print("done")
    else:
        print("Unable to connect.")

Bug in Roster.getItems()

This method don't work, and this line is the cause :

items[JID(itemxml.get('jid'))] = item

Because variables are assigned by reference, the dictionnary is full of the last item values.

I've used this workaround with the help of copy module :

items[JID(itemxml.get('jid'))] = copy.copy(item)

Maybe there are better solutions.

Support for connection throgh Proxy servers ... starting with "basic" authentication ...

Please make support for proxy servers with basic authentication. These kind of net connectivity is more popular in school/university internal networks.

To achive this
1.Connect method need to modified to connect to proxyserver:port 1st ... using the same connect method of socket obj.
2.Than send the connection request to xmpp server along with autherization header through the socket connected to proxy server.

PS: Follwing exmaple is taken form xmpppy .

connector = ['CONNECT %s:%s HTTP/1.0'%self._server,
'Proxy-Connection: Keep-Alive',
'Pragma: no-cache',
'Host: %s:%s'%self._server,
'User-Agent: HTTPPROXYsocket/v0.1']
if self._proxy.has_key('user') and self._proxy.has_key('password'):
credentials = '%s:%s'%(self._proxy['user'],self._proxy['password'])
credentials = base64.encodestring(credentials).strip()
connector.append('Proxy-Authorization: Basic '+credentials)
connector.append('\r\n')
so.send('\r\n'.join(connector))

post_init is not called when loading a plugin with registerPlugin

There are two options for loading plugins: register_plugins and registerPlugin. The first option is for loading all plugins at once, and after it does so (by using registerPlugin to load each plugin) it calls post_init on each plugin. However, if only registerPlugin is used, post_init is not called.

Since post_init is intended for cross-plugin interaction, this can cause trouble with registering service discovery features.

I've made a patch to let registerPlugin call post_init, depending on if a flag passed to it is set. This way register_plugins can delay calling post_init until after all plugins have been loaded and avoid dependency issues.

The only downside to this is that you must handle plugin dependencies yourself (ie, load xep_0030 before xep_0050) for now since things will blow up if the post_init method tries to interact with an unloaded plugin. But that's really not much different than the current situation.

xep-0047 (in-band file transfer) plugin patch

I've created a plugin for xep-0047 (in-band file transfer/byte streams).
http://xmpp.org/extensions/xep-0047.html

The plugin can be found here:
http://github.com/macdiesel/SleekXMPP/blob/master/sleekxmpp/plugins/xep_0047.py

No other changes are necessary for this plugin to work, everything for xep_0047 is self contained in this package.

From the inline doc:
In-band file transfer for xmpp.

Currently only IQ transfer is supported

Plugin will not accept a file transfer if the sender or recipient JID is the
same as the currently logged in JID.

Plugin configuration options:
acceptTransfers        - Boolean     - Sets the plugin to either accept or deny transfers
saveDirectory          - String      - The default directory that incoming file transfers will be saved in
saveNamePrefix         - String      - Prefix that will be prepended to the saved file name of an incoming transfer
overwriteFile          - Boolean     - If an incoming file transfer should overwrite a file if that file already exists
stanzaType             - String      - Either IQ or message,  Currently only iq is supported
maxSessions            - integer     - The max number of send/receive sessions that may run concurrently
transferTimeout        - integer     - How long should a stream session wait between messages
maxBlockSize           - integer     - Largest block size that a stream session should accept (limited by xmpp server)
prefBlockSize          - integer     - The preferred block size for file transfer
acceptTransferCallback - function ptr- This should be a function pointer that will return a boolean value letting the caller know if a 
                                       file transfer should or should not be accepted.  If this option is provided the maxSessions option is ignored.
fileNameCallback       - function ptr- This should be a function pointer that will return a string with the full path and name a file should be saved as.  
                                       If the provided function pointer returns None or is not provided the default saveDirectory + saveNamePrefix_sid will be used.

There are also 2 events that users of this plugin can register to receive notifications:
FILE_FINISHED_SENDING     - This event is fired after a file send has completed
FILE_FINISHED_RECEIVING   - This event is fired after an incoming file transfer has completed.

Add stanzaPlugin method to stanzabase class

There are several instances of the stanzaPlugin floating around, but it should be part of the base stanza class. Also, add it to the documentation for stanza objects.

2 points

xep_0060 plugin broken

All the iq.get('id') calls in the class throws exceptions. As far as I can tell, the get() on Iq objects does not take any parameters and it is overriding the get() in ElementBase which does take a key param.

Handling Plugin Dependencies

Plugins usually have dependencies on other plugins, even though they may not interact with those plugins every time the system is run.

One way to solve the issue of broken dependencies, or just loading plugins in the wrong order, is to record in each plugin the set of plugins it depends on.

The registerPlugin method will then load a plugin and call its plugin_init method, then call a new register_dependencies method, and finally the post_init method.

I should have a patch to implement this behavior ready soon.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.