Compare commits

...

1479 Commits

Author SHA1 Message Date
mathieui
36824379c3 slixmpp 1.2.1
Fix a few bugs along with the testsuite, and remove the asyncio loop
monkeypatch hack.
2016-10-05 20:32:32 +02:00
mathieui
a0a37c19ff Remove monkeypatching hack on the event loop
This allowed us to schedule events in-order later in the event loop, but
was detrimental to using other event loops and debugging.
2016-10-05 20:19:07 +02:00
mathieui
1b5fe57a5e Fix XEP-0060 tests 2016-10-04 21:21:55 +02:00
mathieui
5da31db0c7 Fix stanza accessors case in tests
They were using deprecated (and-removed) style.
2016-10-04 21:15:01 +02:00
mathieui
f8cea760b6 Fix the gmail_notify plugin 2016-10-04 21:10:10 +02:00
mathieui
5ef01ecdd1 Fix XEP-0033
Re-add relevant stanza methods, broken in 7cd1cf32ae
2016-10-04 19:47:11 +02:00
mathieui
62aafe0ee7 Attrib property has been removed 2016-10-04 19:43:45 +02:00
mathieui
cf3f36ac52 Set unset part of a JID to empty string instead of None
it breaks assumptions on the type of the value
2016-10-04 19:42:05 +02:00
mathieui
b88d2ecd77 Add more checks in the XEP-0060 stanza building
Try to not append slixmpp stanzas to ElementTree objects.
2016-10-04 19:31:49 +02:00
mathieui
e691850a2b Fix XEP-0128
Broken since 125336aeee due to unforeseen consequences of a variable
removal.
2016-10-04 19:26:03 +02:00
mathieui
d4bff8dee6 Fix XEP-0009
Broken since 3a9b45e4f because of an overzealous cleanup.
2016-10-04 19:23:21 +02:00
mathieui
187c350805 Update for slixmpp 1.2 2016-10-02 17:36:14 +02:00
mathieui
96d1c26f90 Add a fallback if the lang we want is not available
Previously, trying to get a text node with a lang which is different
from the one we specified would return nothing, which means e.g. a
message would be ignored because its body is of lang 'fr' when we setup
slixmpp to prefer 'en'. We want to return something when there is an
available, valid content in a different language.
2016-10-02 17:12:47 +02:00
mathieui
46a90749f8 Fix uses of super() in the codebase
Fix #3165, we don’t need to use the long form to get the superobject in
our supported python versions.
2016-09-30 21:25:36 +02:00
mathieui
0c63a4bbda Fix #3226 (unicity of scheduled event names)
Thanks tchiroux for raising the issue and providing the fix as well.
2016-09-30 20:59:31 +02:00
mathieui
e4696e0471 Merge branch 'doc_fixes' of https://github.com/SamWhited/slixmpp 2016-09-30 20:53:36 +02:00
Sam Whited
8217dc5239 Minor documentation fixes 2016-09-30 13:49:04 -05:00
mathieui
2586abc0d3 Fix xep-0050 stanza
broken in 3a9b45e4f2
2016-09-20 20:51:21 +02:00
Emmanuel Gil Peyrot
28f84ab3d9 ElementBase: Remove support for TitleCase methods.
This gains about 1/8th of the time spent in __getitem__.
2016-09-21 01:31:53 +09:00
Emmanuel Gil Peyrot
813b45aded XEP-0045: Remove support for old-style {get,set,del}TitleCase methods. 2016-09-21 01:28:24 +09:00
Emmanuel Gil Peyrot
3a9b45e4f2 ElementBase: Remove deprecated find() and findall() methods. 2016-09-20 16:45:29 +09:00
Emmanuel Gil Peyrot
b8e091233e XEP-0004: Remove deprecated getXML() and fromXML() methods. 2016-09-20 16:34:48 +09:00
Emmanuel Gil Peyrot
0edeefd977 BaseXMPP: Stop automatically enabling UserNick, and remove deprecated alias module. 2016-09-20 16:23:02 +09:00
Emmanuel Gil Peyrot
6ba53cf1ff ElementBase: Remove attrib interface. 2016-09-20 16:23:02 +09:00
Emmanuel Gil Peyrot
d7758eb7f4 ElementBase: Remove subitem interface. 2016-09-20 16:23:02 +09:00
Emmanuel Gil Peyrot
125336aeee Remove locking from static disco. 2016-09-20 16:23:02 +09:00
Emmanuel Gil Peyrot
7cd1cf32ae Various XEPs: Remove deprecated aliases. 2016-09-20 16:23:02 +09:00
Emmanuel Gil Peyrot
d099e353a4 Implement XEP-0333: Chat Markers. 2016-08-26 22:42:24 +01:00
Emmanuel Gil Peyrot
1e4a301c6e Replace _format_jid with a JID method updating both bare and full at the same time. 2016-08-26 22:25:58 +01:00
mathieui
f53b12d227 Fix the MUC address in contributing.rst 2016-08-23 23:10:17 +02:00
Dan Sully
e2562dcccf Make session_bind_event awaitable 2016-08-23 23:05:22 +02:00
louiz’
7b69ae3738 Add a contributing file 2016-08-24 00:33:07 +02:00
Emmanuel Gil Peyrot
ab6df235d7 Pre-compute JID bare and full forms, and store that in each JID.
This wins about 4s over a 54s real-world benchmark.
2016-08-22 23:43:16 +01:00
mathieui
52cd8f4b22 Don’t trigger presence events on MUC presence
Specifically, previously, each MUC would be added as a roster item, and
then each join presence would be counted as a resource of that item,
triggering 1 to 5 events and more backend logic in slixmpp.

As a result, joining big rooms is tremendously slow, (JID() calls,
event() calls, __getitem__ calls for nothing), and takes RAM (a quick
tracemalloc tells me around 1 MiB for 3500 participants, i.e. 2 big IRC
rooms). Those resources may not necessarily be cleaned properly, leading
to memory leaks on long-term usage.

This is a micro-optimization that adds an attribute to roster items so
that MUC room events can be ignored safely while not affecting common
roster usage.
2016-08-22 01:29:07 +02:00
Emmanuel Gil Peyrot
e28318c271 Micro-optimise _format_jid. 2016-08-21 20:26:51 +01:00
mathieui
39ee833c29 Improve XEP-0070 and examples 2016-08-19 23:48:37 +02:00
Emmanuel Gil Peyrot
9019e2bc71 Initial work on XEP_0070, plugin and examples 2016-08-19 23:48:29 +02:00
louiz’
9208bf5bf1 Merge remote-tracking branch 'zejn/master' 2016-08-19 11:18:27 +02:00
Emmanuel Gil Peyrot
f0f1698e46 ElementBase: micro-optimise __getitem__, hands down the most often called function
This makes it go down from 8.767s to 7.960s in a random benchmark.

Remove unnecessary assignations, don’t create an OrderedDict from a
dict to then convert it to a dict again, only obtain the get_method2
name if get_method wasn’t present.

get_method2 (the title-case one) takes about 1/8th of the total time
spent in this function, we should eliminate it as soon as possible.
2016-08-17 00:46:56 +01:00
Gasper Zejn
eccd7f1c98 Provide domain name to loop.create_connection if using SSL. 2016-08-12 15:32:42 +02:00
Emmanuel Gil Peyrot
2587d82af8 Make util.XOR about ten times faster by calling bytes only once. 2016-07-30 00:14:54 +01:00
mathieui
7ea121b115 Don’t swallow presence exceptions abritrarily 2016-06-28 20:58:47 +02:00
mathieui
bb81fbbdfc Implement XEP-0256 (last activity in presence)
mostly useless, but allows to use LastActivity stanzas inside Presence
stanzas as well.
2016-06-05 02:04:52 +02:00
mathieui
1a00a08b7d Make XEP-0186 return futures as well
Improving the api if the developer wants to wait on them.
2016-06-05 00:19:24 +02:00
mathieui
90ea2a3411 Implement XEP-0352 (client state indication) 2016-06-04 22:59:23 +02:00
mathieui
8fc6814b6d Update XEP-0198 for asyncio 2016-06-04 20:51:59 +02:00
mathieui
ffced0ed9a Add a xep-0334 plugin 2016-06-04 19:34:12 +02:00
mathieui
e7248d9af9 Fix the Waiter handler for asyncio 2016-05-28 20:53:41 +02:00
mathieui
6b1a04f59d Fix xep-0199
The keepalive ping was not working, and and ping() was tracebacking due
to a wrong parameter.
2016-05-28 15:13:33 +02:00
mathieui
4905407092 Fix the ordering of stream features
since iq.send is non-blocking, some features handlers could end up
being executed before others were set, leading to issues. Adding yield
from where it’s necessary fixes that.
2016-05-28 14:46:39 +02:00
louiz’
bd6ec10939 Add some credits 2016-03-15 09:35:36 +01:00
Sam Whited
e15e6735f1 The XEP-0198 plugin exists now; fix the docs 2016-03-14 23:59:01 +01:00
mathieui
67afd6a462 Fix #3166 (broken link) 2016-02-03 22:43:47 +01:00
mathieui
2e2b97c53b Merge branch 'xep_0012_fix' of https://github.com/misuzu/slixmpp 2016-01-21 23:22:28 +01:00
Tsukasa Hiiragi
a35df7fe1f Fixed NameError in start_uptime 2016-01-21 14:59:03 +02:00
Krzysztof Kotlenga
fbc8562779 Remove dead code
See 5c769632e8.
2015-12-15 19:44:29 +01:00
mathieui
b549db959a Update version to 1.1 2015-10-02 19:35:29 +02:00
mathieui
d5188ac68a Mention the build of cython modules in the README 2015-10-02 19:22:26 +02:00
mathieui
ada9444bf8 Merge branch 'sleek-merge' 2015-10-02 19:07:45 +02:00
mathieui
acc52fd935 Merge branch 'develop' of https://github.com/fritzy/SleekXMPP into sleek-merge
Conflicts:
	README.rst
	examples/IoT_TestDevice.py
	examples/disco_browser.py
	setup.py
	sleekxmpp/jid.py
	sleekxmpp/plugins/google/auth/stanza.py
	sleekxmpp/plugins/google/gmail/notifications.py
	sleekxmpp/plugins/google/nosave/stanza.py
	sleekxmpp/plugins/google/settings/settings.py
	sleekxmpp/thirdparty/__init__.py
	sleekxmpp/thirdparty/socks.py
	sleekxmpp/thirdparty/statemachine.py
	sleekxmpp/util/__init__.py
	sleekxmpp/xmlstream/xmlstream.py
	slixmpp/basexmpp.py
	slixmpp/plugins/xep_0004/stanza/form.py
	slixmpp/plugins/xep_0009/rpc.py
	slixmpp/plugins/xep_0050/adhoc.py
	slixmpp/plugins/xep_0065/proxy.py
	slixmpp/plugins/xep_0084/stanza.py
	slixmpp/plugins/xep_0202/time.py
	slixmpp/plugins/xep_0323/sensordata.py
	slixmpp/plugins/xep_0325/control.py
	slixmpp/plugins/xep_0325/stanza/control.py
	slixmpp/roster/single.py
	slixmpp/stanza/atom.py
	slixmpp/stanza/rootstanza.py
	slixmpp/test/slixtest.py
	slixmpp/util/sasl/mechanisms.py
	slixmpp/version.py
	slixmpp/xmlstream/stanzabase.py
	tests/test_stanza_xep_0323.py
	tests/test_stanza_xep_0325.py
	tests/test_stream_xep_0323.py
	tests/test_stream_xep_0325.py
2015-10-02 19:00:19 +02:00
mathieui
1100ff1feb Reset the DNS answers after a connection is made succesfully 2015-09-25 19:34:04 +02:00
mathieui
c17fc3a869 Fix IPv6 resolving with aiodns 1.0 2015-09-24 19:38:53 +02:00
mathieui
4dba697075 Fix support for python 3.4 <= 3.4.2
asyncio module is provisional, which means it gets updated everytime
2015-09-23 23:23:02 +02:00
mathieui
e42d651d7e Fix connecting to a custom host/port 2015-09-19 15:27:12 +02:00
Mike Taylor
4305eddb4f Merge pull request #397 from rerobins/xep_0050_updates
Xep 0050 updates
2015-09-18 16:18:41 -04:00
Robert Robinson
c2dc44cfd1 Merge branch 'develop' into xep_0050_updates
# Conflicts:
#	tests/test_stream_xep_0050.py
2015-09-18 13:35:28 -06:00
Robert Robinson
5fc14de32e Merge pull request #3 from fritzy/develop
Merge to fritzy_master
2015-09-18 13:30:30 -06:00
Mike Taylor
d245558fd5 Merge pull request #396 from rerobins/add_xep_0122
XEP_0122: Add support for form validation
2015-09-18 15:15:27 -04:00
Mike Taylor
9d45370e8a Merge pull request #393 from aalba6675/fix/time
Only send time if Iq type is get.
2015-09-18 15:15:01 -04:00
Mike Taylor
cc1cc61d36 Merge pull request #392 from aalba6675/fix/tel_number
Do not overwrite telephone numbers
2015-09-18 15:14:35 -04:00
Mike Taylor
c6740a4908 Merge pull request #389 from alexdraga/develop
Add get users by affiliation.
2015-09-18 15:13:54 -04:00
Mike Taylor
55114bcffe Merge pull request #384 from elya5/patch-1
Fix UnboundlocalError in disco_browser.py example
2015-09-18 15:13:30 -04:00
Mike Taylor
4fa5dedc47 Merge pull request #386 from jdowner/develop-iot
iot: only add the 'done' field when all devices are done
2015-09-18 15:13:07 -04:00
Mike Taylor
5525ef2285 Merge pull request #395 from rerobins/refactor_forms
XEP_0004: Data Forms use register_stanza_plugin
2015-09-18 15:11:47 -04:00
Robert Robinson
a7ac969215 register_Stanza_plugin shouldn't be iterable
Should not use iterable for registering the stanza plugins.
2015-09-17 16:21:54 -06:00
Robert Robinson
329cb5a9f8 Add 0122 to plugin/__init__.py __all__ 2015-09-17 16:21:13 -06:00
Robert Robinson
d9b47b33f5 Update __init__.py
changed xep_0121 to xep_0122
2015-09-15 10:20:37 -06:00
Robert Robinson
3582ac9941 Merge branch 'add_xep_0122' of https://github.com/rerobins/SleekXMPP into add_xep_0122 2015-09-15 10:12:50 -06:00
Robert Robinson
2a127a57a7 Add test case Reported->Data Form Validation
Add a test case that will verify that reported fields can contain data form validation data.
2015-09-15 10:09:06 -06:00
Robert Robinson
7059400020 Merge branch 'refactor_forms' into add_xep_0122 2015-09-15 10:07:34 -06:00
Robert Robinson
0b14ef82d4 Add test case for reported and items
Previous stanza test cases didn't have test cases for reported and item field types in forms.   This fixes that issue.

Modified stanzabase to use an ordered dict so that can guarentee the that 'items' in a form are added after reported.  Also updated the set of interfaces that are stored in Form to be a ordered set.  Used the order set implementation from:  https://code.activestate.com/recipes/576694/

The OrderedSet implementation is licensed under the MIT license and is developed by the same developer of the ordereddict.
2015-09-15 10:05:53 -06:00
Robert Robinson
83953af53d Missing xep_122 dir in setup.py 2015-09-14 20:28:55 -06:00
Robert Robinson
110cf25c6d Add plugin support 2015-09-14 17:06:07 -06:00
Robert Robinson
f2bf6072ec Add plugin
(cherry picked from commit 2296d56)
2015-09-14 17:04:43 -06:00
Robert Robinson
5f9abe2e0e Working through test case issues.
(cherry picked from commit 6b58cef)
2015-09-14 17:04:16 -06:00
Robert Robinson
ea65b672e7 Initial cut at getting the stanzas to work.
(cherry picked from commit 8c7df49)
2015-09-14 17:04:08 -06:00
Robert Robinson
93c705fb31 Fix xep_0050 changes after form refactor. 2015-09-14 17:00:53 -06:00
Robert Robinson
0724f623bb Force forms and fields to use plugin resolution
Instead of using the interface/subinterface code that was currently being implemented for the plugin.
(cherry picked from commit 1467ec7)
2015-09-14 16:46:36 -06:00
mathieui
82e549c0e9 (Temporary) fix for python 3.5
This will work until the old ssl implementation is finally deprecated.
Hopefully, new features to painlessy implement starttls will be around
by then.
2015-09-14 23:14:53 +02:00
mathieui
1aa15792b4 Bump the requirements to aiodns 1.0
(and use install_requires instead of requires in the setup.py)
2015-09-14 23:14:06 +02:00
Robert Robinson
ffb2b6bc04 Update test_stream_xep_0050.py
Fix Unit Test for adhoc 50 stream.
2015-09-12 20:08:21 -06:00
Emmanuel Gil Peyrot
27f98bf22c xep_0231: Fix a traceback on result serialization. 2015-09-05 18:35:59 +01:00
mathieui
3978078710 vcard-temp: add some checks against wrong input 2015-09-04 01:59:40 +02:00
mathieui
00a0698720 Add timeout_callback to a bunch of plugins as a parameter 2015-09-04 01:05:56 +02:00
Robert Robinson
4a24f58be2 XEP0050: Add support for payload in completed response
When sending the command to complete the task, the adhoc plugin does not provide the ability to send a payload from the _handle_command_complete method.
2015-09-03 10:15:41 -06:00
Mike Taylor
da14ce16ec Merge pull request #394 from sangeeths/misc_updates
adding 'id' to self['xep_0332'].send_request()
2015-08-27 13:00:34 -04:00
Sangeeth Saravanaraj
18e5abb9dd adding 'id' to self['xep_0332'].send_request() 2015-08-27 13:24:01 +05:30
Richard Chan
1a75b76916 Only send time if Iq type is get. 2015-08-25 18:21:58 +08:00
Richard Chan
53b56899a0 Do not overwrite telephone numbers; otherwise all TEL/NUMBER received
from a server will be blank.
2015-08-25 18:11:54 +08:00
mathieui
804b23d390 Merge branch 'socks5' of http://git.linkmauve.fr/slixmpp 2015-08-23 17:14:53 +02:00
Emmanuel Gil Peyrot
04eaf52b1d xep_0065: Remove an unused variable. 2015-08-23 16:06:01 +01:00
Emmanuel Gil Peyrot
dc7fef1064 xep_0065: Remove the last useless threading locks. 2015-08-23 16:06:01 +01:00
Emmanuel Gil Peyrot
488c433555 Add SOCKS5 Bytestream examples. 2015-08-23 16:06:01 +01:00
Emmanuel Gil Peyrot
9c5dd024b1 Fix the xep_0065 plugin, by rewriting its socks5 implementation. 2015-08-23 16:06:01 +01:00
Florent Le Coz
6e61adf3db Fix the order in which <identity/> and <feature/> tags are sent on disco#info
The identities should all be at the start, and features at the end, so we
just prepend the identity on add_identity, and append features on
add_feature
2015-08-22 18:48:29 +02:00
Emmanuel Gil Peyrot
041bd63864 Add a function to convert a domain name to punycode. 2015-08-20 20:04:58 +01:00
Aleksandr Draga
a366482551 Add get users by affiliation. 2015-08-10 15:34:27 +03:00
Emmanuel Gil Peyrot
a721084f6e Fix the pubsub_client example. 2015-08-08 17:34:06 +02:00
Emmanuel Gil Peyrot
1b4187fa56 Add a format() method to XMPPError which returns a readable string. 2015-08-08 17:34:06 +02:00
Emmanuel Gil Peyrot
cf7a60705e Fix docstring of unsubscribe method in the PubSub plugin. 2015-08-08 17:34:06 +02:00
Emmanuel Gil Peyrot
349b05b9b7 Stop disco_browser and pubsub_client examples once they are finished. 2015-08-08 17:34:06 +02:00
Emmanuel Gil Peyrot
9fbacf377a Strip strings after pygments, so we don’t include an needless newline. 2015-08-08 17:34:06 +02:00
mathieui
2da9e35cbc Add missing files to the MANIFEST 2015-08-08 17:34:06 +02:00
mathieui
8adc8fa2ba Update README 2015-08-08 17:34:06 +02:00
mathieui
9efa909dfc slixmpp v1.0 2015-08-08 17:34:06 +02:00
mathieui
7f21fdbe26 Fix the test suite
(mock transport class missing .close())
2015-08-08 17:34:06 +02:00
mathieui
f9c7fa92ea Reset the connect future after a disconnect 2015-08-08 17:34:05 +02:00
Florent Le Coz
e75a160d52 Remove a useless line of code from “your first XMPP bot” example 2015-08-08 17:34:05 +02:00
Emmanuel Gil Peyrot
170bd51387 Properly answer an error instead of tracebacking on unknown command execution. 2015-08-08 17:33:59 +02:00
Mike Taylor
abcec1e2d3 Merge pull request #388 from sangeeths/misc_updates
Retaining 'id' in the response and error stanzas
2015-08-01 14:04:22 -04:00
Sangeeth Saravanaraj
eeab646bfa Retaining 'id' in the response and error stanzas 2015-08-01 17:47:03 +05:30
Mike Taylor
2c69144189 Merge pull request #387 from mcella/378
Fixes #378: must acquire JID_CACHE_LOCK before adding to JID_CACHE
2015-07-31 11:21:01 -04:00
Michele Cella
f54ebec654 Fixes #378: must acquire JID_CACHE_LOCK before adding to JID_CACHE 2015-07-31 11:55:50 +02:00
mathieui
2ce931cb7a Add a waiting time before reconnecting automatically
Punishing a server for being down by sending more traffic is not a nice
thing to do. Taking 100% of the CPU is not nice either.
2015-07-21 00:58:52 +02:00
mathieui
84eddd2ed2 Fix components
(use_tls is useless since slixmpp will always try to use starttls
whenever possible)
2015-07-21 00:33:15 +02:00
Joshua Downer
2042e1a4d5 iot: only add the 'done' field when all devices are done 2015-07-20 17:34:09 -04:00
Robert Robinson
be14f0cc52 XEP_0050: Form not iterable in command
Cannot pass in a form into the initial command and have it show up in the payload of the session.  Line 344 makes this possible when following the standard workflow.
2015-07-15 20:52:06 -06:00
elya5
edd9199be8 Fix UnboundlocalError in disco_browser.py example
If self.get is in self.info_types and self.items_types, only self['xep_0030'].get_info is executed and not self['xep_0030'].get_items. So the condition in line 129 is successful but items is not assigned.
2015-07-09 17:15:36 +02:00
Mike Taylor
bb094cc649 Merge pull request #365 from jdowner/staging
Fixed imports
2015-07-05 15:46:04 -04:00
Mike Taylor
dbaa6ed952 Merge pull request #366 from jdowner/develop-iot-cleanup
Minor cleanup of IoT plugin
2015-07-05 15:45:47 -04:00
Mike Taylor
8c94d894ab Merge pull request #369 from stevenroose/patch-2
Change to roster migration e
2015-07-05 15:45:19 -04:00
Mike Taylor
ffc7eac4dc Merge pull request #370 from jdowner/develop-jid
Removed duplicate property
2015-07-05 15:44:58 -04:00
Mike Taylor
555fd6d926 Merge pull request #380 from anirudh-chhangani/XEP-0096-add-hash-param
add hash metadata for file transfer
2015-07-05 15:44:03 -04:00
Mike Taylor
c024ac8f0b Merge pull request #382 from sangeeths/initialize_certificate
Initialize certfile, keyfile and ca_certs in XMLStream. Added **kwargs to ClientXMPP, BaseXMPP and XMLStream.
2015-07-03 15:07:35 -04:00
Sangeeth Saravanaraj
f00177c0cf Added **kwargs to ClientXMPP, BaseXMPP and XMLStream so that certfile, keyfile and ca_certs can be initialized. 2015-07-03 10:47:06 +05:30
mathieui
d0ad25745a Merge branch 'jid' of http://git.linkmauve.fr/slixmpp 2015-06-22 23:56:05 +02:00
Emmanuel Gil Peyrot
55be23a6da Update the INSTALL file, and add a point about Cython. 2015-06-22 01:16:33 +01:00
Emmanuel Gil Peyrot
75ba283572 Store None instead of '' for unset parts of a JID. 2015-06-22 01:12:56 +01:00
mathieui
f7164d35d2 Add a wrapper to get_info/get_items functions
(and fix caps in the process)
2015-06-21 16:23:47 +02:00
Emmanuel Gil Peyrot
4afbb0322b Rework slixmpp.jid’s JID classes to make them more efficient. 2015-06-20 01:49:48 +01:00
Emmanuel Gil Peyrot
7bce1ecc8a Add a Cython version of slixmpp.stringprep, using libidn.
This makes the validation of a JID a *lot* faster.
2015-06-20 01:14:46 +01:00
Emmanuel Gil Peyrot
bbce16d526 Move stringprep and idna support in a different module than slixmpp.jid. 2015-06-20 01:14:46 +01:00
Emmanuel Gil Peyrot
c29fc39ef1 Remove JID cache, to better test for performance. 2015-06-20 01:12:03 +01:00
Emmanuel Gil Peyrot
8335c08782 Fix test_jid to not use deprecated ways to create JID objects, and add it a few more tests. 2015-06-20 01:12:03 +01:00
Anirudh
224d7ae133 add hash param to file metadata 2015-06-18 00:21:19 +05:30
Emmanuel Gil Peyrot
04bff00171 XEP-0030: return the iq.send() future when sending a disco#info or disco#items. 2015-06-14 15:11:24 +01:00
Emmanuel Gil Peyrot
f3e31baf04 Properly consider malformed IPv6 domains as invalid. 2015-06-12 11:52:48 +01:00
Sangeeth Saravanaraj
9b25a7cf77 Fixed typo. 2015-06-05 12:25:41 +05:30
Joshua Downer
7a908ac07b Removed duplicate property 2015-05-28 09:35:50 -04:00
Steven Roose
92901637ec Change to roster migration example
I did have the chance to test the script yet, but it seems like that line should be outside the for loop.
2015-05-25 01:01:08 +02:00
Joshua Downer
3590b663ed xep-0323: removed deadcode 2015-05-14 06:27:59 -04:00
Joshua Downer
a33bde9cc3 xep-0323: spelling 2015-05-14 06:27:39 -04:00
Joshua Downer
ac50fdccfc xep-0323: unused import 2015-05-14 06:26:54 -04:00
Joshua Downer
a0c6bf15e9 Fixed imports
Removed unused modules/packages and added getpass, which was missing.
2015-05-13 17:24:06 -04:00
mathieui
a2852eb249 Allow the use of a custom loop instead of asyncio.get_event_loop() 2015-05-12 00:02:32 +02:00
mathieui
f1e6d6b0a9 Advertize the disco#info feature in our disco#info
Actually a MUST in XEP-0030
2015-05-08 13:41:20 +02:00
Emmanuel Gil Peyrot
116a33ba51 Make syntax highlighting for XML lazy, to only call pygments when debug logs are enabled.
Makes poezio about 11% faster when sending/receiving messages.
2015-05-06 13:03:47 +02:00
Mike Taylor
a8ac115310 Merge pull request #363 from sangeeths/xep_0332
XEP_332: Prefixed request and response with "http"
2015-05-01 12:50:06 -04:00
Sangeeth Saravanaraj
1345b7c1d0 Misc updates for send_error() 2015-05-01 15:34:53 +05:30
Sangeeth Saravanaraj
d60a652259 data need not be prefixed with http.. 2015-05-01 14:32:36 +05:30
Sangeeth Saravanaraj
61a7cecb31 Prefixed request, response and data with http. Avoided (plugin_attrib) name collision with other plugins. 2015-04-29 14:44:25 +05:30
Mike Taylor
192b7e0349 Merge pull request #345 from sangeeths/xep_0332
XEP-0332: HTTP over XMPP transport
2015-04-28 22:44:27 -04:00
Sangeeth Saravanaraj
80b60fc048 Merge remote-tracking branch 'origin/develop' into xep_0332 2015-04-28 16:53:40 +05:30
mathieui
b8d7b9520c Fix some disco tests
The targeted JID was a bare JID, which is wrong since the XEP specifies
that such disco requests are handled by the server.
2015-04-21 20:10:47 +02:00
mathieui
0305ce66b7 Merge branch 'ibb' of http://linkmauve.fr/git/slixmpp 2015-04-19 20:53:35 +02:00
Emmanuel Gil Peyrot
474405ab90 XEP-0047: fix examples. 2015-04-19 20:48:02 +02:00
Emmanuel Gil Peyrot
4415d3be1a XEP-0047: use coroutines for send(), sendall() and the new sendfile(). 2015-04-19 20:48:02 +02:00
Emmanuel Gil Peyrot
058c530787 XEP-0047: prevent any unneededly large or useless bytes slice. 2015-04-19 20:48:01 +02:00
Emmanuel Gil Peyrot
766d0dfd40 XEP-0047: use asyncio’s Queue implementation, to prevent any possibility of deadlock. 2015-04-19 20:48:01 +02:00
Emmanuel Gil Peyrot
ac31913a65 XEP-0047: make open_stream() return a future that will be set to the stream object. 2015-04-14 19:14:56 +02:00
Emmanuel Gil Peyrot
d34ddf33db XEP-0047: replace threading events with simple booleans. 2015-04-14 19:14:56 +02:00
Emmanuel Gil Peyrot
eb4e09b0ca XEP-0047: allow only one window over the stream. 2015-04-14 19:14:56 +02:00
Emmanuel Gil Peyrot
ce085bf4f4 XEP-0047: announce the correct stanza type if message is selected. 2015-04-14 19:14:56 +02:00
Emmanuel Gil Peyrot
990113f8e7 XEP-0047: return the correct error type on not-acceptable (example 5). 2015-04-14 19:14:56 +02:00
Emmanuel Gil Peyrot
aa022204ee XEP-0047: don’t answer with an unauthorized error when block-size is too big. 2015-04-14 19:14:56 +02:00
Emmanuel Gil Peyrot
c1f23b566b XEP-0047: remove now-useless threading locks. 2015-04-14 19:14:56 +02:00
Emmanuel Gil Peyrot
45f7cb8bda XEP-0047: prevent tracebacks in stanza reading. 2015-04-14 19:14:56 +02:00
mathieui
bdb1f66ac9 basexmpp: Add a message_error event
The "message" event only receives messages with a body, and error
messages don’t necessarily have it. Removing the body requirement from
the "message" event could lean to unhandled conditions in existing code.
2015-04-13 15:08:04 +02:00
Mike Taylor
842157a6cc Merge pull request #187 from ekini/xep_0138
added xep-0138 support (compression)
2015-04-11 20:58:45 -04:00
Mike Taylor
a63cc01482 Merge pull request #316 from rakoo/develop
Extend AtomEntry capabilities
2015-04-11 20:53:44 -04:00
bear (Mike Taylor)
1bbb6f3ff9 Merge branch 'hildjj-develop' into develop 2015-04-11 20:43:56 -04:00
bear (Mike Taylor)
93894247a4 Merge branch 'develop' of https://github.com/hildjj/SleekXMPP into hildjj-develop 2015-04-11 20:42:33 -04:00
Mike Taylor
16bb5e2537 bump to version v1.4 2015-04-11 20:38:11 -04:00
Mike Taylor
d19a6e05b2 remove python v3.1 - v3.3 from tox.ini 2015-04-11 20:37:05 -04:00
Mike Taylor
86e85f9835 Merge pull request #313 from mayflower/develop
Proposing #310 again in fixed version
2015-04-11 20:12:19 -04:00
Mike Taylor
cc145d20b0 Merge pull request #297 from keith-gray-powereng/develop
Fixed a unicode error in xep_0065 on Python 3
2015-04-11 19:49:43 -04:00
Mike Taylor
881d9040c4 Merge pull request #329 from FlySnake/send_queue_overflow
In queues added option to remove first element on addind new if queue is full
2015-04-11 19:46:26 -04:00
Mike Taylor
1e77ea0944 Merge pull request #328 from FlySnake/develop
On initial connect use delay if connection failed
2015-04-11 19:20:39 -04:00
Mike Taylor
140f0885b2 Merge pull request #331 from mathieui/develop
Fix the element name for retrieving certs in XEP-0257
2015-04-11 19:15:26 -04:00
Mike Taylor
83f71a6610 Merge pull request #348 from gribouille-dev/tor_fixes
Makes XEP-0009 compatible with Python 2 & 3.
2015-04-11 18:32:42 -04:00
Mike Taylor
271343a32d Merge pull request #349 from mulog1990/ssl-version-fix
ssl-version not passed to wrap_socket, fixed
2015-04-11 18:26:05 -04:00
Mike Taylor
48857b0030 Merge pull request #354 from erigones/develop
Fixed bug #353 Python3 XEP-0084 error
2015-04-11 18:12:40 -04:00
Mike Taylor
1fe7f5f4e6 Create .travis.yml 2015-04-11 17:45:23 -04:00
Emmanuel Gil Peyrot
d5b1904ebb Use a full JID for testing. 2015-04-04 16:56:26 +02:00
Emmanuel Gil Peyrot
b6b0e82dec Iq.send: set the timeout even when no timeout_callback is set 2015-04-04 16:48:30 +02:00
Emmanuel Gil Peyrot
632b7b4afe XMLStream: add a forever parameter to process(), defaulting to True, to select whether we want to stop the event loop after a disconnection 2015-04-04 16:48:30 +02:00
Richard Kellner
81b7b2c190 Fixed bug #353 Python3 XEP-0084 error 2015-03-25 14:04:46 +01:00
mulog1990
460de7d301 ssl-version not passed to wrap_socket, fixed 2015-03-10 18:13:53 +08:00
Cédric Souchon
69022c6db7 Makes XEP-0009 compatible with Python 3 while maintaining compatibility with Python 2.6 and up. 2015-03-09 12:33:18 +01:00
Emmanuel Gil Peyrot
0ef3fa2703 XMLStream: factorize the highlight function so it can be used in tests as well 2015-03-02 17:10:27 +01:00
mathieui
8da269de88 Set XMLStream.socket after the SSL connection is made too
Fixes SCRAM-SHA-1-PLUS.
2015-02-28 20:32:33 +01:00
mathieui
93ce318259 XEP-0325: Don’t use threading 2015-02-28 19:05:22 +01:00
mathieui
997928de91 Revert or edit most previous XEP plugin changes
In a single commit, because it isn’t that interesting to detail each
change.

List of reverts:

Revert "XEP-0030: allow get_info and get_items to return a coroutine"
    This reverts commit 506ca69917.

Revert "XEP-0060: wrap all iq-sending functions with coroutine_wrapper"
    This reverts commit e85fa4203e.

Revert "XEP-0163: wrap publish() with coroutine_wrapper"
    This reverts commit 69da1c1d7c.

Revert "XEP-0084: wrap functions with coroutine_wrapper"
    This reverts commit ea5615f236.

Partially revert 3d243f7 (XEP-0054) - continue wrapping functions but with future_wrapper

Partially revert 115fe95 (xep-0153) - use callbacks rather than coroutine callbacks, and propagate iqtimeouts in set_avatar.

Revert "XEP-0049: wrap functions with coroutine_wrapper"
    This reverts commit e68135f59f.

Revert "XEP-0077: wrap functions with coroutine_wrapper"
    This reverts commit 1e4944d47e.

Partially revert cd7ff685 (XEP-0199) - remove the iq.send wrapping but keep ping() as a coroutine

Revert "XEP-0257: wrap functions with coroutine_wrapper"
    This reverts commit 4da870fd19.

Revert "XEP-0092: wrap get_version() with coroutine_wrapper"
    This reverts commit 6e35948276.

Revert "XEP-0191: wrap functions with coroutine_wrapper"
    This reverts commit 6e8235544c.

Revert "XEP-0280: wrap functions with coroutine_wrapper"
    This reverts commit f795ac02e3.

Revert "XEP-0012: wrap get_last_activity() with coroutine_wrapper"
    This reverts commit 2ee05d9616.

Revert "XEP-0202: wrap get_entity_time() with coroutine_wrapper"
    This reverts commit 6fb3ecd414.

Revert "XEP-0231: wrap get_bob() with coroutine_wrapper"
    This reverts commit 17464b10a4.

Revert "XEP-0258: wrap get_catalog() with coroutine_wrapper"
    This reverts commit 18a4978456.

Revert "XEP-0050: wrap send_command() and get_commands() with coroutine_wrapper"
    This reverts commit e034b31d6b.

Revert "XEP-0279: wrap check_ip() with coroutine_wrapper"
    This reverts commit e112e86475.
2015-02-28 19:02:49 +01:00
mathieui
83d00a5913 Fix examples relying on the changed API 2015-02-28 19:02:44 +01:00
mathieui
bf5d7c83af Change the API to make iq.send() always return a future
remove coroutine_wrapper, add a future_wrapper (which is only needed
when the result stanza can be cached).

Update the documentation as well.
2015-02-28 19:02:35 +01:00
mathieui
c66a4d4097 Update the documentation and examples
- update most of the examples with slixmpp
- change the help channels pointed out in the doc
- add a page listing differences from slixmpp and how to use asyncio
  nicely with slixmpp
- fix some in-code rst documentation
2015-02-24 22:47:15 +01:00
mathieui
e112e86475 XEP-0279: wrap check_ip() with coroutine_wrapper 2015-02-24 22:46:08 +01:00
mathieui
e034b31d6b XEP-0050: wrap send_command() and get_commands() with coroutine_wrapper
(if flow=True in send_command, the result will still be using the
default callbacks and the function will return None)
2015-02-24 22:46:07 +01:00
mathieui
18a4978456 XEP-0258: wrap get_catalog() with coroutine_wrapper 2015-02-24 22:46:07 +01:00
mathieui
17464b10a4 XEP-0231: wrap get_bob() with coroutine_wrapper 2015-02-24 22:46:07 +01:00
mathieui
6fb3ecd414 XEP-0202: wrap get_entity_time() with coroutine_wrapper 2015-02-24 22:46:07 +01:00
mathieui
c214e4f037 XEP-0084: fix setting and getting the Data value
get_value: return a bytes object
set_value: accept a bytes or a str object
2015-02-24 22:46:06 +01:00
mathieui
2ee05d9616 XEP-0012: wrap get_last_activity() with coroutine_wrapper 2015-02-24 22:46:06 +01:00
mathieui
f795ac02e3 XEP-0280: wrap functions with coroutine_wrapper 2015-02-24 22:46:06 +01:00
mathieui
6e8235544c XEP-0191: wrap functions with coroutine_wrapper 2015-02-24 22:46:06 +01:00
mathieui
6e35948276 XEP-0092: wrap get_version() with coroutine_wrapper 2015-02-24 22:46:05 +01:00
mathieui
4da870fd19 XEP-0257: wrap functions with coroutine_wrapper 2015-02-24 22:46:05 +01:00
mathieui
cd7ff685fb XEP-0199: wrap functions with coroutine_wrapper and make ping() a coroutine 2015-02-24 22:46:05 +01:00
mathieui
1e4944d47e XEP-0077: wrap functions with coroutine_wrapper 2015-02-24 22:46:05 +01:00
mathieui
e68135f59f XEP-0049: wrap functions with coroutine_wrapper 2015-02-24 22:46:04 +01:00
mathieui
6408c5a747 XEP-0115: fix a handler which expected an iq to block 2015-02-24 22:46:04 +01:00
mathieui
115fe954ac XEP-0153: wrap functions with coroutine_wrapper 2015-02-24 22:46:04 +01:00
mathieui
3d243f7da5 XEP-0054: wrap functions with coroutine_wrapper 2015-02-24 22:46:04 +01:00
mathieui
ea5615f236 XEP-0084: wrap functions with coroutine_wrapper 2015-02-24 22:46:04 +01:00
mathieui
69da1c1d7c XEP-0163: wrap publish() with coroutine_wrapper 2015-02-24 22:46:03 +01:00
mathieui
e85fa4203e XEP-0060: wrap all iq-sending functions with coroutine_wrapper 2015-02-24 22:46:03 +01:00
mathieui
506ca69917 XEP-0030: allow get_info and get_items to return a coroutine 2015-02-24 22:46:03 +01:00
mathieui
8ac0ecdf40 Fix dns resolution without aiodns
(use loop.getaddrinfo instead of the blocking version)
2015-02-24 19:17:45 +01:00
mathieui
dbd8115557 Remove the filesocket shim (2.6 compatibility) 2015-02-24 19:08:12 +01:00
mathieui
74b4ea20bf Add back stanza-specific exception handlers
(fixes the test suite too)
2015-02-23 17:43:35 +01:00
mathieui
11fbaa4241 Import xmlstream.asyncio and coroutine_wrapper at the top level
Since they will be used quite a lot in plugins.
2015-02-23 17:32:39 +01:00
mathieui
8fd0d7c993 Add a coroutine_wrapper decorator
This decorator checks for the coroutine=True keyword arg and wraps the
result of the function call in a coroutine if it isn’t.

This allows to have constructs like:

@coroutine_wrapper
def toto(xmpp, *, coroutine=False):
    if xmpp.cached:
        return xmpp.cached
    else:
        return xmpp.make_iq_get().send(coroutine=coroutine)

@asyncio.coroutine
def main(xmpp):
    result = yield from toto(xmpp, coroutine=True)
    xmpp.cached = result
    result2 = yield from toto(xmpp, coroutine=True)

If the wrapper wasn’t there, the second fetch would fail. This decorator
does not do anything if the coroutine argument is False.
2015-02-23 17:32:31 +01:00
mathieui
1450d36377 Add a coroutine parameter to iq.send() to return a coroutine
(instead of exposing a different send_coroutine method)
2015-02-23 17:20:47 +01:00
mathieui
06358d0665 Use CallbackCoroutine with Iq callbacks too 2015-02-22 20:13:48 +01:00
mathieui
2b3b86e281 Allow event handlers to be coroutine functions
And do not copy data when running events with XMLStream.event()
2015-02-22 14:17:17 +01:00
mathieui
92e4bc752a Add a “blocking” send_coroutine method to the Iq class 2015-02-21 23:45:30 +01:00
mathieui
ffb2e05f21 Check that ciphers have been initialized
(if not, python will use the system default)
2015-02-17 04:27:03 +01:00
mathieui
1e2665df19 Update the test suite.
- monkey-patch our own monkey-patched idle_call to run events immediatly
  rather than adding them to the event queue, and add a fake transport
  with a fake socket.
- remove the test file related to xep_0059 as it relies on blocking
  behavior, and comment out one xep_0030 test uses xep_0059
- remove many instances of threading and sleep()s because they do
  nothing except waste time and introduce race conditions.
- keep exactly two sleep() in IoT xeps because they rely on timeouts
2015-02-12 12:23:47 +01:00
mathieui
4d063e287e Remove more threaded= and block= options from the plugins
(also, correct a typo)
2015-02-12 12:21:20 +01:00
mathieui
44f02fb3ab Do the plugins post_init() upload loading
(the top_level boolean used to load them at this point wasn’t ever set
to true)
2015-02-12 12:18:32 +01:00
mathieui
f6b3a0c6cf Fix the uses of stanza.reply()
This is relying on the stanzas being copied for each handler. We no
longer do that for performance reasons, so instead of editing the copy
in-place, stanza.reply() now returns a new stanza.
2015-02-12 12:17:01 +01:00
mathieui
8b36e918e8 Fix the componentxmpp interface 2015-02-12 12:11:50 +01:00
Sangeeth Saravanaraj
9044807121 Added help for running example.. 2015-02-05 18:11:41 +05:30
Sangeeth Saravanaraj
24264d3a07 Updated Example.. 2015-02-05 18:10:10 +05:30
Sangeeth Saravanaraj
8bc70264ef misc updates.. 2015-02-05 17:35:04 +05:30
Florent Le Coz
957c635fb7 XMLStream must provide the BaseProtocol interface 2015-02-04 17:49:30 +01:00
mathieui
4027927c6e Don’t set the msg['from'] and msg['id'] in receipt.ack()
setting msg['id'] is wrong, and setting msg['from'] might lead to
echoing back wrong input.
2015-02-04 16:49:39 +01:00
Sangeeth Saravanaraj
c16b862200 Raise http_request and http_response events. 2015-02-03 12:33:25 +05:30
Sangeeth Saravanaraj
a96f608469 Composing request and response. 2015-01-29 08:33:40 +05:30
Sangeeth Saravanaraj
e1f25604ec Added callbacks, registered stanzas, added features, etc. 2015-01-28 14:52:15 +05:30
Sangeeth Saravanaraj
0fe057b5c3 Boilerplate for Stanzas - request and response 2015-01-27 15:13:57 +05:30
Sangeeth Saravanaraj
be76dda21d Added xep_0332 to setup 2015-01-23 10:29:21 +05:30
Sangeeth Saravanaraj
ecd124dd06 Boilerplate for xep_0332 2015-01-22 16:40:03 +05:30
Sangeeth Saravanaraj
4a8951c4ee added xep_0332 to plugins 2015-01-22 16:39:27 +05:30
Sangeeth Saravanaraj
8afba7de85 renamed example for convenience. 2015-01-22 16:38:16 +05:30
Sangeeth Saravanaraj
1ce42d3a2f Boilerplate example. 2015-01-22 11:30:38 +05:30
Sangeeth Saravanaraj
2f4d811db4 Fixed a typo in docs/guide_xep_0030.rst 2015-01-22 11:13:03 +05:30
Sangeeth Saravanaraj
61127f521d Added PyCharm's .idea folder to .gitignore 2015-01-22 11:09:47 +05:30
mathieui
62eefdbd6a Expose MUC support in disco#info
http://xmpp.org/extensions/xep-0045.html#disco-client
2015-01-15 22:50:49 +01:00
Florent Le Coz
225e07eb64 Fix the call of iscoroutinefunction() 2015-01-05 11:36:24 +01:00
Florent Le Coz
1207c81ab5 Do not copy the stanza before calling each handler 2015-01-03 18:42:57 +01:00
Florent Le Coz
565da65ccd Use a deque for the idle list 2015-01-03 16:13:39 +01:00
Florent Le Coz
47fbd4cead Delay the handling of stanza for when the process is not busy
We use some dirty monkey-patching to add a idle_call() function to the
asyncio module. We then use that method to handle each received stanza only
when the event loop is not busy with some other IO (mainly, the standard
input)
2015-01-03 06:08:03 +01:00
mathieui
1b9b4199e8 Make the ca_certs option useful again (CA-based cert validation)
It was broken since the fork.
2014-12-17 19:03:49 +01:00
mathieui
b5930ca958 Bring back authentication through SASL EXTERNAL
(and only update the ssl context before it gets used)
2014-12-11 19:27:13 +01:00
mathieui
063e73c0d2 Fix the element name for retrieving certs in XEP-0257
And s/258/257/ in the XEP description
2014-12-11 18:32:50 +01:00
mathieui
423974f90d Fix xep-0257 for slixmpp, and fix an element name 2014-12-11 14:46:52 +01:00
Oleg Antonyan
d261318e1a In queues added option to remove first element on addind new if queue is
full
2014-11-27 07:11:06 +02:00
Oleg Antonyan
d33cc00fe9 On initial connect use delay if connection failed 2014-11-23 16:46:01 +02:00
Florent Le Coz
5fcf08a415 Lower the timeout for each DNS resolution attempt 2014-11-14 01:13:52 +01:00
mathieui
3c06568ed5 Let loop.create_connection do its getaddrinfo coroutine if there are no dns records left/available 2014-11-12 22:22:20 +01:00
Lance Stout
27582f6fd2 Merge pull request #326 from s-m-b/patch-1
Typo fix of parameter name 'data' it is now 'iq'
2014-11-10 09:07:32 -08:00
s-m-b
e328ff4833 Typo fix of parameter name 'data' it is now 'iq'
Code was broken during refactoring
2014-11-09 04:36:38 +03:00
Florent Le Coz
68e35e631a Also work without SRV records 2014-11-05 01:11:44 +01:00
mathieui
ad8c76602b Depend on aiodns and not dnspython in the setup.py 2014-11-03 16:55:43 +01:00
Florent Le Coz
b5c98ba99e Fix default value of dns_answers to None (instead of []) 2014-11-02 17:44:41 +01:00
mathieui
711f8dc6af Use aiodns instead of dnspython to query DNS records 2014-11-02 17:26:29 +01:00
mathieui
5b41fb98de Add the ssl_cert and ssl_invalid_chain back
- hack the stdlib to get the peercert, remove that hack when http://bugs.python.org/issue22768 gets fixed
2014-10-30 19:51:30 +01:00
mathieui
6da625dbdb Make the "ciphers" option work again 2014-10-30 19:51:00 +01:00
mathieui
e862c47b8b Remove the ssl_version option, as the defaults in python3.4 are sane 2014-10-30 19:49:26 +01:00
Florent Le Coz
4a8fe56470 Something something get_stanza_values
Fix something that was broken by Link Mauve
2014-10-11 21:04:28 +02:00
Emmanuel Gil Peyrot
7c3e61950d Remove all deprecated alias in the core of slixmpp, and wherever they were used. 2014-09-28 23:58:46 +02:00
Emmanuel Gil Peyrot
61f89eef2e Remove the now useless Queue wrapper in slixmpp.util. 2014-09-28 23:58:46 +02:00
Emmanuel Gil Peyrot
06de587ed2 Don’t check for logging.NullHandler, it got added in Python 3.1. 2014-09-28 23:58:46 +02:00
Emmanuel Gil Peyrot
49beb3ac08 Don’t set the wait time to True instead of leaving its float default, in examples. 2014-09-28 23:58:46 +02:00
Lance Stout
403462fdb8 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2014-09-09 08:50:24 -07:00
Lance Stout
f22d8e67b4 Preserve ID for error responses
Fixes #319
2014-09-09 08:49:37 -07:00
Emmanuel Gil Peyrot
e1c944d723 Improve run_tests.py, allowing it to run only specific tests. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
83442b9849 Remove useless ez_setup.py file, we use setuptools in the normal setup.py instead. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
edd6ffeb01 Clean setup.py, using modern 3.4 features. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
5a8881000c Remove support for gevent, incompatible with python3. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
70839368c1 Fix indentation in xep_0016. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
9d8a2a1a7a Remove all trailing semicolons. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
17174016ec Remove all trailing whitespaces. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
ed37174a2b Always use OrderedDict from collections, and remove its implementation in slixmpp.thirdparty. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
8660148960 Move examples from the deprecated optparse to argparse, and remove the redundant -v option. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
67ca2dd0f4 Import getpass from getpass, instead of using getpass.getpass everytime. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
882f984b26 Remove (usually) useless comments in examples about OpenFire and how to verify a certificate. 2014-09-01 02:47:15 +02:00
Emmanuel Gil Peyrot
6175cbcd99 Reintroduce XMLStream.process, making it run the asyncio event loop. 2014-09-01 02:47:08 +02:00
Emmanuel Gil Peyrot
476d76a533 Remove threaded from examples’ add_event_handler. 2014-09-01 02:42:45 +02:00
Emmanuel Gil Peyrot
df68bb4896 Remove raw_input usage and other python2 support in examples 2014-09-01 02:42:45 +02:00
Emmanuel Gil Peyrot
815e647c97 Set the shebang to python3 everywhere. 2014-09-01 02:42:45 +02:00
Emmanuel Gil Peyrot
ad70ffba59 Add pygments support to debug output. 2014-09-01 02:42:45 +02:00
Emmanuel Gil Peyrot
0e95015410 Remove sys.version_info checks for python2 and clean some imports. 2014-09-01 02:42:45 +02:00
Matthieu Rakotojaona
35f33f1614 Extend AtomEntry capabilities 2014-08-30 17:23:27 +02:00
Lance Stout
c9f8ddff65 Merge pull request #315 from louiz/develop
Fix saslprep on the username
2014-08-24 16:19:15 -07:00
Florent Le Coz
f5ae98aaf1 Fix saslprep on the username
Two issues fixed here:

- ints are not comparable with bytes, so char was never == to b',', which
  renders the whole function pointless
- The bytes were converted back to “characters” by using chr(), which
  doesn’t make sense if the username contains characters that fit on more
  than one bytes. This would trigger an “invalid username” error from the
  server when using a non-ascii JID.
2014-08-25 01:08:13 +02:00
Florent Le Coz
b92dac72f3 Fix saslprep for non-ascii usernames 2014-08-25 00:59:23 +02:00
Robin Gloster
073e85381a fix args, kwargs which were broken with #310. this is essentially the same but working 2014-08-23 14:25:35 +02:00
Robin Gloster
afc939708f cleanup semicolons, whitespace and mutable default arguments 2014-08-23 12:47:29 +02:00
Lance Stout
aabec8b993 Fix some more Unicode in **kwargs issues in Py2.6 2014-08-21 10:05:42 -07:00
Lance Stout
e5e2fbb16b Merge pull request #311 from Mayflower/develop
Revert "cleanup semicolons, whitespace and mutable default arguments"
2014-08-18 13:34:15 -07:00
Robin Gloster
3dd379cdf1 Revert "cleanup semicolons, whitespace and mutable default arguments"
This reverts commit 7265682a4d.
2014-08-18 15:15:14 +02:00
Lance Stout
a20582aba4 Merge pull request #309 from Mayflower/whitespace_keepalive
only schedule whitespace keepalive if enabled
2014-08-17 17:21:25 -07:00
Lance Stout
09cdbf1b76 Merge pull request #308 from Mayflower/develop
Serialize JID to allow json serializing
2014-08-17 17:20:45 -07:00
Lance Stout
ca306e7cec Merge pull request #310 from Mayflower/cleanup
Cleanup
2014-08-17 17:20:26 -07:00
Robin Gloster
1bf34f7fe6 fix mutable default arguments 💥 2014-08-18 00:55:10 +02:00
Robin Gloster
4144d60017 cleanup semicolons, whitespace and mutable default arguments 2014-08-18 00:55:10 +02:00
Robin Gloster
7265682a4d cleanup semicolons, whitespace and mutable default arguments 2014-08-18 00:52:24 +02:00
Robin Gloster
08c62a6bf1 fix mutable default arguments 💥 2014-08-18 00:18:10 +02:00
Robin Gloster
d61f1cd035 only schedule whitespace keepalive if enabled 2014-08-17 23:38:07 +02:00
Robin Gloster
1063feb33b only schedule whitespace keepalive if enabled 2014-08-17 23:37:19 +02:00
Robin Gloster
79f3c1ac8f serialize JID to allow json serializing 2014-08-17 23:13:56 +02:00
Florent Le Coz
cdb9a6ff7e Remove deprecated xmlstream/jid.py 2014-08-16 11:27:18 +02:00
Vincent Canfield
a59148dfeb Remove google modules from setup.py file 2014-08-15 20:27:31 -07:00
Lance Stout
a5c03b763a Merge pull request #305 from trinque/develop
Added wait param to XEP_0009 RemoteSession.close
2014-08-11 14:08:56 -07:00
Michael Trinque
3670d82f1c Added wait param to XEP_0009 RemoteSession.close
This parameter is False by default to preserve existing behavior.
2014-08-10 16:02:10 -07:00
Florent Le Coz
07e46837d9 Fix some more blocking iq 2014-08-01 15:02:54 +02:00
Florent Le Coz
fa21e262c7 Add the 'connecting' event 2014-08-01 04:01:31 +02:00
Florent Le Coz
93934c7992 Improve the events triggered on failed authentication
Trigger failed_auth as before, once for each failed method
Trigger failed_all_auth once all method failed
Trigger no_auth only if we couldn’t even try one method
2014-08-01 03:16:22 +02:00
Florent Le Coz
73edd42774 Fix the connection (and a few minor things) in xmlstream 2014-07-30 17:57:57 +02:00
Florent Le Coz
ab03ad54aa Fix the iq.send() function, and a bunch of places where it is called
This is a big-and-dirty commit with a bunch of cleanup, maybe breaking a few
things, and not fixing all iq.send() calls yet.
2014-07-30 17:52:59 +02:00
Florent Le Coz
2e571ac950 Remove all the google stuf 2014-07-24 01:57:20 +02:00
Florent Le Coz
6c15d65107 And that 2014-07-23 17:40:08 +02:00
Florent Le Coz
e5af0597a6 Forgot to remove that 2014-07-23 17:17:41 +02:00
Florent Le Coz
74117453b5 Cleanup how events are run, they are always direct by definition now 2014-07-23 17:01:17 +02:00
Emmanuel Gil Peyrot
5611b30022 Use ".remove()" instead of "is in" followed by ".pop()" 2014-07-22 11:16:06 +02:00
Florent Le Coz
ede9dcd18f An other cleanup of xmlstream.py
Remove some useless things (like handling signals, managing the threads,
etc), add some comment to recently added/fixed methods…
2014-07-22 02:58:34 +02:00
Florent Le Coz
d3b56a5d94 Remove unused RestartStream exception 2014-07-22 02:18:48 +02:00
Florent Le Coz
f5d4334963 Remove the now useless state machine 2014-07-21 20:40:45 +02:00
Florent Le Coz
5c769632e8 Make connect(), abort() and reconnect() work
All the auto_reconnect, connect_retry logic and that kind of stuf has been
entirely removed.
2014-07-21 20:34:20 +02:00
Florent Le Coz
373505f483 Clean a new bunch of stuf 2014-07-21 20:32:09 +02:00
Florent Le Coz
a2cad40f91 Remove the send_thread() function, and the stop threading.event 2014-07-21 17:50:56 +02:00
Florent Le Coz
4328762076 Fix signature of init_plugins() function 2014-07-21 17:50:29 +02:00
Florent Le Coz
c2f6f07776 Make xmlstream use an asyncio loop
Scheduled events, connection, TLS handshake (with STARTTLS), read and write
on the socket are all done using only asyncio.

A lot of threads, and thread-related (and thus useless) things still remain.
This is only a first step.
2014-07-20 20:46:03 +02:00
Florent Le Coz
5ab77c7452 Rename to slixmpp 2014-07-17 14:19:04 +02:00
Keith Gray
e94a73553d New version of the socks library socksipy from https://code.googlle.com/p/socksipy-branch/ 2014-06-15 19:01:19 -05:00
Keith Gray
577fd71472 Fixed a unicode error in xep_0065 on Python 3 2014-06-15 18:40:58 -05:00
Lance Stout
e5582694c0 Bump to 1.3.1 2014-06-09 08:30:31 -07:00
Lance Stout
768136e493 Fix things again, this time for python3 2014-06-09 08:29:48 -07:00
Lance Stout
753cb3580e Bump to 1.3.0 2014-06-08 20:01:07 -07:00
Lance Stout
60b050b82a Make ssl args work in Python <=2.6.4 2014-06-08 19:59:40 -07:00
Lance Stout
ad91a8cd5e Bring back use of dnspython for A/AAAA resolution.
This is behind a use_dnspython flag, however, so it can be disabled as
desired.
2014-06-08 19:51:57 -07:00
Lance Stout
02f79fc94b Only request auto-receipts for messages with bodies 2014-06-07 20:20:42 -07:00
Lance Stout
230a73fad2 Fix own_host in ping plugin 2014-06-07 20:06:17 -07:00
Lance Stout
d94dd486fe Merge pull request #294 from mofrank/develop
Fixes log.debug message in _connect_proxy
2014-05-16 08:43:39 -07:00
Lance Stout
6ecc39b816 Merge pull request #292 from 4gra/develop
Fix support for jabberd2 with GSSAPI
2014-05-16 08:43:26 -07:00
mofrank
9c240df9db Fixes log.debug message in _connect_proxy 2014-05-16 08:49:01 -05:00
Graham
a918bf3a95 Support jabberd2 SASL with really empty response
Despite http://xmpp.org/rfcs/rfc3920.html#rfc.section.6.2, jabberd version 2.2.14 cannot accept the typical "<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">=</response>".  Instead it must be truly empty, so we force an empty response for this stanza only.
2014-05-14 22:32:51 +01:00
Graham
9434ae267f support 'success' phase correctly
When the GSSAPI mechanism's process() function is invoked for the third time (on success) it must not attempt further processing.  Instead it should clean the context and return an empty response.
2014-05-14 22:25:09 +01:00
Graham
94187d215a don't use the kerberos.GSSError.message attribute
Replaced the reference to kerberos.GSSError.message in any raised exception, because:

 DeprecationWarning: BaseException.message has been deprecated as of Python 2.6

and its natural repr is probably the most desirable output.
2014-05-14 17:47:34 +01:00
Lance Stout
ef2f5d2978 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2014-04-20 18:10:22 -07:00
Lance Stout
62671e0f56 Fix using SCRAM with ejabberd 2014-04-20 18:09:20 -07:00
Lance Stout
93869f77a0 Merge pull request #285 from lovesnow/develop
Fix Don't process vCard avatars for MUC occupants caused TypeError
2014-04-20 18:06:04 -07:00
Lance Stout
8282d135cc Bump version 2014-04-20 18:05:27 -07:00
Lance Stout
9acc78c81d Merge pull request #288 from tpltnt/develop
doc typo fixed
2014-04-20 17:56:56 -07:00
tpltnt
3642469630 doc typo fixed 2014-04-19 19:12:09 +02:00
lovesnow
34cd20339c Fix Don't process vCard avatars for MUC occupants caused TypeError 2014-02-21 10:31:04 +08:00
Lance Stout
7548f44047 Bump version 2014-02-14 13:53:25 -08:00
Lance Stout
7cf55ef695 Allow IQ processing based on only id value before the session is bound.
See issue #278
2014-02-14 13:50:21 -08:00
Lance Stout
543250da13 Bump version 2014-02-09 14:39:50 -08:00
Lance Stout
69e55d7316 Merge pull request #280 from allan-simon/develop
fixed setRole function,
2014-02-09 14:39:08 -08:00
Lance Stout
158411e918 Include stanza dirs 2014-02-09 14:36:36 -08:00
Lance Stout
3f873002c4 Bump minor version 2014-02-09 14:33:36 -08:00
Lance Stout
818f4e5973 Fix setup.py to include xep_0323 and xep_0325 2014-02-09 14:33:02 -08:00
Allan Simon
c8d6e512d2 fixed setRole function, the check where made against 'affiliation' values, now we do that against actual role values 2014-02-07 12:11:28 +08:00
Lance Stout
a2423b8499 Get the IoT plugins to pass tests on Py3 2014-02-06 09:54:45 -08:00
Lance Stout
49acdac776 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2014-02-06 09:20:24 -08:00
Lance Stout
7e1587faa2 Merge pull request #277 from allan-simon/develop
close #276, now we  trigger 'groupchat_message_error'
2014-02-06 09:19:24 -08:00
Lance Stout
84a6ed8e80 Merge pull request #272 from tfriem/develop
Fix X-FACEBOOK-PLATFORM authentication in Python3.
2014-02-06 09:18:54 -08:00
Lance Stout
654420e351 Add Py3.3 to list of supported versions 2014-02-06 09:14:22 -08:00
Lance Stout
651915f31c Add test for wrong sender in IQ 2014-02-06 09:13:28 -08:00
Lance Stout
d9db1b84fe Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2014-02-03 19:19:15 -06:00
Lance Stout
bd03f071c6 Fix verifying 'from' for IQ results.
Closes issue #278
2014-02-03 19:15:08 -06:00
Allan Simon
eb6ac68d5c close #276, now we trigger 'groupchat_message_error' and muc::ROOM::message_error when we receive a message type=error from the server 2014-01-31 18:54:59 +08:00
Lance Stout
848e6ebd83 Merge pull request #275 from waechtjn/develop
XEP-0065 Implementation Broken
2014-01-26 16:53:50 -08:00
waechtjn
f76524fc9f Fixed XEP-0065 SOCKS5 socket closing
SCOKS5 SID were removed multiple times from the _sessions dictionary
2014-01-26 16:53:53 +01:00
waechtjn
b95532b68b Update xep_0065/proxy.py
Removed reference to undefined variable "conn"
2014-01-26 16:48:31 +01:00
Lance Stout
d002d4c06f Merge pull request #274 from anton-ryzhov/fixes
Examples and thread counting
2014-01-21 12:05:02 -08:00
Anton Ryzhov
7c03cc622c Thread counting fix 2014-01-21 19:28:17 +04:00
Anton Ryzhov
cebfd84416 Examples fixes 2014-01-21 16:19:27 +04:00
Lance Stout
12995e280e Merge pull request #270 from optiflows/fix_hosts
Don't use dnspython for A and AAAA (but keep it for SRV).
2014-01-15 09:51:43 -08:00
Lance Stout
4ae6d44efc Allow setting custom cipher suites in Py2.7+ 2014-01-13 10:14:10 -08:00
Tobias Friemel
01e1878900 Fix X-FACEBOOK-PLATFORM authentication in Python3. 2013-12-23 16:19:49 +01:00
Lance Stout
df9ad82336 Undo event name fix, due to breakage in Py2.x 2013-12-22 01:10:19 -08:00
Lance Stout
c183fd5e35 Merge pull request #271 from louiz/develop
Use strings for ElementTree.iterparse events names
2013-12-19 11:23:45 -08:00
Florent Le Coz
820d07f309 Use strings for ElementTree.iterparse events names
Because if cElementTree is not available on the system,
ElementTree is used instead, and that version doesn't accept
bytes, resulting in an exception. See
http://bugs.python.org/issue9257#msg152864
2013-12-19 11:47:31 +01:00
Guilhem Lettron
f4e3c04bbf Don't use dnspython for A and AAAA (but keep it for SRV).
dnspython don't perform a full resolv.
For example it don't manage /etc/hosts on linux.
2013-12-09 15:44:35 +01:00
Lance Stout
540d6e9dbb Merge pull request #267 from juanrmn/develop
Added a MUC method 'setRole'. Change role property of a nick in a room, ...
2013-11-26 21:18:34 -08:00
juanrmn
79a3a2befd Added a MUC method 'setRole'. Change role property of a nick in a room, useful for moderator bots. 2013-11-06 11:20:50 +01:00
Lance Stout
08a0fd5420 Merge pull request #265 from anton-ryzhov/delay_plugins
Check delay field existence
2013-10-23 11:09:05 -07:00
Anton Ryzhov
92d6bc6875 Check delay field existence
Import missing class
2013-10-23 13:33:52 +04:00
Lance Stout
fb5d20c4f8 Ensure PEP updates default to item if of 'current' 2013-10-09 11:28:09 -07:00
Lance Stout
65e3122f52 Update XEP-0319 plugin to track namespace change. 2013-09-27 00:37:02 -07:00
Lance Stout
be874e3c70 Fix deepcopying JIDs 2013-09-24 16:32:30 -07:00
Lance Stout
beae845281 Fix MAM start query 2013-09-24 16:07:50 -07:00
Lance Stout
6f64dac262 Add log message noting that SCRAM-SHA-1-PLUS requires Py3.3+ 2013-09-21 19:10:12 -07:00
Lance Stout
cd2d25cf87 Chmod +x examples, and add shebang lines 2013-09-20 11:50:51 -07:00
Lance Stout
b8b2f37e7b Make the ssl version log usable 2013-09-17 16:37:52 -07:00
Lance Stout
00152358de Normalize handling html body content
Closes issue #261
2013-09-13 10:01:33 -07:00
Lance Stout
a2784be4d6 Add MAM archived tags 2013-09-12 10:52:15 -07:00
Lance Stout
ad7a57103d ElementTree._escape_cdata isn't reliable across Python versions.
It also does not work as desired.

Revert "Merge pull request #254 from barreverte/develop"

This reverts commit 23750357e2, reversing
changes made to 07284f380f.
2013-09-12 10:39:10 -07:00
Lance Stout
19b24b276d Update MAM to use latest carbons. 2013-09-12 10:32:19 -07:00
Lance Stout
23750357e2 Merge pull request #254 from barreverte/develop
tostring.escape : optimization
2013-09-12 10:21:56 -07:00
Lance Stout
07284f380f Merge pull request #207 from spartanbits/pull_request_gevent_check
Pull request gevent check
2013-09-12 10:15:53 -07:00
Lance Stout
e60401278f Merge pull request #255 from anton-ryzhov/logging
Add null handler to logging engine
2013-09-05 16:27:43 -07:00
Lance Stout
24c474a9ec Merge branch 'xep_0323_325' of git://github.com/joachimlindborg/SleekXMPP into joachimlindborg-xep_0323_325
Conflicts:
	sleekxmpp/plugins/__init__.py
2013-09-05 16:26:18 -07:00
Joachim Lindborg
8fd3781ef5 added disco imformation, fixed some bugs in device 2013-09-04 14:57:27 +02:00
Joachim Lindborg
c85f2494a8 first functional IoT_Test 2013-09-03 22:51:11 +02:00
Lance Stout
6c2fa7a382 Fix pubsub owner subscriptions stanza 2013-08-30 08:51:46 -07:00
Joachim Lindborg
45689fd879 First implementation of the xep_0323 and xep_325 used in IoT systems. Tests are added for stanza and streams 2013-08-30 02:29:52 +02:00
Lance Stout
45a2cfb01b Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2013-08-22 14:57:39 -07:00
Lance Stout
c4bb6c900c Don't reset _expected_server_name when connecting. 2013-08-22 14:54:53 -07:00
Lance Stout
f7c042fc77 Merge pull request #257 from di/patch-1
Typo in _validate_domain error message
2013-08-16 14:52:49 -07:00
Dustin Ingram
b20dc9fe2b Typo in _validate_domain error message
s/illegar/illegal/g
2013-08-16 17:47:26 -04:00
Anton Ryzhov
a030e05993 Add null handler to logging engine 2013-08-10 21:34:18 +04:00
Lance Stout
648b03f811 Make send_message(mhtml='..') work as expected without loading plugin
71.
2013-08-07 08:48:15 -07:00
Lance Stout
e57e321d33 Try re-ordering initial imports to avoid import bugs 2013-08-06 15:54:02 -07:00
Jean-Philippe Caruana
b6e53c7b1b escape: use xml.etree.ElementTree._escape_attrib to avoid duplication 2013-07-31 11:02:10 +02:00
Jean-Philippe Caruana
1c3bfd949b escape: imports at the top 2013-07-31 11:02:06 +02:00
Lance Stout
6401c9aaaa Add back ET and ElementBase references 2013-07-30 11:46:04 -07:00
Jean-Philippe Caruana
c02adbb8e1 tostring.escape : optimization
use of xml.etree.ElementTree._escape_attrib and xml.etree.ElementTree._escape_cdata
2013-07-30 18:51:23 +02:00
Jean-Philippe Caruana
88e64dbfae Merge remote-tracking branch 'upstream/develop' into develop 2013-07-30 18:02:03 +02:00
Lance Stout
afd48b9e08 Merge pull request #253 from kxepal/patch-1
Don't resolve AAAA records if there is no dnspython nor IPv6 support
2013-07-29 09:54:40 -07:00
Jean-Philippe Caruana
db0ab9a0b3 .gitignore: idea 2013-07-29 12:22:10 +02:00
Alexander Shorin
556e4bd74d Don't resolve AAAA records if there is no dnspython nor IPv6 support
If system doesn't has IPv6 support or dnspython package, socket.getaddrinfo 
with AF_INET6 flag return weird IP info for requested host, making SleekXMPP 
crush with more weird error.
2013-07-29 14:21:46 +04:00
Lance Stout
d439c4f215 Merge pull request #252 from jpcaruana/develop
refactor : optimize imports + replace mutable argument (a list) in StateMachine constructor
2013-07-29 02:24:33 -07:00
Jean-Philippe Caruana
a9f2e1482c fix: replace mutable argument (a list) in StateMachine constructor 2013-07-26 17:48:33 +02:00
Jean-Philippe Caruana
2c26fb0d76 optimize imports 2013-07-26 17:48:33 +02:00
Jean-Philippe Caruana
18dde97c8c refactor: no import * in tests 2013-07-26 13:02:26 +02:00
Lance Stout
85bc6f5301 Merge pull request #251 from jpcaruana/jid_performance 2013-07-25 11:23:27 -07:00
Jean-Philippe Caruana
8f364b9a95 performance in jid : replace __getattr__ et __setattr__ by @property and @xxx.setter
this implementatian is much more verbose but faster, especilally if you are dealing a lot with JIDs
on my box, ./testall.py now takes 45s. It takes 53s in the old implementation (about 15% faster)
2013-07-25 16:36:18 +02:00
Lance Stout
ee6c5632ac Merge pull request #248 from jakebasile/develop
Caught OSError when querying AAAA records.
2013-07-18 12:59:16 -07:00
Jake Basile
cc81a0e8da DRYed up the OSError/socket.gaierror handler. 2013-07-18 13:07:25 -05:00
Jake Basile
262652992d Caught OSError when querying AAAA records. 2013-07-18 08:25:28 -05:00
Lance Stout
eb63825dfd Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2013-07-05 14:05:39 -07:00
Lance Stout
c49017c6f1 Update 319 plugin to update XEP-0012/256 last activity too. 2013-07-05 14:04:48 -07:00
Lance Stout
7d08bd3142 Merge pull request #247 from anton-ryzhov/block_queues
Blocking queue get
2013-07-01 00:12:25 -07:00
Anton Ryzhov
f12c241dca Blocking queue get 2013-07-01 10:30:43 +04:00
Lance Stout
cedc9dd175 Adjust get_roster to always return, even with invalid JIDs
Issue #245
2013-06-29 22:33:00 -07:00
Lance Stout
669e708b70 Fix import error 2013-06-23 18:24:35 -07:00
Lance Stout
e76a483931 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2013-06-22 14:35:20 -07:00
Lance Stout
c0437d2de8 Add roster migration example 2013-06-22 14:35:00 -07:00
Lance Stout
37a8043202 Merge pull request #244 from anton-ryzhov/speedup
Speedup main threads loops
2013-06-20 09:21:38 -07:00
Lance Stout
f4c69d4045 Merge pull request #243 from anton-ryzhov/skip_eintr
Skip EINTR errors on raw sockets
2013-06-20 09:19:53 -07:00
Anton Ryzhov
a3606d9e4d Fixed scheduler wait loop
Do fastloop wait until task run time
2013-06-20 18:30:07 +04:00
Anton Ryzhov
805f1c0e39 Use timeout constants instead of magic numbers in scheduler and event loop
Set default wait timeout as max() of previous values
2013-06-20 18:30:07 +04:00
Anton Ryzhov
7430a8ca40 Some optimizations in scheduler 2013-06-20 18:30:07 +04:00
Anton Ryzhov
1776e2edcc Skip EINTR errors on raw sockets 2013-06-20 18:29:53 +04:00
Lance Stout
baf9aaf26c Add test for nodeprep idempotency after explicitly using Unicode 3.2 2013-06-19 08:21:54 -07:00
Lance Stout
4864b07e13 Explicitly use Unicode 3.2 for StringPrep profiles.
See http://labs.spotify.com/2013/06/18/creative-usernames/
2013-06-19 00:28:11 -07:00
Lance Stout
13c919773e Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2013-06-07 19:00:42 -04:00
Lance Stout
ed3a4fb8d4 Add support for XEP-0319, idle presence 2013-06-07 19:00:22 -04:00
Lance Stout
df3e826d0a Merge pull request #242 from Florob/xep-0084-id
Properly set itemID for XEP-0084 metadata
2013-06-07 10:09:30 -07:00
Florian Zeitz
a9e7d489b8 Properly set itemID for XEP-0084 metadata 2013-06-07 13:29:28 +02:00
Lance Stout
da6b549f8b Merge pull request #239 from SecurityForUs/add_95_96_to_setup
Add xep_0095 and xep_0096 to setup so they are installed into the egg
2013-05-27 13:40:57 -07:00
Eric Hansen
76e07a9089 Add xep_0095 and xep_0096 to setup so they are installed into the egg 2013-05-27 06:14:21 -04:00
Lance Stout
4a590d1497 Simplify stream method unregistration process 2013-05-26 14:53:28 -07:00
Lance Stout
82e1508d6f Make stream initiation methods unregisterable. 2013-05-26 14:50:01 -07:00
Lance Stout
400f08db9d Fix crash conditions in IBB 2013-05-22 14:27:14 -07:00
Lance Stout
e48b650caa Fix encrypting with GPG 2013-05-22 11:59:17 -07:00
Lance Stout
d9f595283a Merge pull request #234 from SecurityForUs/str_no_stripped
.stripped() would result in error
2013-05-22 10:19:52 -07:00
Eric Hansen
85fd14f47f .stripped() would result in error 2013-05-22 09:16:49 -04:00
Joachim Lindborg
b7adaafb3e First test stanza 2013-05-17 12:18:00 +02:00
Lance Stout
d0bba87cdd Only remap component namespaces for top level stream elements. 2013-05-14 14:28:16 -07:00
Lance Stout
2cc75d4bbd Update copyright years, and license for Suelta 2013-05-13 14:09:28 -07:00
Lance Stout
24bd591faa Update copyright for sasl modules. 2013-05-13 13:33:04 -07:00
Lance Stout
2e9ccd0623 Merge branch 'si_file_transfer' into develop 2013-05-11 12:48:47 -07:00
Lance Stout
7b49c82210 Add support for XEP-0152: Reachability Addresses 2013-05-11 12:22:56 -07:00
Lance Stout
d3284f1604 Merge pull request #232 from kstaniek/develop
Fix in tzoffset and _get_fixed_offset_tz
2013-05-09 12:19:35 -07:00
Klaudiusz Staniek
3279697128 Fix in tzoffset and _get_fixed_offset_tz
The tzoffset object is constructed with offset in minutes not in
seconds.
2013-05-09 20:59:00 +02:00
Lance Stout
60cfab995f Try preventing strptime thread safety problems.
Fixes #231
2013-04-27 03:56:20 -07:00
Lance Stout
8ec18bdb2c Carry scheduled kwargs all the way 2013-04-23 11:09:04 -07:00
Lance Stout
3c3cd65235 Update gitignore 2013-04-01 22:43:26 -07:00
Lance Stout
7ac75de19d Make XMLMasks match properly for components. 2013-04-01 20:57:16 -07:00
Lance Stout
fae39e1ab4 Fix some errors in the IBB plugin. 2013-03-29 13:16:18 -07:00
Lance Stout
3732139fc3 Save progress on SI file transfer 2013-03-29 13:16:18 -07:00
Lance Stout
0a2737dc77 Merge pull request #228 from anton-ryzhov/events
Some events refactoring
2013-03-28 12:20:38 -07:00
Anton Ryzhov
481971928c failed_auth data returned
Manual updated
2013-03-28 22:41:00 +04:00
Anton Ryzhov
020197718f Event index documentation updated 2013-03-28 22:09:33 +04:00
Anton Ryzhov
a0c77c04a5 XMLStream proxy_error event duplicated with connection_failed
SASL `no_auth` event duplicated with `failed_auth`
2013-03-28 22:09:33 +04:00
Anton Ryzhov
620ee9719f Changed failed_auth event according to manual 2013-03-28 22:09:33 +04:00
Anton Ryzhov
c0d02d9935 Remove roster_received event 2013-03-28 22:09:33 +04:00
Anton Ryzhov
01356d23e5 Log events triggering 2013-03-28 20:44:37 +04:00
Lance Stout
8b73c2bcff Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2013-03-11 16:42:15 -07:00
Lance Stout
5a771dbe2f Prevent race condition in pubsub test. 2013-03-11 16:41:44 -07:00
Lance Stout
9ba5b644cf Add XEP-0196 for User Gaming, from mathieui 2013-03-11 16:26:26 -07:00
Lance Stout
f76f0c3787 Merge pull request #226 from imo/develop
Correct argument order by using keyword for keepalive.
2013-03-06 22:15:26 -08:00
Patrick Horn
01abd6a705 Correct argument order by using keyword for keepalive. 2013-03-06 21:35:07 -08:00
Lance Stout
44e2b5d945 Bump version in prep for 1.2.0 2013-02-28 11:53:24 -08:00
Lance Stout
82bbe5d1a6 Merge branch 'develop' 2013-02-25 09:53:35 -08:00
Lance Stout
a1d71d31e8 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2013-02-22 10:08:35 -08:00
Lance Stout
766e0b685d Clear out iterable data when resetting Disco items. 2013-02-22 10:07:19 -08:00
Lance Stout
58f5e4702b Merge pull request #224 from anton-ryzhov/no_deprecated_methods_usage
Don't use internally deprecated methods
2013-02-21 13:55:34 -08:00
Anton Ryzhov
d9906756cf Don't use internally deprecated methods 2013-02-22 01:48:03 +04:00
Lance Stout
9a45ebd98b Merge branch 'develop' 2013-02-19 01:01:09 -08:00
Lance Stout
7f9ff9d0e7 Use requested_jid instead of boundjid during binding. 2013-02-18 11:56:04 -08:00
Lance Stout
8c763fcf43 Merge pull request #223 from anton-ryzhov/resource_generation
Fixed resource generation via uuid
2013-02-18 11:54:20 -08:00
Anton Ryzhov
6dd4456b11 Fixed resource generation via uuid 2013-02-18 23:41:13 +04:00
Lance Stout
c30c47d291 Add XEP-0020 support. 2013-02-15 10:36:31 -08:00
Lance Stout
d8c9662302 Resolve most Python3.3 related issues.
Tests now run successfully. Occasionally get single error related to
duplicated payload data in pubsub items when copying stanza values.
2013-02-14 01:24:09 -08:00
Lance Stout
ec5e819b16 Merge branch 'develop' 2013-02-12 09:38:57 -08:00
Lance Stout
55e50ad979 Add XEP-0079 Advanced Message Processing plugin. 2013-02-12 01:30:44 -08:00
Lance Stout
99ecb166d3 More caps cleanup 2013-02-11 20:01:53 -08:00
Lance Stout
cdeae7e72f Make legacy caps log more useful, until we support legacy caps. 2013-02-11 19:53:57 -08:00
Lance Stout
fbf79755d7 Track which verstrings are being checked, so we don't request duplicates. 2013-02-11 19:49:38 -08:00
Lance Stout
78bd21b7cf Support using messages for IBB data transfer. 2013-02-11 18:08:34 -08:00
Lance Stout
88c7c29954 Ensure gmail last result time and tid are always updated. 2013-02-10 11:55:49 -08:00
Lance Stout
d4dde89ea6 Remove old_* plugins. 2013-02-10 11:47:58 -08:00
Lance Stout
774bf35fab Tidy up a bit 2013-02-10 11:47:47 -08:00
Lance Stout
1a2db7fb11 Merge branch 'xep_0077' 2013-02-10 11:30:37 -08:00
Lance Stout
da3223ac92 Merge branch 'develop' 2013-02-10 11:29:57 -08:00
Lance Stout
b0fed5a48d Merge pull request #221 from Roger/fix_gmail_notify_check
fixed gmail new mail notification check
2013-02-10 11:27:23 -08:00
roger
43132dab85 fix not blocking gmail notification check 2013-02-09 12:31:13 -03:00
roger
badd327360 fixed gmail new mail notification check
without the tid gmail ignores the query
2013-02-09 11:34:46 -03:00
Lance Stout
9a6bfc6614 Enable force_registration in the register account example. 2013-02-08 09:44:39 -08:00
Lance Stout
79914fb56b Add option to XEP-0077 plugin to force registration attempts. 2013-02-08 09:36:51 -08:00
Lance Stout
75a792eb6f Fix HTML-IM lang support. 2013-02-08 09:09:07 -08:00
Lance Stout
23f112602c Get tests to pass again.
Re-add old gmail_notify plugin for now.
2013-01-26 15:15:01 -08:00
Lance Stout
639a3aa832 Add Google plugins to setup.py 2013-01-26 14:40:23 -08:00
Lance Stout
79a8c5ceae Add proper XEP-0071 plugin. 2013-01-26 14:33:52 -08:00
Lance Stout
97a2f4449d Handle lang='*' in disco info 2013-01-26 14:31:08 -08:00
Lance Stout
7f42d15175 Fix ping event issue. 2013-01-26 14:12:44 -08:00
Lance Stout
ef9c8e910c Tighten up session checks in XEP-0050 plugin. 2013-01-25 09:52:29 -08:00
Lance Stout
a1b33da9ca Refactor Google GTalk extensions into a single meta plugin. 2013-01-24 23:05:05 -08:00
Lance Stout
1741059cf6 Add Google JID Domain Discovery plugin 2013-01-24 02:46:16 -08:00
Lance Stout
1f137735e1 Put StringPrep exception handler with the right try block. 2013-01-24 02:45:28 -08:00
Lance Stout
a186972f09 Ensure XMPPError.text is a string. 2013-01-24 02:45:14 -08:00
Lance Stout
751628401e Fixes for vCard avatar hash calculations and MUC considerations. 2013-01-24 02:44:27 -08:00
Lance Stout
403b1802ec Update tostring to inject xmlns definitions when needed. 2013-01-24 02:43:46 -08:00
Lance Stout
9165cbf7f6 Cleanup and expand XEP-0065 plugin. 2013-01-23 02:18:27 -08:00
Lance Stout
bad405bea9 Merge branch 'master' into develop 2013-01-21 02:34:22 -08:00
Lance Stout
4f9a95b011 Add plugin for Google's nosave feature. 2013-01-21 01:39:08 -08:00
Lance Stout
903e641457 Fix issues in Google settings plugin. 2013-01-21 01:38:42 -08:00
Lance Stout
f34b9399cc Simplify Gmail notifications. 2013-01-21 01:38:02 -08:00
Lance Stout
7d0d96f940 Add Google Settings plugin. 2013-01-20 23:59:28 -08:00
Lance Stout
27196a21ae Modernize the Gmail plugin. 2013-01-20 23:01:54 -08:00
Lance Stout
ea0381fa09 Remove old versions of some plugins. 2013-01-20 21:35:06 -08:00
Lance Stout
3423589ba1 Updated XEP-0199 to take and return standardized values.
Handles Iq errors appropriately when the recipient can't be found.
2013-01-20 20:14:16 -08:00
Lance Stout
1f9286d39e Add BoB data to message and presence stanzas. 2013-01-20 18:44:17 -08:00
Lance Stout
93b8e66b5d Remove unused portions of XMLMask 2013-01-20 16:24:50 -08:00
Lance Stout
a1716de683 Update tests for XEP-0092 2013-01-20 16:08:01 -08:00
Lance Stout
ccf7916257 Allow for simplified XPath namespaces 2013-01-20 15:43:02 -08:00
Lance Stout
d86adfa1b1 Updated XEP-0092 to take callbacks and return the version result stanza. 2013-01-20 13:54:01 -08:00
Lance Stout
648f3f978a Merge branch 'master' into develop 2013-01-16 23:37:05 -08:00
Lance Stout
5e4b8bd67c Ensure that initial vCard requests are sent. 2013-01-16 23:36:22 -08:00
Lance Stout
64ef690432 Merge branch 'master' into develop 2013-01-16 23:06:41 -08:00
Lance Stout
41991b5982 Fix logging for vcard lookup failure. 2013-01-16 23:06:13 -08:00
Lance Stout
01da222d67 Merge branch 'master' into develop 2013-01-16 22:33:05 -08:00
Lance Stout
518eee05c2 Set vCard avatar hash on startup. 2013-01-16 22:32:40 -08:00
Lance Stout
1dbfa29a1e Merge branch 'master' into develop 2013-01-16 16:26:35 -08:00
Lance Stout
6bac4741f6 Fix setting autojoin in bookmarks. 2013-01-16 16:26:19 -08:00
Lance Stout
a0266dac6f Merge branch 'master' into develop 2013-01-11 17:19:29 -08:00
Lance Stout
ce977a7809 Don't reset exponential backoff delay until a stream has been confirmed. 2013-01-11 17:18:58 -08:00
Lance Stout
8644a83ed9 Merge branch 'master' into develop 2013-01-09 22:14:00 -08:00
Lance Stout
7b45245b1d Fix sending BOB data in Python3 2013-01-09 22:13:44 -08:00
Lance Stout
f04f4e4a1a Merge branch 'master' into develop 2013-01-08 21:14:34 -08:00
Lance Stout
b07f1b3bd3 Give X-FACEBOOK-PLATFORM precedence over DIGEST-MD5 2013-01-08 21:14:05 -08:00
Lance Stout
0e7486d7b4 Merge branch 'master' into develop 2013-01-04 03:00:43 -08:00
Lance Stout
6c0afb87b9 Add XEP-0048 support 2013-01-04 00:32:14 -08:00
Lance Stout
e5750b368e Fix setting publish options for pubsub storage. 2013-01-04 00:25:46 -08:00
Lance Stout
ef76f923ad Merge branch 'master' into develop 2013-01-02 17:05:35 -08:00
Oskari Timperi
2c04ae084c util/sasl/mechanisms.py: SASLMutualAuthFailed not defined
SASLMutualAuthFailed was not imported from sleekxmpp.util.sasl.client
2013-01-02 17:05:23 -08:00
Lance Stout
91dc58d967 Fix startup issues with components using caps and vcards. 2013-01-02 17:04:27 -08:00
Lance Stout
0e2abe74d5 Merge pull request #215 from oswjk/patch-1
util/sasl/mechanisms.py: SASLMutualAuthFailed not defined
2013-01-02 12:57:02 -08:00
Oskari Timperi
fea444925e util/sasl/mechanisms.py: SASLMutualAuthFailed not defined
SASLMutualAuthFailed was not imported from sleekxmpp.util.sasl.client
2013-01-02 16:53:16 +02:00
Lance Stout
0998429b07 Merge branch 'master' into develop 2012-12-29 15:17:34 -08:00
Lance Stout
597eb1779c Fix other instance of inet_pton usage. 2012-12-29 15:17:15 -08:00
Lance Stout
9ae3a7dbff Merge branch 'master' into develop 2012-12-21 13:44:08 -08:00
Lance Stout
3519e845a3 Apparently twisted fills in inet_pton on Windows and uses different exceptions. 2012-12-21 13:43:38 -08:00
Lance Stout
29c049612a Merge branch 'master' into develop 2012-12-18 10:33:33 -08:00
Lance Stout
ed48185732 Fix unicode conversion in Python3 2012-12-18 10:33:14 -08:00
Lance Stout
f431bbfca2 Merge branch 'master' into develop 2012-12-14 09:37:45 -08:00
Lance Stout
8b29900be4 Fix some Python3 compatibility issues. 2012-12-14 09:37:29 -08:00
Lance Stout
6f8a4f8354 Merge branch 'master' into develop 2012-12-03 12:42:53 -08:00
Lance Stout
def34f0e42 Fix requesting channel binding from sockets that don't support it. 2012-12-03 12:42:30 -08:00
Lance Stout
e25a49f804 Merge branch 'master' into develop 2012-11-27 19:57:48 -05:00
Lance Stout
b820351f64 Fix DIGEST-MD5 support for picky servers 2012-11-27 19:54:46 -05:00
Lance Stout
0eb009496e Use the username credential instead of jid to enable ANONYMOUS auth. 2012-11-27 19:53:43 -05:00
Lance Stout
2c2498b658 Allow for more credential values to be user specified instead of auto-filled. 2012-11-27 19:53:04 -05:00
Pedro Vicente
a1d988fed5 Merge branch 'upgrading_sleekxmpp_1_1_11' into develop_sleek 2012-11-12 13:55:32 +01:00
Pedro Vicente
b0c50b7a59 Added gevent as parameter to testall checking test suite with gevent
enabled/disabled
2012-11-12 13:48:20 +01:00
Pedro Vicente
1a2b404076 Checked if gevent thread is patched to do the right import 2012-11-12 13:33:09 +01:00
Lance Stout
2d066c34fd Merge branch 'master' into develop 2012-11-09 09:58:51 -08:00
Lance Stout
7a1ed64985 Don't clobber SASL config when specifying sasl_mech in ClientXMPP constructor. 2012-11-09 09:57:20 -08:00
Lance Stout
1b449585f7 Merge pull request #205 from SeyZ/develop
Xep 0065 improvements
2012-11-04 16:01:22 -08:00
Sandro Munda
032d41dbb8 Adapted the xep_0065 plugin to be compatible with all kind of others XMPP
client.
Sent a 'socks_connected' xmpp event when the streamer is connected.
2012-11-04 11:44:33 +01:00
Sandro Munda
3a7569e3ea Avoided to log a debug message error when the socket is normally closed. 2012-11-01 11:38:55 +01:00
Sandro Munda
d444930494 Improved the gitignore files (vim temp file, .pyo file and .baboon directory).
Automatically pack & unpack data through the socket.

Added some comments to the pack method.

Handled possible error during the unpacking of data.
2012-11-01 11:17:05 +01:00
Lance Stout
6045a6bfb3 Bump version to 1.1.11 2012-11-01 11:17:05 +01:00
Lance Stout
f3f543b31e Merge branch 'master' into develop 2012-10-31 13:55:49 -07:00
Lance Stout
0fea4262ea Bump version to 1.1.11 2012-10-31 13:55:30 -07:00
Joe Hildebrand
ef1c4368d0 Merge branch 'master' of git://github.com/fritzy/SleekXMPP into develop
# By Joe Hildebrand (2) and Lance Stout (1)
# Via Lance Stout
* 'master' of git://github.com/fritzy/SleekXMPP:
  Relax timing issues in Iq timeout callback test.
  update JID_CACHE logic again.
  Allow IQ timeouts to be asynchronous, by passing a timeout_callback parameter to send().  An example modification of disco is included.  If this approach is approved, I'll go through and update the other plugins.

Conflicts:
	tests/test_stream_handlers.py
2012-10-31 14:44:51 -06:00
Lance Stout
4b7ec4a32a Merge branch 'master' into develop 2012-10-31 13:42:32 -07:00
Lance Stout
2229ad8d8e Relax timing issues in Iq timeout callback test. 2012-10-31 13:41:55 -07:00
Joe Hildebrand
61aff9f49a update JID_CACHE logic again. 2012-10-31 13:27:31 -07:00
Joe Hildebrand
67235c4214 Allow IQ timeouts to be asynchronous, by passing a timeout_callback parameter to send(). An example modification of disco is included. If this approach is approved, I'll go through and update the other plugins. 2012-10-31 13:27:06 -07:00
Joe Hildebrand
48def71d0c Merge branch 'master' of git://github.com/fritzy/SleekXMPP into develop
# By Lance Stout
# Via Lance Stout
* 'master' of git://github.com/fritzy/SleekXMPP:
  Turns out not all data is UTF-8, so don't try to decode it.
2012-10-31 12:49:33 -06:00
Lance Stout
a00eee1bbe Merge branch 'master' into develop 2012-10-31 00:17:26 -07:00
Lance Stout
12e8bb6ddc Turns out not all data is UTF-8, so don't try to decode it.
Fixes issue #204
2012-10-31 00:16:58 -07:00
Joe Hildebrand
c8c20fff71 update JID_CACHE logic again. 2012-10-29 14:15:07 -06:00
Joe Hildebrand
75a18b5ffe Allow IQ timeouts to be asynchronous, by passing a timeout_callback parameter to send(). An example modification of disco is included. If this approach is approved, I'll go through and update the other plugins. 2012-10-29 10:03:32 -06:00
Lance Stout
06a690a259 Merge branch 'master' into develop 2012-10-24 13:07:19 -07:00
Paul Molodowitch
52feabbe76 added setdefaultencoding method so reload(sys) not needed
reload(sys) could cause problem in user code - ie, sys.stdout, excepthook, and displayhook would be reset, etc
2012-10-24 13:06:36 -07:00
Lance Stout
14c9e9a9cc Merge branch 'master' into develop 2012-10-24 13:00:01 -07:00
Lance Stout
a22ca228cc Lock the bound JID in the JID cache. 2012-10-24 12:56:54 -07:00
Lance Stout
d0666a5eb6 Update JID cache to do extra memoization and locking.
Passing cache_lock=True to JID() will insert the JID into the cache
and prevent it from being dropped from the cache.
2012-10-24 12:47:25 -07:00
Lance Stout
931d49560a Merge branch 'master' into develop 2012-10-24 01:23:08 -07:00
Lance Stout
2a4e435228 Enable gevent support.
Closes issues #166 and #167

Thanks to @pvicent, @chason, and @gabriel-samfira
2012-10-24 01:20:23 -07:00
Lance Stout
3655827ef2 Merge branch 'master' into develop 2012-10-22 20:10:07 -07:00
Lance Stout
c5046b9c91 Fix JID cache (wrong in-progress version comitted earlier) 2012-10-22 20:09:35 -07:00
Lance Stout
4598031dd2 Respond to probes when the subscription is 'from', not 'to'. 2012-10-22 19:22:27 -07:00
Lance Stout
12e0e1a16b Merge branch 'master' into develop 2012-10-22 13:58:12 -07:00
Lance Stout
5e9266ba90 Optimize generating JIDs with some caching. 2012-10-22 13:57:49 -07:00
Lance Stout
0d448b8221 Merge branch 'master' into develop 2012-10-19 00:15:21 -07:00
Lance Stout
e6c95f0a2a Add support for XEP-0257: Client Certificate Management for SASL EXTERNAL 2012-10-19 00:06:45 -07:00
Lance Stout
63b58edda1 Allow passing form instructions as a list of strings. 2012-10-19 00:06:45 -07:00
Lance Stout
af9632519c Always cache published vcard 2012-10-18 12:26:50 -07:00
Lance Stout
d367fb938d Recognize plugin stanzas when they're appended. 2012-10-18 12:26:17 -07:00
Lance Stout
77f2a339e1 Merge branch 'master' into develop 2012-10-15 22:27:30 -07:00
Lance Stout
4190027a78 Prevent xmlns="" in stream output.
This was causing problems for HTML-IM because the HTML is parsed
without a namespaced context.

While xmlns="" technically can be valid, it's usually wrong, so this will work
for now until the HTML-IM parsing is fixed.
2012-10-15 22:22:07 -07:00
Lance Stout
ef48a8c4d9 Simplify xep-0084 avatar metadata publishing. 2012-10-15 22:20:38 -07:00
Lance Stout
829b225053 Fix vcard-temp stanzas to include organization data. 2012-10-15 22:20:13 -07:00
Lance Stout
747a6e94e6 Auto-subscribe to whitelisted JIDs if auto_subscribe is true 2012-10-15 22:19:47 -07:00
Lance Stout
cebc798e72 Merge branch 'stream_features' 2012-10-15 15:00:23 -07:00
Lance Stout
7c485c6a8b Merge branch 'master' into develop 2012-10-14 17:35:37 -07:00
Lance Stout
e2e8c4b5dc Remove unneeded ssl_support checks. 2012-10-10 11:42:24 -07:00
Lance Stout
675c0112ac Correct handling deleting plugins when xml:lang is active. 2012-10-10 11:07:25 -07:00
Lance Stout
4dd2c15775 Update carbons plugin to use latest spec. 2012-10-10 10:48:30 -07:00
Lance Stout
9f6decdbc1 Fix XEP-0078 error handling 2012-10-05 09:49:04 -07:00
Lance Stout
fc07e23ff8 Merge branch 'master' into develop 2012-10-05 08:58:22 -07:00
Lance Stout
4ea328b9f2 Fix empty namespaces in XEP-0045 plugin. 2012-10-05 08:58:04 -07:00
Lance Stout
84a2fc382b Merge branch 'master' into develop 2012-10-02 09:51:24 -07:00
Lance Stout
098714b3c4 Unclobber connected event handler names.
Fixes issue #199
2012-10-02 09:25:30 -07:00
Lance Stout
cf2c94d974 Add stream_negotiated event.
Fires after all stream features have been processed.
2012-10-01 16:28:31 -07:00
Lance Stout
657102e938 Update legacy auth to be used outside of stream features.
Also, add detection of legacy XMPP version.
2012-10-01 16:27:55 -07:00
Lance Stout
44e7585bf8 Merge branch 'master' into develop 2012-09-30 17:15:13 -07:00
Lance Stout
94488fa2ea Expand warning for missing ASN1 parser to include pyasn1_modules 2012-09-30 17:14:45 -07:00
Lance Stout
a2c60a4911 Merge branch 'master' into develop 2012-09-28 11:02:57 -07:00
Lance Stout
ee9c4abd08 Add support for XEP-0091: Legacy Delayed Delivery 2012-09-26 01:47:45 -07:00
Lance Stout
b5b1c932c7 Add support for XEP-0013: Flexible Offline Message Retrieval 2012-09-26 01:47:05 -07:00
Lance Stout
b8f04983e1 Allow disco queries to got to server when no JID is specified and marked not local. 2012-09-26 01:42:51 -07:00
Lance Stout
90807dd973 Fix RSM tests 2012-09-25 23:22:49 -07:00
Lance Stout
ef974114ea Add support for XEP-0313: Message Archive Management
NOTE: XEP-0313 is still very experimental, and there will likely be
      API changes in the future.
2012-09-25 20:20:43 -07:00
Lance Stout
f6e1fecdf8 Add Collector stanza handler class.
This style of handler is necessary for capturing result sets from
queries that use multiple messages to send the results instead of
in a single result stanza. Notably, XEP-0313 (MAM).
2012-09-25 20:20:22 -07:00
Lance Stout
94e8b2becf Update RSM iterator to specify where to look to count result sizes. 2012-09-25 20:17:37 -07:00
Lance Stout
a6ca6701a0 Add XEP-0308 Last Message Correction support 2012-09-25 12:35:53 -07:00
Lance Stout
c4edb9724b Fix copyright year 2012-09-25 12:27:44 -07:00
Lance Stout
b5c669bdff Add options to auto add ID values to message and presence stanzas. 2012-09-25 12:26:56 -07:00
Lance Stout
e449dce65c Fix handling forwarded stanzas to do proper lookups and deletions. 2012-09-25 12:25:45 -07:00
Lance Stout
73ce9a5ecc Merge branch 'master' into develop 2012-09-25 02:45:48 -07:00
Lance Stout
671f680bb3 Add support for XEP-0280 Message Carbons 2012-09-25 02:34:51 -07:00
Lance Stout
dfff19ffbf Add XEP-0297: Stanza Forwarding support 2012-09-24 22:59:19 -07:00
Lance Stout
a4abdf9fa6 Fix deleting non-existent stanza plugins. 2012-09-24 21:00:23 -07:00
Lance Stout
6c57bb0553 Simplify stringifying XML 2012-09-24 20:59:51 -07:00
Lance Stout
d385b9e708 Merge branch 'master' into develop 2012-09-18 10:37:04 -07:00
Lance Stout
c2ae1ee891 Remove race condition when aborting while connecting/reconnecting. 2012-09-18 10:35:53 -07:00
Lance Stout
67147570e9 Merge branch 'master' into develop 2012-09-13 11:00:58 -07:00
Lance Stout
fb3e6b7e35 Don't break checking certs for localhost. 2012-09-13 11:00:29 -07:00
Lance Stout
cf28d4586d Add support for XEP-0049: Private XML Storage 2012-09-11 20:39:32 -07:00
Lance Stout
f65eb5eeea Add support for Google's X-OAUTH2 SASL mechanism 2012-09-11 20:29:22 -07:00
Lance Stout
26fa9bd87e Don't perform caps lookup if the disco info is already known. 2012-09-11 20:28:28 -07:00
Lance Stout
0016d9a638 Add support for XEP-0279: Server IP Check 2012-09-04 20:39:43 -07:00
Lance Stout
a88b9737ff Add support for XEP-0235: OAuth over XMPP 2012-09-04 19:42:49 -07:00
Lance Stout
df9ac58d05 Merge branch 'master' into develop 2012-09-01 13:57:24 -07:00
Lance Stout
357406d801 Map <group /> elements with no content to '' instead of None. 2012-09-01 13:56:48 -07:00
Lance Stout
19a78f63f4 Merge branch 'master' into develop 2012-08-24 11:51:03 -07:00
Lance Stout
c7ec6a72cd Add catch-all chatstate event. 2012-08-24 11:47:21 -07:00
Florian Fieber
e68b07dbce Fix get_blocked() in XEP-0191 2012-08-24 11:44:56 -07:00
Lance Stout
e20610ab80 Merge pull request #197 from FlorianFieber/develop
Fix get_blocked() in XEP-0191
2012-08-23 11:04:30 -07:00
Lance Stout
1ca0c46333 Special plugin loading case for xep_0115 no longer needed. 2012-08-23 00:23:32 -07:00
Florian Fieber
e510875f64 Fix certificate expiration scheduler
timedelta.seconds does not store the total seconds of a time span.
Internally, seconds is the next smaller unit to days, hence
timedelta.seconds will never exceed (or reach) the number of seconds
in a day (60*60*24=86400)
2012-08-23 00:22:22 -07:00
Florian Fieber
f52a10b061 Fix get_blocked() in XEP-0191 2012-08-23 03:57:05 +02:00
Lance Stout
7d382a2bfd Merge pull request #195 from FlorianFieber/develop
Fix certificate expiration scheduler
2012-08-19 10:11:17 -07:00
Florian Fieber
09bec1c4fe Fix certificate expiration scheduler
timedelta.seconds does not store the total seconds of a time span.
Internally, seconds is the next smaller unit to days, hence
timedelta.seconds will never exceed (or reach) the number of seconds
in a day (60*60*24=86400)
2012-08-19 16:40:22 +02:00
Lance Stout
ff28b0a005 Merge branch 'master' into develop 2012-08-17 10:18:11 -07:00
Lance Stout
8a03bd72ae Ensure that auth is done based on the original, requested JID and not on the bound JID. 2012-08-17 10:17:35 -07:00
Lance Stout
a249f8736a Merge branch 'master' into develop 2012-08-14 11:06:54 -07:00
Lance Stout
f0e1fc5aad Fix using PLAIN over older SSL method. 2012-08-14 11:06:36 -07:00
Lance Stout
f09adf0014 Merge branch 'master' into develop 2012-08-14 09:55:05 -07:00
Lance Stout
c6ac64ed2d Help prevent race condition dealing with auto_reconnect 2012-08-14 09:54:38 -07:00
Lance Stout
04dc68f5f6 Merge branch 'master' into develop 2012-08-13 11:12:41 -07:00
Lance Stout
92be051450 Handle Iq errors/timeouts in XEP-0153 hash reset. 2012-08-13 11:09:35 -07:00
Lance Stout
5c25208fb5 Merge branch 'master' into develop 2012-08-12 22:36:23 -07:00
Lance Stout
779c258e27 Fix ISO date parsing fallback.
Closes issue #194
2012-08-12 22:35:42 -07:00
Lance Stout
962dfad216 Merge branch 'master' into develop 2012-08-10 14:15:55 -07:00
Lance Stout
f7a710e55b Add abort() method to kill the session and stop all processing without properly closing the stream. 2012-08-10 14:12:05 -07:00
Lance Stout
814a50e36f Fix handling state machine lock when quick exiting. 2012-08-10 14:11:44 -07:00
Lance Stout
230465b946 Fix unicode conversion utility. 2012-08-10 12:41:29 -07:00
Lance Stout
d11a67702e Exit transition immediately if already in the desired state. 2012-08-10 12:41:02 -07:00
Lance Stout
4e12e228cb Fix tracking service name for DIGEST-MD5 2012-08-10 12:40:28 -07:00
Lance Stout
4a94aeba49 Save a user's chosen, persistent nickname in the MUC roster data as 'alt_nick'
The use of <nick /> elements in MUCs is now discouraged in XEP-0172, however.
2012-08-07 19:33:17 -07:00
Lance Stout
14aa831169 Merge branch 'master' into develop 2012-08-07 16:45:20 -07:00
Lance Stout
295d23ccf3 Fix disco browser example to handle errors. 2012-08-07 16:44:52 -07:00
Lance Stout
75d904ed01 Merge branch 'master' into develop 2012-08-07 01:40:29 -07:00
Lance Stout
aebcf6ff82 Re-add connection delay after exhausting DNS records. 2012-08-07 01:38:15 -07:00
Lance Stout
8c2ece3bca Ensure self._der_cert exists even if no certs are used. 2012-08-04 21:37:46 -07:00
Lance Stout
80a90a6221 Prevent auto_reconnect interference when disconnecting. 2012-08-04 21:10:45 -07:00
Lance Stout
f81d5e4bd6 Merge branch 'master' into develop 2012-08-02 13:47:37 -07:00
Lance Stout
2324c90232 Ensure default authzids are handled. 2012-08-02 13:47:06 -07:00
Lance Stout
2f65fdbc76 Merge branch 'master' into develop 2012-08-01 23:03:56 -07:00
Lance Stout
59ff08174f Fix SASL exceptions in Py3 2012-08-01 17:43:38 -07:00
Lance Stout
2f4149c7d0 Merge branch 'master' into develop 2012-08-01 11:11:54 -07:00
Lance Stout
b84e359770 Use the proper mappings for nodeprep. 2012-08-01 11:11:40 -07:00
Lance Stout
fb4275648c Merge branch 'master' into develop 2012-08-01 09:05:47 -07:00
Lance Stout
475ccfa8dc Use correct method for getting channel binding. 2012-08-01 09:04:58 -07:00
Lance Stout
267c24c8ef Fix encoding issue in Python3. 2012-08-01 09:04:41 -07:00
Lance Stout
06a9d9fc30 Merge branch 'master' into develop
Conflicts:
	sleekxmpp/thirdparty/__init__.py
2012-07-31 21:33:19 -07:00
Lance Stout
1383ca19b5 Fix disco in XEP-0050 plugin.
Closes issue #191
2012-07-31 09:20:57 -07:00
Lance Stout
4c3ff2abab Add XEP-0242 plugin for 2010 Client Compliance 2012-07-30 22:07:49 -07:00
Lance Stout
7c6ef18e4f Add initial support for XEP-0016 Privacy Lists 2012-07-30 22:07:24 -07:00
Lance Stout
f8856467d5 Fix setup.py after moving SASL stuff. 2012-07-30 22:06:55 -07:00
Lance Stout
3bd84b8d27 Ignore roster updates with unrecognized subscription values. 2012-07-30 19:44:13 -07:00
Lance Stout
bc8b5774ac Fix logging of SASL errors. 2012-07-30 19:43:49 -07:00
Lance Stout
8009b0485e Add stream feature for server support of subscription pre-approvals. 2012-07-30 19:30:01 -07:00
Lance Stout
8742a56b3e Actually commit file of byte and hash utilities. 2012-07-30 19:29:33 -07:00
Lance Stout
a792bcdafe Ensure that sasl mechs that don't require security options work. 2012-07-30 19:15:10 -07:00
Lance Stout
167d1ce97b Add fields for setting client cert and key for SASL EXTERNAL. 2012-07-30 19:15:10 -07:00
Lance Stout
695cd95657 Update and integrate Suelta. 2012-07-30 19:15:10 -07:00
Lance Stout
44ce01a70b Merge branch 'master' into develop 2012-07-30 09:08:58 -07:00
Lance Stout
e4b4c67637 Bump version to 1.1.10 2012-07-30 09:04:15 -07:00
Lance Stout
422e77ae40 Don't wait to retry connection if out of DNS records. 2012-07-29 17:26:04 -07:00
Lance Stout
5ae6c8f8fa Add support for XEP-0131: Standard Headers and Internet Metadata 2012-07-28 01:06:21 -07:00
Lance Stout
54656b331a Restrict caps updates to available presences (not subscriptions, etc). 2012-07-27 15:51:35 -07:00
Lance Stout
9047b627a4 Only broadcast vCard hashes for available presences (not subscriptions, etc). 2012-07-27 15:48:15 -07:00
Lance Stout
6645a3be40 Compile JID pattern regex. 2012-07-27 11:24:01 -07:00
Lance Stout
c2189b4ecd Merge branch 'master' into develop 2012-07-27 10:45:52 -07:00
Jonas Wielicki
e3fab66dfb Allow tasks to remove themselves during execution
The scheduler class is now capable with dealing with tasks which remove
themselves from the scheduler during execution.

Additionally, some optimizations were applied by use of iterators and
some functions better suited for the purpose.

Please peer-review, all tests pass.
2012-07-27 10:45:23 -07:00
Lance Stout
5867f08bf1 Improve docs and fix typo in stringprep profiles. 2012-07-26 23:35:23 -07:00
Lance Stout
a06fa2de67 Enhance plugin config with attribute accessors.
This makes updating the config after plugin initialization much easier.
2012-07-26 23:04:16 -07:00
Lance Stout
c9b2cf6043 Merge branch 'master' into develop 2012-07-26 12:24:34 -07:00
Lance Stout
35396d2977 Don't include a 'from' JID when requesting vCards as a client. 2012-07-26 11:55:54 -07:00
Lance Stout
3bff743d9f Fix logging statement for MUC invitations. 2012-07-26 11:53:07 -07:00
Lance Stout
5a878f829b Fix error with session binding in components. 2012-07-26 11:50:59 -07:00
Lance Stout
16ec0f151a Merge branch 'master' into develop 2012-07-25 01:47:26 -07:00
Lance Stout
26dc6e90ea Add example for setting an avatar. 2012-07-25 01:37:03 -07:00
Lance Stout
94c749fd5a Fix avatar hash advertising. 2012-07-25 01:36:31 -07:00
Lance Stout
7b80ed0807 Substitute a blank JID for the boundjid in API calls. 2012-07-25 01:33:44 -07:00
Lance Stout
98b7e8b10a Fix initializing plugins in stanzas with a language set. 2012-07-25 01:33:17 -07:00
Lance Stout
c42f1ad4c7 Merge branch 'master' into develop 2012-07-24 20:01:18 -07:00
Lance Stout
9d8de7fc15 Fix publish vcard avatars, and PEP avatar metadata. 2012-07-24 19:43:39 -07:00
Lance Stout
70883086b7 Modify update_roster() to only change the information provided.
Before: Not specifying the groups, name, etc would remove them from the
        roster entry.

After: Any parameters not specified are populated with the current
       roster entry's values.
2012-07-24 16:48:24 -07:00
Lance Stout
9a08dfc7d4 Add support for using CDATA for escaping.
CDATA escaping is disabled by default, but may be enabled by setting:

    self.use_cdata = True

Closes issue #114
2012-07-24 03:25:55 -07:00
Lance Stout
3e43b36a9d Standardize importing of queue class.
This will make it easier to enable gevent support.
2012-07-24 02:39:54 -07:00
Lance Stout
352ee2f2fd Fix JID validation bugs, add lots of tests. 2012-07-24 01:43:20 -07:00
Lance Stout
78aa5c3dfa Add more validation for 0 length JID components. 2012-07-24 01:43:20 -07:00
Lance Stout
613323b5fb Finish docstrings for jid.py 2012-07-24 01:43:20 -07:00
Lance Stout
6c4b01db8a Add plugin for advertising XEP-0106 support. 2012-07-24 01:43:20 -07:00
Lance Stout
d06897a635 Add backwards compatibility shim for the old jid.py location. 2012-07-24 01:43:20 -07:00
Lance Stout
1600bb0aaf Cleanup and docs. 2012-07-24 01:43:20 -07:00
Lance Stout
b5c9c98a8b Add JID escaping support. 2012-07-24 01:43:20 -07:00
Lance Stout
e4e18a416f Add validation for JIDs. 2012-07-24 01:43:20 -07:00
Lance Stout
01cc0e6def Add 'by' attribute for error stanzas. 2012-07-23 21:48:19 -07:00
Lance Stout
a3ec1af205 Merge branch 'master' into develop 2012-07-23 01:52:55 -07:00
ekini
d571d691a7 old clients still support xep-184/1.0 version
Now psi (and probably miranda) correctly receive delivery receipts.
2012-07-23 01:52:45 -07:00
ekini
ea3d39b50e added xep-0138 support (compression) 2012-07-23 15:39:07 +07:00
Lance Stout
2e580304f9 Merge branch 'master' into develop 2012-07-22 14:02:26 -07:00
Lance Stout
fb221a8dc0 Add XEP-0133 support, which just makes the appropriate XEP-0050 calls. 2012-07-22 13:58:23 -07:00
Lance Stout
459e1ed345 Handle Windows newlines in XEP-0027.
Closes issue #184
2012-07-22 12:15:46 -07:00
Lance Stout
6680c244f5 Fix deprecation warning for setting self.resource 2012-07-20 22:04:36 -07:00
Lance Stout
06423964ec Fix description of XEP-0222 plugin. 2012-07-20 22:03:17 -07:00
Lance Stout
5492e9028d Merge branch 'master' into develop 2012-07-20 18:15:54 -07:00
Lance Stout
474390fa00 Add example for retrieving avatars. 2012-07-20 18:10:14 -07:00
Lance Stout
81d3723084 Add event for vCard avatar update. 2012-07-20 18:07:27 -07:00
Lance Stout
32e798967e Fix see-other-host handling if no host is actually given. Also, limit number of consecutive redirection attempts. 2012-07-20 15:28:18 -07:00
Lance Stout
060c9ab679 Merge branch 'master' into develop 2012-07-20 00:25:32 -07:00
Lance Stout
acd9c32a9f Bump version to 1.1.9 2012-07-20 00:17:53 -07:00
Lance Stout
b8581b0278 Of course Peter goes and changes the XEP title the day after I implement it. 2012-07-19 23:59:35 -07:00
Lance Stout
917faecdcb Fix issue of roster data being split across multiple rosters.
Resolved by always normalizing JIDs to bare form, regardless of if they
are JID objects or strings.

Also simplified related code to prefer use of JID objects instead of
strings so they don't need to be parsed multiple times.
2012-07-19 23:54:18 -07:00
Lance Stout
78f0325398 Merge branch 'master' into develop 2012-07-16 20:13:35 -07:00
Lance Stout
f6edaa56a6 Add plugin for XEP-0191: Simple Communications Blocking 2012-07-16 20:10:14 -07:00
Lance Stout
51fee28bf4 Add a warning log if dnspython is not found for SRV lookup.
Closes issue #183
2012-07-16 19:38:50 -07:00
Lance Stout
e8a3e92ceb Update plugins to use session_bind handler for disco, and use plugin_end 2012-07-10 01:37:44 -07:00
Lance Stout
5df3839b7a Add method to remove a filter. 2012-07-10 01:37:23 -07:00
Lance Stout
8dcb441f44 Add default plugin session_bind handler.
All plugins may now simply define a session_bind method where disco
features and other actions which require the bound JID may be done.
2012-07-10 01:36:21 -07:00
Lance Stout
a347cf625a Add session_bind_event threading event. 2012-07-10 01:35:57 -07:00
Lance Stout
46f49c7a12 Add method to unregister stream features. 2012-07-10 01:35:25 -07:00
Lance Stout
99701c947e Prevent None from being added to the schedule from a timing issue. 2012-07-09 22:59:26 -07:00
Lance Stout
1baae1b81e Fix issues of disco info leaking between entities with the same bare JIDs.
To ensure that disco info, or any settings which depend on the bound
JID, are correct, only set such information on or after the
session_bound event has fired.
2012-07-09 22:22:05 -07:00
Lance Stout
7d20f0e9a6 Fix missing import in xep_0256 plugin. 2012-07-09 22:21:40 -07:00
Lance Stout
fbad22a1cd Merge pull request #181 from whooo/upstream
Fix for the RSM iterator
2012-07-09 09:25:09 -07:00
Erik Larsson
5af2f62c04 Make sure that the last RSM stanza is returned from the iterator 2012-07-08 23:27:13 +02:00
Jay Farrimond
4a4a03858e dereference iq stanza only once for roster processing 2012-07-06 14:03:41 -07:00
Lance Stout
1efe049959 Merge pull request #180 from jay-instaedu/develop
dereference iq stanza only once for roster processing
2012-07-06 13:58:46 -07:00
Jay Farrimond
2393148908 dereference iq stanza only once for roster processing 2012-07-06 13:50:15 -07:00
Lance Stout
6819b57353 Handle converting None to byte data (b''). 2012-07-06 11:05:47 -07:00
Jay Farrimond
88b5e60807 only log cert errors if not handled by user 2012-07-05 13:38:26 -07:00
Lance Stout
c7594b3ef0 Merge pull request #179 from jay-instaedu/develop
only log cert errors if not handled by user
2012-07-05 13:36:53 -07:00
Jay Farrimond
b210870f48 only log cert errors if not handled by user 2012-07-05 13:30:33 -07:00
Lance Stout
a26a8bd79c Bump version to 1.1.8 2012-06-30 17:40:11 -07:00
Lance Stout
9307a6915f Add notes to echo_client.py example on working with Facebook and MSN. 2012-06-23 22:30:24 -07:00
Lance Stout
5d6019a962 Merge branch 'master' into develop 2012-06-22 23:17:15 -07:00
Lance Stout
85ef2d8d0b Add support for reconnecting based on see-other-host stream errors. 2012-06-22 23:13:16 -07:00
Lance Stout
c2c7cc032b Fix plugin registration for single file plugins. 2012-06-22 21:58:50 -07:00
Lance Stout
e4911e9391 Add meta plugin for XEP-0302 for the 2012 compliance suite.
There are still a few remaining items in the RFCs to add support for,
but the current plugin support matches the advanced client profile.
2012-06-22 21:52:39 -07:00
Lance Stout
b11e1ee92d Add meta plugin for XEP-0270, 2010 compliance suite.
Registering this plugin will load the plugins required for advanced
client compliance status.
2012-06-22 21:26:25 -07:00
Lance Stout
5027d00c10 Change packaging for XEP-0256 to just a single file. 2012-06-22 21:26:01 -07:00
Lance Stout
69ddeceb49 Add support for XEP-0256: Last Activity in Presence 2012-06-22 21:13:30 -07:00
Lance Stout
82698672bb Add 'thread' and 'parent_thread' interfaces to message stanzas.
These values are perisisted across replies.
2012-06-22 20:05:34 -07:00
Lance Stout
9cec284947 Mark presence status as language aware. 2012-06-22 20:05:17 -07:00
Lance Stout
dc501d1902 Mark message body and subject as language aware interfaces. 2012-06-22 19:08:51 -07:00
Lance Stout
100e504b7f Resolve xml:lang issue with duplicated elements depending on ordering. 2012-06-22 18:19:17 -07:00
Lance Stout
eb5df1aa37 Merge branch 'master' into develop 2012-06-20 23:46:13 -07:00
Lance Stout
8a745c5e81 Bump version to 1.1.7 2012-06-20 23:45:14 -07:00
Lance Stout
bf0a157c5d Add support for XEP-0221: Data Forms Media Element 2012-06-20 23:38:30 -07:00
Lance Stout
f49818be06 Add support for XEP-0186: Invisible Command 2012-06-20 23:37:39 -07:00
Lance Stout
1ad171dfe5 Fix issue with setting subelements values with default langs. 2012-06-20 23:19:52 -07:00
Lance Stout
2a78570d65 Fix setting IPv6 default configuration option. 2012-06-20 22:21:34 -07:00
Lance Stout
546066d677 Merge branch 'master' into develop 2012-06-20 21:13:06 -07:00
Lance Stout
7a112f2523 Bump version to 1.1.6 2012-06-20 21:08:43 -07:00
Lance Stout
3234596974 Merge branch 'master' into develop 2012-06-20 19:45:11 -07:00
Lance Stout
e86444e5fb Make the use of IPv6 configurable.
Set self.use_ipv6 = False before connecting.

Fixes issue #175
2012-06-20 19:39:24 -07:00
Lance Stout
5820d49cd4 Merge branch 'master' into develop
Conflicts:
	sleekxmpp/basexmpp.py
2012-06-19 21:50:33 -07:00
Lance Stout
36c11ad9de Ordering fixes for Python3.3 2012-06-19 18:19:44 -07:00
Lance Stout
019a4b20ae Fix assigning values to error stanzas.
The new data interfaces were deleting the actual error conditions if
they were set afterward with falsy data.
2012-06-19 16:21:34 -07:00
Lance Stout
433ee08687 Allow message and presence stanzas to be embedded as substanzas. 2012-06-19 16:20:54 -07:00
Lance Stout
7858d969d8 Remove usage of deprecated getchildren() method. 2012-06-19 09:47:31 -07:00
Lance Stout
8119551049 Don't compare against booleans using ==. 2012-06-19 01:38:36 -07:00
Lance Stout
061489f03a Limit except clause to just ImportErrors when loading plugins. 2012-06-19 01:38:12 -07:00
Lance Stout
d92aa05b5c PEP8 formatting updates. 2012-06-19 01:29:48 -07:00
Lance Stout
f7a74d960e Simplify send_presence_subscription() 2012-06-19 00:06:31 -07:00
Lance Stout
95a0e51b41 Add example for dealing with GTalk custom domain certificates. 2012-06-19 00:02:36 -07:00
Lance Stout
110e45e187 Add examples for using IBB. 2012-06-19 00:02:17 -07:00
Lance Stout
534aaf2b2a Properly handle certs with no extensions. 2012-06-19 00:01:02 -07:00
Lance Stout
4cc20fdd05 Use plugin_multi_attrib values to make vcards nicer. 2012-06-18 23:19:38 -07:00
Lance Stout
f3fae192a8 Fix plugin_multi_attrib value for avatar pointers. 2012-06-18 23:05:02 -07:00
Paulo Freitas
7d59a8a0ad Fixed typo in _handle_get_vcard() 2012-06-18 22:54:30 -07:00
Lance Stout
8da387a38a Add support for error conditions that include data. 2012-06-18 22:19:04 -07:00
Lance Stout
ff6fc44215 Simplify tracking last sent presence using outgoing filters. 2012-06-18 22:15:21 -07:00
Lance Stout
62391a895a Update plugin list, fix syntax error. 2012-06-18 22:08:38 -07:00
Lance Stout
9bcdd7d18f Add initial support for XEPS 222 and 223. 2012-06-18 22:08:38 -07:00
Lance Stout
5c4f7bfe8b Initial support for XEP-0258 2012-06-18 22:07:39 -07:00
Lance Stout
0b7f134021 Add initial XEP-0084 support.
It does not auto-retrieve and store avatars yet, but everything is there
to do so.
2012-06-18 22:07:17 -07:00
Lance Stout
378a42889f Simplify and update XEP-0033 to latest plugin format. 2012-06-18 22:03:03 -07:00
Lance Stout
f824950552 Enable using xml:lang with normal interfaces.
Using the special language value '*' will return a dictionary of all
such elements keyed by language.

    >>> msg = Message()
    >>> msg['body'] = 'Hi!'
    >>> msg['body|sv'] = 'Hej!'
    >>> print(msg)
    '<message xmlns="jabber:client">
      <body>Hi!</body>
      <body xml:lang="sv">Hej!</body>
    </message>'
    >>> print(msg['body|*'])
    OrderedDict(
        ('', 'Hi!'),
        ('sv', 'Hej!'))

Remaining items:

- Stanza path matching does not support language specifiers for normal
  interfaces, only for plugins.
2012-06-18 22:00:33 -07:00
Lance Stout
3d2d11f169 Update stream features stanza to work with new plugin keys. 2012-06-18 22:00:33 -07:00
Lance Stout
181aea737d Add initial support for xml:lang for streams and stanza plugins.
Remaining items are suitable default actions for language supporting
interfaces.
2012-06-18 22:00:33 -07:00
Lance Stout
1ab66e5767 Add example for dealing with GTalk custom domain certificates. 2012-06-15 16:03:38 -07:00
Lance Stout
aab2682f9a Add examples for using IBB. 2012-06-15 16:03:22 -07:00
Lance Stout
55d332bcc8 Merge branch 'master' into develop 2012-06-15 15:36:30 -07:00
Lance Stout
ee702f4071 Bump version to 1.1.5 2012-06-15 15:36:01 -07:00
Lance Stout
a08c2161a7 Ensure that ssl_invalid_cert returns PEM formatted certifcate data. 2012-06-15 15:29:53 -07:00
Lance Stout
f89df6e70c Merge branch 'master' into develop 2012-06-13 09:27:47 -07:00
Lance Stout
0e36a01354 Bump version to 1.1.4 2012-06-13 09:17:08 -07:00
Lance Stout
c39ad7dfbb Prevent duplicate certificate expiration timers. 2012-06-13 09:13:33 -07:00
Lance Stout
b92ae706e9 Fix loading cached disco identity data. 2012-06-13 09:13:13 -07:00
Lance Stout
250d28e870 Properly handle certs with no extensions. 2012-06-11 08:28:02 -07:00
Lance Stout
19f65c8510 Simplify send_presence_subscription.
It is technically obsolete now, but remains because it set a default
subscription type of 'subscribe'.
2012-06-10 14:42:54 -07:00
Lance Stout
f70b49882f Fix XEP-0065 imports and naming for Python3. 2012-06-10 14:15:58 -07:00
Lance Stout
a7b092a305 Fix Python3 exception handling.
Fixes issue #173
2012-06-09 15:04:27 -07:00
Lance Stout
daa73a3f3c Merge branch 'master' into develop 2012-06-09 11:43:06 -07:00
Lance Stout
6997261c6b Bump version for 1.1.3 2012-06-09 11:32:03 -07:00
Lance Stout
0b51afe87a Add extra check for the cert in the expiration handler. 2012-06-09 11:05:18 -07:00
Lance Stout
6cfb5cb14c Add extra check for the cert in the expiration handler. 2012-06-09 11:01:45 -07:00
Lance Stout
8567d6034f Use False for use_tls for components.
A log message is shown for those who try to set it to True.

Fixes issue #171
2012-06-09 11:01:35 -07:00
Lance Stout
e06368f8cd Default use_tls to False for components.
Issue #171
2012-06-09 11:01:21 -07:00
Lance Stout
4b37a4706f Fix SSL handshake handling when not using legacy SSL.
Fixes issue #172
2012-06-09 11:01:11 -07:00
Lance Stout
7b1564947d Ensure that all SSL cert error handling is overridable using event handlers.
Relevant events:

    ssl_invalid_cert
    ssl_invalid_chain
    ssl_expired_cert
2012-06-09 11:00:55 -07:00
Lance Stout
2b298766c9 Use False for use_tls for components.
A log message is shown for those who try to set it to True.

Fixes issue #171
2012-06-09 10:48:16 -07:00
Lance Stout
10664d723b Default use_tls to False for components.
Issue #171
2012-06-09 10:43:57 -07:00
Lance Stout
c012208a8f Merge pull request #170 from SeyZ/develop
Added the xep_0065 plugin in the setup.py
2012-06-09 10:37:49 -07:00
Lance Stout
0953896d2d Fix SSL handshake handling when not using legacy SSL.
Fixes issue #172
2012-06-09 10:32:25 -07:00
Sandro Munda
cf9e89d0ae Added the xep_0065 plugin in the setup.py 2012-06-09 18:45:58 +02:00
Lance Stout
48dd01b0bb Ensure that all SSL cert error handling is overridable using event handlers.
Relevant events:

    ssl_invalid_cert
    ssl_invalid_chain
    ssl_expired_cert
2012-06-08 09:31:44 -07:00
Lance Stout
7247efe055 Merge pull request #169 from SeyZ/develop
xep_0065 plugin (Socks5 Bytestreams)
2012-06-07 10:40:22 -07:00
Sandro Munda
8def3758e4 Added the get_socket(sid) method to the xep_0065 plugin to retrieve
the socket of the Proxy thread.
2012-06-07 19:36:25 +02:00
Sandro Munda
1851ab6f5f Added the SID in the socks_recv xmpp event in the xep_0065 plugin. 2012-06-07 19:24:23 +02:00
Sandro Munda
289b052338 Renamed Query to Socks5 in the xep_0065.
Renamed the 'q' plugin_attrib of the Socks5 stanza to 'socks'.
2012-06-07 19:14:37 +02:00
Sandro Munda
26147f5ae0 Added a top level field to the xep_0065 class:
name = 'xep_0065'
2012-06-07 19:08:20 +02:00
Sandro Munda
ae01f1071a Fixed the callback names of the xep_0065:
In-Band bytestreams -> Socks5 bytestreams
2012-06-07 19:04:24 +02:00
Sandro Munda
dcdf5dcd09 Added the Socksipy module in the thirdparty of SleekXMPP.
Updated the LICENSE file with the license of the Socksipy
module (New-BSD).
2012-06-07 19:02:09 +02:00
Sandro Munda
c59a6d0f51 Sent a socks_closed when the socket is closed in the xep_0065 plugin. 2012-06-07 18:38:57 +02:00
Sandro Munda
2cd936318d Improved the close of the proxy thread (and the socket) in the xep_0065 plugin. 2012-06-07 18:38:57 +02:00
Sandro Munda
2f38857681 Changed the description of the xep_0065 plugin 2012-06-07 18:38:56 +02:00
Sandro Munda
39505ae1ff The xep_0065 plugin supports now multiple stream (multiple connected
sockets).

To send data over a stream, we need to pass the SID in order to
retrieve the good proxy thread (and so, the good socket).
2012-06-07 18:38:56 +02:00
Sandro Munda
44ee0633f2 Renamed the _handle_on_recv to the on_recv method.
Renamed requester_thread and target_thread to proxy. The send method is now simpler.
2012-06-07 18:38:56 +02:00
Sandro Munda
b52d2768b0 Added some comments to the get_network_address method 2012-06-07 18:38:56 +02:00
Sandro Munda
cf24b870b1 Registered stanza plugin in the stanza module 2012-06-07 18:38:56 +02:00
Sandro Munda
69cffce7dc Used the namespace in all stanzas 2012-06-07 18:38:56 +02:00
Sandro Munda
a14979375b Added a partial support of the XEP 0065 - Socks5 Bytestreams 2012-06-07 18:38:56 +02:00
Sandro Munda
40ef4a16b1 Updated the .gitignore to add .ropeproject/ folder 2012-06-07 18:38:56 +02:00
Lance Stout
f5652a667b Add 'presence' event, raised for all incoming presence stanzas. 2012-06-06 16:10:25 -07:00
Lance Stout
3b2c865a58 Bump version to 1.1.2 2012-06-06 12:26:15 -07:00
Lance Stout
db0e683d01 Don't request registration forms unless the register event is handled.
Some servers end the stream if registration can not be completed
in-band, which means always requesting the form can prevent regular
login.
2012-06-06 12:23:40 -07:00
Lance Stout
e29a9e0394 Bump version for 1.1.1 minor release. 2012-06-04 11:56:53 -07:00
Lance Stout
edf65f4f52 Include the default, unnamed group in self.client_roster.groups() 2012-06-04 11:54:25 -07:00
Lance Stout
98677fd602 Don't add cert expiration timer if no certs are being used. 2012-06-04 11:53:58 -07:00
Lance Stout
61a4f76c8d Update version and README for 1.1 2012-06-01 14:13:17 -07:00
Lance Stout
856a826eea Fix syntax error in line continuation. 2012-06-01 14:09:14 -07:00
Lance Stout
387ef513d6 Check that the session is still alive before sending data.
Fixes issue #168
2012-06-01 13:50:38 -07:00
Lance Stout
2858dbf57f Update development version number to prepare for 1.1 release. 2012-05-31 22:07:36 -07:00
Lance Stout
350a2b8bbc Preemptively mark threads as exited if calling disconnect(). 2012-05-31 22:04:45 -07:00
Lance Stout
c9093c9972 Handle not being able to connect using IPv6 if the host does not support it. 2012-05-27 16:33:21 -07:00
Lance Stout
d1ad31696e Fix X-FACEBOOK-PLATFORM mechanism to work with Python3. 2012-05-25 11:04:46 -07:00
Lance Stout
f49311ef9e Add better certificate handling.
Certificate host names are now matched (using DNS, SRV, XMPPAddr, and
Common Name), along with expiration check.

Scheduled event to reset the stream once the server's cert expires.

Handle invalid cert trust chains gracefully now.
2012-05-22 03:56:06 -07:00
Lance Stout
678e529efc Remove unused xmlstream test client.
It's in the repo history if we need it later.
2012-05-17 22:27:03 -07:00
Lance Stout
6ddb430fef Spell thirdparty correctly. 2012-05-16 12:00:00 -07:00
Lance Stout
74d1f88146 Prune unused conn_test code. 2012-05-16 11:57:55 -07:00
Lance Stout
7842c55da3 Add auth_success event.
The auth_success event is triggered upon successful SASL negotiation.
2012-05-15 14:26:25 -07:00
Lance Stout
f5beac2afa Use SASLPrepFailure as the exception name instead of UnicodeError. 2012-05-14 23:12:54 -07:00
Lance Stout
8a23f28dfa Add an exception handler for SASLprep failures. 2012-05-14 22:26:06 -07:00
Lance Stout
9c4886e746 Remove extra connection info so that examples run without modification.
GTalk users may still need to change the connect() call if dnspython is
not installed, as usual.
2012-05-14 22:17:39 -07:00
Lance Stout
e0bcd5d722 Add more documentation to the custom stanza examples. 2012-05-14 22:12:52 -07:00
Erick Pérez Castellanos
ba854e7d85 Added custom_stanza example 2012-05-14 21:47:43 -07:00
Lance Stout
4ded34ebc9 Add MUC events for room configuration changes.
New events:
    groupchat_config_status
    muc::[room JID]::config_status
2012-05-14 16:10:22 -07:00
Lance Stout
e918a86028 Make the error message better regarding hanged threads.
All event handlers which call disconnect() MUST be registered using
`add_event_handler(..., threaded=True)` in order to prevent temporarily
deadlocking until a timeout occurs.

This is required because disconnect() waits for the main threads to
exit before returning, including the event processing thread. Since
handlers registered without `threaded=True` run in the event processing
thread, the disconnect() call will deadlock.
2012-05-10 10:22:38 -07:00
Lance Stout
24234bf718 Update other examples to use threaded mode for handlers that call disconnect() 2012-05-06 20:19:02 -07:00
Lance Stout
ec99339140 Update send_client.py to call disconnect() from a threaded handler. 2012-05-06 20:07:05 -07:00
Lance Stout
03dedfc871 Windows doesn't support inet_pton. 2012-05-06 12:17:50 -07:00
Lance Stout
9e86a7b357 Tidy up and add tests for multi_attrib plugins. 2012-05-05 14:01:13 -07:00
Lance Stout
6a32417957 Merge pull request #163 from whooo/master
factory for recurring substanzas
2012-05-05 11:34:29 -07:00
Lance Stout
97a7be7dfa Fix loading plugins from custom modules when passing the module itself.
Loading plugins from custom modules when passed as a string still works.
2012-05-04 09:51:02 -07:00
Erik Larsson
fa86f956ef added multifactory and support for it to register_stanza_plugin 2012-04-30 22:19:17 +02:00
Lance Stout
a9acff5294 Collapse initial payload to a single stanza instead of a list if only one stanza is found. 2012-04-30 11:16:10 -07:00
Lance Stout
ad5b61de50 Add full support for initial payloads with adhoc commands, plus test. 2012-04-30 11:07:54 -07:00
Lance Stout
f53b815855 Allow providing initial payload to adhoc commands. 2012-04-30 08:27:10 -07:00
Lance Stout
bf8a9dc20d Add logging note about potential cause of disconnect() deadlock. 2012-04-29 14:48:14 -07:00
Lance Stout
08716c35fd Set a timeout when waiting for threads.
If calling disconnect() from a non-threaded event handler, deadlock can
happen as disconnect() is waiting for threads to close, but the event
runner is blocked by a handler waiting for disconnect() to return.

It is best to specify threaded=True for event handlers which may call
disconnect().
2012-04-29 14:45:00 -07:00
Lance Stout
fd81bab906 Use the correct 'from' jid when requesting vcards for avatars. 2012-04-29 13:33:53 -07:00
Lance Stout
1cf55c14b0 Don't raise errors when receiving an iq error for vcards. 2012-04-29 13:33:30 -07:00
Lance Stout
8b47159788 Populate the to attribute for message and presence stanzas if the server leaves it blank. 2012-04-26 15:46:18 -07:00
Lance Stout
2eeaf4d80c Use provided stanza ID. 2012-04-25 13:55:46 -07:00
Lance Stout
4d89d26a1c Prevent corrupting roster_update event with iq result. 2012-04-25 11:03:33 -07:00
Lance Stout
0cc14cee4d Ensure that SSL errors are handled in Py3.3 2012-04-24 16:11:49 -07:00
Lance Stout
a20a9c505d Track threads to ensure all have exited when disconnecting. 2012-04-22 18:13:36 -07:00
Lance Stout
913738444e Count and track the main threads, so we can delay disconnecting until all have quit. 2012-04-21 10:36:39 -07:00
Lance Stout
8ee30179ea Add _use_daemons flag to XMLStream to run all threads in daemon mode.
This WILL make the Python interpreter produce exceptions on shutdown.
2012-04-20 15:21:31 -07:00
Lance Stout
cb2469322b Handle using provided weakrefs as stanza parent references.
Fixes issue #159
2012-04-14 11:13:38 -04:00
Lance Stout
94aa6673ca Check for the stop event more aggressively in the send thread. 2012-04-13 08:27:11 -04:00
Lance Stout
4b2b2d16b8 Reset attempted SASL mech set after no suitable mechs are found. 2012-04-11 12:53:22 -04:00
Lance Stout
4cd5d3b3b5 Fix DNS resolution results for IP literals. 2012-04-10 14:08:33 -04:00
Lance Stout
e48e50c6ff Update setup.py with the latest plugins. 2012-04-09 21:45:19 -04:00
Lance Stout
01189376e2 Add initial support for XEP-0153. 2012-04-09 21:41:59 -04:00
Lance Stout
60195cf2dc Initial support for XEP-0231. 2012-04-08 23:27:19 -04:00
Lance Stout
15ef273141 Add a prefix to stanza ID values to ensure that they are unique per client. 2012-04-08 21:15:53 -04:00
Lance Stout
eed6da538a Undo the additional Iq result checks until further testing is done.
Revert "Check for Iq results based on both the sender's JID and the ID value."

This reverts commit 9ffde5ab37.
2012-04-08 16:30:52 -04:00
Lance Stout
d3e8993e22 Fix looking up local and cached vcards. 2012-04-08 16:01:47 -04:00
Lance Stout
8a8926c5e8 Fix errors in caps related to unwrapped disco data and full JIDs. 2012-04-08 16:00:36 -04:00
Lance Stout
f9d0ee824b Ensure that wrapped disco results retain requesting iq id. 2012-04-08 16:00:07 -04:00
Lance Stout
af099737ab Ensure that accessing self.api.settings works for plugins. 2012-04-08 15:59:47 -04:00
Lance Stout
9ffde5ab37 Check for Iq results based on both the sender's JID and the ID value. 2012-04-08 15:58:48 -04:00
Lance Stout
272ddf9f01 Add nickname element to the XEP-0054 plugin. 2012-04-07 21:16:36 -04:00
Lance Stout
259c84e99a Add initial XEP-0054 plugin. 2012-04-07 20:50:02 -04:00
Lance Stout
7391288668 Tidy up roster_received event and callbacks. 2012-04-07 17:30:25 -04:00
Lance Stout
7734aee7ad Prevent roster_update from firing twice after retrieving the roster. 2012-04-07 17:22:29 -04:00
Lance Stout
9f855b9679 Trigger got_online after resource information has been saved. 2012-04-07 16:23:24 -04:00
Lance Stout
aedbecd673 Correct the statemachine's ensure_any method.
It had not been updated to use the new condition instead of the old
threading event.
2012-04-06 17:39:51 -04:00
Lance Stout
83c5a4cd2f Pass JID objects to API callbacks and not strings. 2012-04-06 15:22:36 -04:00
Lance Stout
9c61c2882f Add support for XEP-0027 2012-04-06 15:22:23 -04:00
Lance Stout
e0dd9c3618 Simplify registering API handler defaults. 2012-04-06 15:09:26 -04:00
Lance Stout
4921c44d0a Don't break test plugins that use None instead of a stream object. 2012-04-06 15:09:26 -04:00
Lance Stout
3161f104c7 Update XEP-0012 plugin to use new api. 2012-04-06 15:09:26 -04:00
Lance Stout
898f5f4b51 Allow for registering a handler and setting it as default in one step. 2012-04-06 15:09:26 -04:00
Lance Stout
3ee3fdca91 Fix XEP-0115 with the new API registry. 2012-04-06 15:09:26 -04:00
Lance Stout
488f7ed886 Begin experiment with a centralized API callback registry.
The API registry generalizes the node handler system from the xep_0030
plugin so that other plugins can use it.
2012-04-06 15:09:25 -04:00
Lance Stout
51e5aee830 Add default mapping of localhost to ::1 and 127.0.0.1 2012-04-06 15:08:21 -04:00
Lance Stout
af13bea2b8 Fix MUC invite events so that they actually work. 2012-04-03 22:41:37 -07:00
Lance Stout
cdf0b353db Fix memory leak with adhoc command sessions.
Fixes issue #155
2012-04-03 11:02:55 -07:00
Lance Stout
48504ed5e2 Display IPv6 literal addresses in brackets. 2012-04-01 19:32:12 -07:00
Lance Stout
4d4d1e0ee5 Improve connection handling by not delaying until all DNS records are tried. 2012-03-30 10:12:44 -07:00
Lance Stout
c1d36cad46 Add better DNS resolver wrapper. 2012-03-30 10:12:43 -07:00
Lance Stout
aad2eb31fc Fix typo 2012-03-30 09:01:15 -07:00
Lance Stout
1bd7824f24 Tidy up the state machine and use a threading condition instead of an event.
Fixes issue #154
2012-03-28 23:58:38 -07:00
Lance Stout
912463ed6a Fix sending data after </stream>
Clearing the session_started_event before sending </stream> will
pause the send loop so that we don't continue sending data after
the </stream>.
2012-03-28 23:53:55 -07:00
Lance Stout
dda2473d35 Reset stream management state on session_end. 2012-03-27 23:27:24 -07:00
Lance Stout
94923ae898 Improve handling disconnections.
- Add option for disconnecting without sending </stream>:

    self.disconnect(send_close=False)

- Optionally distinguish between session_end and disconnected based
  on if </stream> was sent.

    self.end_session_on_disconnect = False
2012-03-27 23:24:42 -07:00
Lance Stout
f1fde07eb9 Add tests for bool_interfaces. 2012-03-27 21:16:53 -07:00
Lance Stout
a1ddd88208 Add support for a new type of stanza interface: bool
The set of bool_interfaces provides default behaviour for
checking/setting the presence of empty subelements.

The prime example of this would be:

    bool_interfaces = set(['required'])

This would mean that ``stanza['required']`` would return ``True`` for:

    <stanza>
       <required />
    </stanza>

and ``False`` for:

    <stanza />

Likewise, assigning ``stanza['required'] = True`` would add an empty
``<required />`` element, and setting it to ``False`` would remove
such an element if it exists.
2012-03-27 21:05:50 -07:00
Lance Stout
ee6a9b981a Simplify sending whitespace keepalives.
Now that we have the send lock, we can use now=True.
2012-03-27 20:53:27 -07:00
Lance Stout
9879c7af59 Make the XEP-0198 ack debug message less confusing. 2012-03-27 20:52:31 -07:00
Lance Stout
fa4c52e499 Correct handling of acks for XEP-0198 under heavy load. 2012-03-21 13:00:43 -07:00
Lance Stout
d5484808a7 Respect reattempt=False setting when reconnecting. 2012-03-21 10:28:26 -07:00
Lance Stout
1c83391948 Merge remote-tracking branch 'hansent/master' into develop 2012-03-20 11:50:57 -07:00
Lance Stout
59d1b8e131 Correct connect() documentation, don't delay attempts if reattempt=False.
See issue #152
2012-03-20 09:56:39 -07:00
Lance Stout
859822ff05 Fix unicode issues in test cases for Py3+ introduced by issue #150. 2012-03-19 14:24:45 -07:00
Lance Stout
3acc7d0914 Merge pull request #150 from correl/rpc_value_fixes
Updated XEP-0009 to handle unicode strings
2012-03-19 14:06:36 -07:00
Lance Stout
b077ef9150 Fix error in the registration example.
The now=True parameter was not being passed to allow the registration
submission to be submitted while the send queue is paused.
2012-03-19 06:05:15 -07:00
Lance Stout
e2ce5ae222 Add example for using user location.
Uses http://freegeoip.com to get an approximate location based
on the machine's IP address.
2012-03-18 23:42:03 -07:00
Lance Stout
73cabcb6ae Add initial support for XEP-0198 for stream management. 2012-03-18 01:02:19 -07:00
Lance Stout
fbdf2bed49 Add out_sync filter category.
Added option to XMLStream.send() to skip applying filters.

Filters in the out_sync group are synced with placing stanza content
either on the wire directly or into the send queue. Because of this,
out_sync filters should not block.
2012-03-18 00:59:45 -07:00
Lance Stout
33d01fb694 Fix requesting receipts on a message that has not been bound to a stream. 2012-03-16 23:42:55 -07:00
Lance Stout
ab2e43d052 Re-add support for special case of 'presence' expiry value. 2012-03-16 23:42:34 -07:00
Lance Stout
0c24fbdb06 Add pubsub examples.
Run pubsub commands via pubsub_client, and watch events as they come in
with pubsub_events.
2012-03-16 23:18:59 -07:00
Lance Stout
eb25998e72 Update subscription event expiry value to use time objects. 2012-03-16 23:16:17 -07:00
Lance Stout
eafd2aee93 Add events for configuration and subscription notifications.
New events:
    pubsub_config
    pubsub_subscription
2012-03-16 23:12:38 -07:00
Lance Stout
a6f3d740a2 Fix error when assigning form values that include booleans. 2012-03-16 22:02:21 -07:00
Lance Stout
19a6f61b44 Fix requiring receipt request messages to have ID values. 2012-03-16 22:01:56 -07:00
Lance Stout
58e0f1e6c3 Expand support for XEP-0184.
New stanza interfaces:

    Adding a message receipt request:

        msg['request_receipt'] = True

    Adding a message receipt:

        msg['receipt'] = '123-24234'

    Retrieving the acked message ID:

        ack_id = msg['receipt']
        print(ack_id)
        '123-24234'

New configuration options:

    auto_ack:
        If True, auto reply to messages that request receipts.

        Defaults to True

    auto_request:
        If True, auto add receipt requests to appropriate outgoing
        messages.

        Defaults to False
2012-03-16 10:51:25 -07:00
Lance Stout
96ff2d43c0 Explicitly set the desired SASL mech to ANONYMOUS if no username is provided. 2012-03-13 12:24:41 -07:00
Lance Stout
1b00b7e8df Correct handling SASL auth failures when forcing the use of a specific mechanism. 2012-03-13 11:07:14 -07:00
Lance Stout
7284ceb90c Move feature_rosterver to new system. 2012-03-12 20:04:11 -07:00
Lance Stout
24ec448b7f Move feature_starttls to new system. 2012-03-12 19:57:20 -07:00
Lance Stout
ed5a2f400d Move feature_session to new system. 2012-03-12 19:52:20 -07:00
Lance Stout
9596616b42 Move feature_mechanisms to new system. 2012-03-12 19:52:01 -07:00
Lance Stout
8d38fb511b Move feature_bind to new system. 2012-03-12 19:49:43 -07:00
Lance Stout
5a2cbbb731 Move XEP-0172 to new system. 2012-03-12 19:32:20 -07:00
Lance Stout
32d6f85649 Move XEP-0118 to the new system. 2012-03-12 19:32:20 -07:00
Lance Stout
a2b47e5749 Move XEP-0108 to new system. 2012-03-12 19:32:20 -07:00
Lance Stout
14d4062f4a Move XEP-0107 to new system. 2012-03-12 19:32:20 -07:00
Lance Stout
67972c5e84 Move XEP-0080 to the new system. 2012-03-12 19:32:20 -07:00
Lance Stout
3467ac18cc Move XEP-0163 to new system.
Also includes new register_pep() method for doing the necessary stanza
and disco registration, plus pubsub node event mapping.
2012-03-12 19:32:20 -07:00
Lance Stout
cabf27424f Cleanup plugin import logic.
Checking for a 'xep' or 'rfc' attribute is more reliable
for detecting an old style plugin than 'name'.
2012-03-12 19:32:20 -07:00
Lance Stout
162e955bd6 Enable using post_init() to resolve circular dependencies.
We really shouldn't have any. However, we may later introduce one
with XEP-0030 and XEP-0059.
2012-03-12 19:32:20 -07:00
Lance Stout
57d761b8a2 Move XEP-0115 to the new system. 2012-03-12 19:32:20 -07:00
Lance Stout
8b2023225c Remove extra logging statement, add backward compatible references. 2012-03-12 19:32:20 -07:00
Lance Stout
f8f2b541db Handle loading plugins on demand.
Plugins that are referenced as dependencies, but have not been
registered now will be imported. Newer plugins should register
themselves automatically, but older style plugins will be
explicitly registered after import.
2012-03-12 19:32:20 -07:00
Lance Stout
9d645ad5cd Update the list of all stream feature plugins. 2012-03-12 19:32:20 -07:00
Lance Stout
610d366bdb Ensure the adhoc command items node exists.
If the plugin is loaded and no commands are defined, we can at least
return a proper empty response instead of an item-not-found error.
2012-03-12 19:32:20 -07:00
Lance Stout
64c46562d3 Move XEP-0249 to the new system. 2012-03-12 19:32:20 -07:00
Lance Stout
87d6ade06d Move XEP-0224 to new system. 2012-03-12 19:32:20 -07:00
Lance Stout
4a009515c1 Move XEP-0203 to new system. 2012-03-12 19:32:20 -07:00
Lance Stout
6497857495 Move XEP-0202 to new system. 2012-03-12 19:32:20 -07:00
Lance Stout
5a324c01de Move XEP-0199 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
17279de4a3 Move XEP-0184 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
34a7a62c35 Move XEP-0128 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
2305cc61fd Move XEP-0092 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
2f677c98f8 Move XEP-0086 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
3fda053606 Move XEP-0085 to the new system.
Optimized handlers so that only one is needed.
2012-03-12 19:32:19 -07:00
Lance Stout
6d855ec06c Move XEP-0082 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
23cc62fe7c Move XEP-0078 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
26ea67d211 Move XEP-0045 to new system.
Still needs updating to the new format.
2012-03-12 19:32:19 -07:00
Lance Stout
d43cd9fa54 Move XEP-0033 to new system.
Still needs updating to the new format.
2012-03-12 19:32:19 -07:00
Lance Stout
6f337b5425 Move XEP-0012 to new system.
Still needs to update to the current plugin format though.
2012-03-12 19:32:19 -07:00
Lance Stout
d104a5fe75 Move XEP-0009 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
cdd69c6842 Move XEP-0077 to the new system. 2012-03-12 19:32:19 -07:00
Lance Stout
4a3a9067d4 Move XEP-0066 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
1aecb2293a Move XEP-0060 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
ad8fd91b7a Move XEP-0050 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
1f5a3a4445 Move XEP-0047 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
be363e0b46 Move XEP-0004 to new system. 2012-03-12 19:32:19 -07:00
Lance Stout
a104cd6dae Tidy up disco plugin. 2012-03-12 19:32:19 -07:00
Lance Stout
e287282782 Moving backwards compatibility shims to __init__ files. 2012-03-12 19:32:07 -07:00
Lance Stout
8b06d10415 Update XEP-0030 and XEP-0059 to new system. 2012-03-12 16:24:18 -07:00
Lance Stout
1a153487c3 Add tests for new plugin manager. 2012-03-12 16:24:18 -07:00
Lance Stout
01b2499915 Introduce new plugin system.
The new system is backward compatible and will load older style plugins.

The new plugin framework allows plugins to track their dependencies, and
will auto-enable plugins as needed.

Dependencies are tracked via a class-level set named `dependencies` in
each plugin.

Plugin names are no longer tightly coupled with the plugin class name,
Pso EP8 style class names may be used.

Disabling plugins is now allowed, but ensuring proper cleanup is left to
the plugin implementation.

The use of a `post_init()` method is no longer needed for new style
plugins, but plugins following the old style will still require a
`post_init()` method.
2012-03-12 16:24:18 -07:00
Lance Stout
9f43d31bf5 Add setting for maximum number of reconnection attempts.
Setting self.reconnect_max_attempts to a non-None value will limit
the number of times a connection attempt will be made before quiting
and raising a 'connection_failed' event.
2012-03-12 16:19:18 -07:00
Lance Stout
a318beded4 Update plugin list and use correct names. 2012-03-11 16:34:41 -07:00
Lance Stout
5f4b528e6b Ensure that result stanzas are returned, as expected. 2012-03-11 16:13:19 -07:00
Lance Stout
f759b0ada1 Add support for XEP-0108: User Activity. 2012-03-11 12:37:54 -07:00
Lance Stout
7d89fa27a8 Expand support of XEP-0172 (user nickname) to include PEP. 2012-03-11 00:22:28 -08:00
Lance Stout
10ec92f7c6 Add support for XEP-0107, User Mood. 2012-03-10 23:32:20 -08:00
Lance Stout
58d2f317a0 Fix plugin loading logs for XEP-0118 and XEP-0163. 2012-03-10 23:31:54 -08:00
Lance Stout
34b094561f Add support for XEP-0080. 2012-03-10 12:54:31 -08:00
Lance Stout
91155444c0 Resolve plugin dependency chains with XEP-0115.
The post_init() system can only reliably handle a single layer
of dependencies between plugins, but PEP plugins with XEP-0115
exceed that limit and plugins can be post_init'ed out of order. To
resolve this, we will special case XEP-0115 to be post_init'ed
first until the new plugin system with dependency tracking is
stable.
2012-03-10 12:48:35 -08:00
Lance Stout
7f71ac7e0a Add user tune feature to disco, not just notifications. 2012-03-10 10:54:24 -08:00
Lance Stout
e5fc59a4c6 Ensure post init works for XEP-0118. 2012-03-10 10:44:53 -08:00
Lance Stout
549a9ab472 Add support for XEP-0118.
See examples/user_tune.py for a demonstration using the currently
playing song in iTunes.
2012-03-10 10:30:32 -08:00
Lance Stout
09720dcf42 Fix XEP-0163's updating of caps. 2012-03-10 10:20:06 -08:00
Lance Stout
ec044affd4 Only auto-broadcast caps changes after a session has started. 2012-03-10 10:19:43 -08:00
Lance Stout
af39945009 Add XEP-0163 plugin.
This is just a very simple wrapper for XEP-0030, XEP-0115, and XEP-0060
for adding interests to caps information, and publishing.
2012-03-10 09:23:47 -08:00
Lance Stout
78a50d0237 Add support for pubsub notification events.
Publishes, retractions, purges, and deletions now raise the events:

- pubsub_publish
- pubsub_retract
- pubsub_purge
- pubsub_delete

In addition, custom events may be raised based on the node that
generated the notification. For example:

xmpp['xep_0060'].map_node_event('http://jabber.org/protocol/tune',
                                'user_tune')

will allow for using the events:

- user_tune_publish
- user_tune_retract
- user_tune_purge
- user_tune_delete
2012-03-10 00:07:56 -08:00
Lance Stout
861d279b08 Correct missing pubsub#event stanzas and interfaces. 2012-03-10 00:07:15 -08:00
Lance Stout
eb1a32fc90 Fix setup.py to include the rosterver stream feature plugin. 2012-03-08 16:21:22 -08:00
Lance Stout
4610a6615c Add tests for roster versioning. 2012-03-07 16:11:59 -08:00
Lance Stout
4cb8a8d389 Modify the cert event to provide the PEM encoded cert in all cases. 2012-03-07 15:03:35 -08:00
Lance Stout
a71823dc04 Add support for roster versioning.
This was XEP-0237, but is now part of RFC 6121.

Roster backends should now expose two additional methods:

version(jid):
    Return the version of the given JID's roster.
set_version(jid, version):
    Update the version of the given JID's roster.

A new state field will be passed to the backend if an item
has been marked for removal. This is 'removed' which will
be set to True.
2012-03-07 14:55:27 -08:00
Lance Stout
d41ada6b66 Cleanup logging when loading a custom plugin. 2012-03-05 11:30:36 -08:00
Lance Stout
fdfe2cd64f Propagate save option when setting a roster backend. 2012-03-05 11:28:10 -08:00
Lance Stout
7b51c6f5cc Save existing roster content when setting a new backend. 2012-03-05 11:12:13 -08:00
Lance Stout
be7f07ad12 Prevent excess loading from the roster db.
Fixes issue #148
2012-03-05 11:11:35 -08:00
Lance Stout
830db11b41 Ensure that roster nodes aren't empty strings.
This would happen when receiving presence without a 'to' field, which
happens when receiving presence from other resources for the same account.
2012-03-05 11:08:57 -08:00
Lance Stout
53bcd33e1d Let disconnect() wait for its lock for a few seconds.
This should eliminate most debug statements about not being
able to acquire a lock during disconnect.
2012-02-22 07:57:13 -08:00
Lance Stout
e3d596c9fa Update XEP-0085 plugin to work with both ElementTree and cElementTree
Each state element must have its own stanza class now. A stanza class
with an empty name field causes errors in ElementTree, even though
it works fine with cElementTree.
2012-02-19 20:28:31 -08:00
Lance Stout
ecd6ad6930 Fix incompatibility with clearing an element between ElementTree and cElementTree 2012-02-19 20:27:53 -08:00
Lance Stout
c36073b40e xml.etree.ElementTree raises ExpatError instead of SyntaxError or ParseError. 2012-02-19 20:27:19 -08:00
Lance Stout
afe0d16797 Centralize references to ET to make switching implementations easier. 2012-02-19 20:26:40 -08:00
Lance Stout
977fcc0632 Fix instances of using undefined variables. 2012-02-18 11:56:10 -08:00
Lance Stout
94b57d232d More pyflakes cleanup. 2012-02-18 11:44:05 -08:00
Lance Stout
7cdedb2ec0 More import cleanup based on pyflakes. 2012-02-18 11:40:34 -08:00
Lance Stout
676324805e Use JID objects when dealing with roster items. 2012-02-18 11:39:47 -08:00
Lance Stout
7d74a7b027 More extraneous import cleanup. 2012-02-17 14:59:56 -08:00
Lance Stout
9d5eb864d1 More import cleanups based on pyflakes results. 2012-02-17 14:41:31 -08:00
Lance Stout
86a482e032 Fix pyflakes complaints for XEP-0115 plugin. 2012-02-17 11:40:51 -08:00
Lance Stout
c43c7be86c Make last_xml usage a little more explict. 2012-02-17 11:40:07 -08:00
Lance Stout
c58462f154 Fix undeclared variable usage for reconnect. 2012-02-17 11:12:48 -08:00
Correl Roush
31d3e3b2b6 Updated XEP-0009 to handle unicode strings 2012-02-17 12:24:44 -05:00
Lance Stout
fb2582e53b Fix fixing remove_stanza()
Fixes issue #146
2012-02-16 07:25:44 -08:00
Lance Stout
d807613117 Don't retrieve cert until a connection is made. 2012-02-16 07:02:56 -08:00
Lance Stout
6d922d00c3 Fix remove_stanza().
Fixes issue #146
2012-02-16 07:02:19 -08:00
Lance Stout
61ea84093b Don't shutdown completely after handling SyntaxError.
The ``shutdown = True`` line was preventing the stream from reconnecting
after handling the error.

Fixes issues #101, #145
2012-02-10 19:28:12 -08:00
Lance Stout
e76d6a481f Fix undefined variable references when DNS timeouts. 2012-02-10 19:20:17 -08:00
Lance Stout
c1357717d9 Use '=' as base64 value for empty string SASL results. 2012-02-09 22:01:11 -08:00
Lance Stout
ca5145c210 Fix IPv6 query logging. 2012-02-10 06:46:51 +01:00
Lance Stout
1a272fd276 Add support for querying and connecting to IPv6 addresses.
Tested using servers provided by Florian Jensen (flosoft.biz)
during the 2012 FOSDEM XMPP Summit.

Fixes issue #94.
2012-02-09 21:28:28 -08:00
Lance Stout
952260b423 Add ssl_cert event (direct).
The payload is a dictionary of parsed cert data, as provided by
Python's getpeercert() socket method. It unfortunately does not
provide much detail beyond basic info.
2012-02-04 14:16:37 +01:00
Lance Stout
caa967105c Add more XEP-0047 tests. 2012-02-03 16:29:38 +01:00
Lance Stout
d565e4be20 Fix XEP-0184 imports 2012-02-03 16:08:27 +01:00
Lance Stout
85dd005abc Fix infinite callback loop. 2012-02-03 16:03:46 +01:00
Lance Stout
021c57205f Don't assume data is ASCII in saslprep. 2012-02-03 16:01:54 +01:00
Lance Stout
261a501afc Merge remote-tracking branch 'whooo/master' into develop 2012-02-03 15:23:01 +01:00
Erik Larsson
9a38a101d2 Added fritzy to the copyright for xep_0184 2012-02-03 15:17:01 +01:00
Lance Stout
4665c5cf1a Fix data stanza based on test results. 2012-02-02 19:19:50 +01:00
Lance Stout
bd52a5e6c1 Initial, mostly working XEP-0047 plugin.
This is inspired by the version from macdiesel and tomstrummer, but
their version was heavily linked with XEP-0096 and focused solely
on file transfer. This version is a more generic implementation.
2012-02-02 18:27:23 +01:00
Lance Stout
f98e5a03de Fix typo s/is_set/is_set() 2012-02-02 18:14:48 +01:00
Erik Larsson
2217c69757 Added plugin for XEP-0184 2012-02-02 14:29:27 +01:00
Thomas Hansen
5a4df56836 examples: fix rpc examples. __init__ method was wrongly named "__init" causing proxy and handler class to not be initialized. 2012-01-31 12:38:41 -06:00
Lance Stout
3ab7c8bcc3 Make socket_error run as a direct event to ensure that it is handled.
Socket errors that occur before stream processing begins could not be
handled as the event loop would not be running yet.

Resolves issue #142
2012-01-28 18:54:46 -08:00
Lance Stout
8f25acd0f3 Bump version number in develop branch to 1.0.1dev. 2012-01-25 20:44:41 -08:00
Lance Stout
999f1932cc Merge pull request #138 from rhcarvalho/patch-2
Set default argument value.
2012-01-25 20:41:45 -08:00
Lance Stout
69940a8ab9 Fix a few typos. 2012-01-24 00:07:31 -08:00
Lance Stout
13158e3cdf Revert the X-GOOGLE-TOKEN mech to not perform HTTP requests.
Added new example for how to retrieve a Google token, following
the best case, non-browser, workflow. Other thirdparty auth
mechs (Facebook, MSN) follow a similar pattern of using an
access token.
2012-01-23 23:58:40 -08:00
Lance Stout
f06589c913 Merge pull request #140 from rhcarvalho/patch-3
Fix ValueError when line has more than one '='.
2012-01-23 10:53:19 -08:00
Rodolfo Carvalho
2735b680b9 Fix ValueError when line has more than one '='. 2012-01-22 18:32:32 -02:00
Rodolfo Henrique Carvalho
5f1d4ce433 Set default argument value.
Without this features/feature_mechanisms/mechanisms.py throws an error when calling the method `process' without arguments on this mechanism.
2012-01-22 01:53:07 -02:00
Lance Stout
25f87607aa Add support for X-GOOGLE-TOKEN.
This is mainly just useful for authenticating without using TLS.

If an access token is not provided, an attempt will be made to
retrieve one from Google.
2012-01-21 00:44:03 -08:00
Lance Stout
f81fb6af44 Require explicitly setting access_token value.
Silently substituting the password field was nice, but for mechs
that can use either the password or an access token, it makes
things very difficult. This really only affects MSN clients since
Facebook clients should already be setting the api key.
2012-01-21 00:19:59 -08:00
Lance Stout
bb0a5186d6 Handle SASLCancelled and SASLError exceptions. 2012-01-21 00:19:08 -08:00
Lance Stout
baad907422 Add missing SASL <abort /> stanza 2012-01-21 00:17:49 -08:00
Lance Stout
1022fc0060 Make things work with Python3's byte semantics. 2012-01-20 02:27:30 -08:00
Lance Stout
3a22d798f8 Allow attempting multiple SASL mechs during a single stream.
Instead of disconnecting when the first chosen mech fails, we will
try all of them once.
2012-01-20 02:01:08 -08:00
Lance Stout
71ea430c62 Add support for X-FACEBOOK-PLATFORM SASL mechanism.
This requires an extra credential for SASL authentication:

xmpp = ClientXMPP('user@chat.facebook.com', '...access_token...')
xmpp.credentials['api_key'] = '...api_key...'
2012-01-20 01:24:05 -08:00
Lance Stout
0d2125e737 Add an extra config dict to store SASL credentials.
We'll need extra things beyond just a password, such as api_key.
2012-01-20 01:08:25 -08:00
Lance Stout
02f4006153 Add basic start for a client side XEP-0077 plugin. 2012-01-19 02:37:36 -08:00
Lance Stout
b25668b5b7 Fix detecting end of result set paging. 2012-01-18 19:57:49 -08:00
Lance Stout
bb3080e829 Merge branch 'docs' into develop
Conflicts:
	docs/index.rst
2012-01-18 15:36:18 -08:00
Lance Stout
bd85e95398 Gah, too many branch conflicts. 2012-01-18 15:34:49 -08:00
Lance Stout
22cc194ed8 Merge branch 'docs' of github.com:fritzy/SleekXMPP into docs
Conflicts:
	docs/index.rst
2012-01-18 15:34:12 -08:00
Lance Stout
79b71228c1 Fix some more merge conflicts. 2012-01-18 15:31:45 -08:00
Lance Stout
fd515d807c Add example of accessing plugins to the README. 2012-01-18 15:22:19 -08:00
Lance Stout
4f4c121d9b Fix merge errors and bot example. 2012-01-18 15:16:56 -08:00
Lance Stout
72e1ab47fc Merge branch 'docs' into develop
Conflicts:
	docs/_static/haiku.css
	docs/_static/header.png
	docs/conf.py
	docs/getting_started/muc.rst
	docs/index.rst
	examples/muc.py
2012-01-18 15:04:33 -08:00
Lance Stout
3575084640 Update home page to include bot example, and example of using a plugin. 2012-01-18 14:24:23 -08:00
Lance Stout
1e01903072 Revert "Remove stream feature handlers on session_start."
This reverts commit 4274f49ada.

The SASL mech was choking on this, so let's send it back for some
more refining.
2012-01-18 11:51:00 -08:00
Lance Stout
3672856ab4 Fix roster key issue for non-JID keys. 2012-01-17 23:10:14 -08:00
Lance Stout
86d8736dcc Hash JIDs based on full JID string.
This makes JID objects equivalent to strings in dictionaries, etc.

>>> j = JID('foo@example.com')
>>> s = 'foo@example.com'
>>> d = {j: 'yay'}
>>> d[j]
'yay'
>>> d[s]
'yay'
>>> d[s] = 'yay!!'
>>> d[j]
'yay!!'
2012-01-17 23:03:48 -08:00
Lance Stout
2923f56561 Pre-parse StanzaPath paths to speed up matching.
The parsing and namespace cleaning isn't terribly expensive, but it does
add up. It was adding an extra 5sec when processing 100,000 basic
message stanzas.
2012-01-17 22:28:44 -08:00
Lance Stout
4274f49ada Remove stream feature handlers on session_start.
Based on profiling, using around 35 stream handlers quarters the number
of basic message stanzas that can be processed in a second, in
comparison to only using the bare minimum of four handlers.

To help, we can drop handlers for stream features once the session
has started. So that we can re-enable these handlers when a stream
must restart, the 'stream_start' event has been added which fires
whenever a stream header is received.

The 'stream_start' event is a more generic replacement for the
existing start_stream_handler() method.
2012-01-17 22:14:24 -08:00
Lance Stout
a4b27ff031 Merge pull request #137 from rhcarvalho/patch-1
Use jid.bare as a key instead of a JID instance.
2012-01-16 11:44:42 -08:00
Rodolfo Henrique Carvalho
f49b6fa79f Use jid.bare as a key instead of a JID instance. 2012-01-16 16:59:45 -02:00
Lance Stout
7b854a190e Tidy up and update the plugin __init__ file. 2012-01-15 22:51:59 -08:00
Lance Stout
947d1ffbb3 Fix xep_0030 reference warning. 2012-01-14 17:12:39 -08:00
Lance Stout
de35848500 Don't serialize XML unless we need to. 2012-01-14 10:54:48 -08:00
Lance Stout
1ae219025a Don't dump exception logs for XML stream parsing errors.
The exceptions are handled, so we don't need to clutter the output logs.
2012-01-12 22:26:15 -08:00
Lance Stout
e8b2dd6698 Update Roster stanza to use RosterItem substanzas.
get_roster() now returns the Iq result stanza instead of True (stanzas
also evaluate to True).
2012-01-12 17:21:43 -08:00
Lance Stout
c0074f95b1 update_caps() can now do presence broadcasting.
As part of adding this feature:

    - fixed bug in update_caps() not assigning verstrings
    - fixed xep_0004 typo
    - can now use None as a roster key which will map to boundjid.bare
    - fixed using JID objects in disco node handlers
    - fixed failing test related to get_roster

Several of these bugs I've fixed before, so I either didn't push them
earlier, or I clobbered something when merging. *shrug*
2012-01-11 16:39:55 -08:00
Lance Stout
a79ce1c35e Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2012-01-10 20:05:25 -08:00
Lance Stout
1eb69f7075 Make the roster easier to inspect.
The __repr__ version now looks like a regular dictionary.
2012-01-10 20:03:22 -08:00
Lance Stout
a86935a42f Make get_roster(block=False) work properly.
Fixes issue #136
2012-01-10 19:57:38 -08:00
Lance Stout
1674bd753e Fix setup.py Unicode issue with README.rst
Fixes issue #135
2012-01-09 15:38:19 -08:00
Lance Stout
6b9a55e62d Sync with Suelta. 2012-01-07 00:19:08 -05:00
Lance Stout
c578ddeb1a Add support for MSN with X-MESSENGER-OAUTH2 SASL support.
NOTE: This requires already having the access token. It does NOT
perform any OAuth requests.
2012-01-06 23:31:58 -05:00
Lance Stout
8ef7188dae Fix client_roster when the bare JID changes after binding.
Adds session_bind event.
2012-01-06 23:30:14 -05:00
Lance Stout
738ec92b8e Fix a few typos. 2012-01-05 13:11:42 -05:00
Lance Stout
be9e26b4a3 Apply Te-Je's MUC guide patch. 2012-01-05 13:09:20 -05:00
Lance Stout
b345c227b2 More &yet branding 2012-01-05 13:07:44 -05:00
Lance Stout
c7e95c8dec Add &yet contact info 2012-01-05 12:28:30 -05:00
Lance Stout
3a4e3d3f51 Update doc settings to new theme, add examples, use 1.0 2012-01-05 12:13:06 -05:00
Lance Stout
8fd2efa2fa Merge branch 'develop-1.1' into develop 2012-01-05 11:33:47 -05:00
Lance Stout
97378998a5 Break the docs out into their own branch. 2012-01-05 11:31:54 -05:00
Lance Stout
79f1aa0e1b Update version and README for 1.0 release. 2012-01-03 17:04:15 -05:00
Lance Stout
fb5a6a7d71 Merge pull request #132 from rhcarvalho/master
Fix a typo in several files.
2012-01-02 13:10:46 -08:00
Rodolfo Carvalho
7d1c5f4a2b Fix a typo in several files.
This fixes several instances of "intial" for "initial".
2012-01-02 18:59:39 -02:00
Lance Stout
6b6995bb0b Merge branch 'develop' into develop-1.1 2011-12-31 21:17:01 -05:00
Lance Stout
27c658922e Fix handing caps in Python3, allow update_caps() call before process() 2011-12-31 21:15:40 -05:00
Lance Stout
1b0fd76b45 Merge pull request #131 from rhcarvalho/master
Small changes to the examples
2011-12-31 17:27:57 -08:00
Lance Stout
35954cdc90 Fix a few holes in caps.
Protip: Don't test using a custom disco handler that always returns the
same feature set :p
2011-12-31 19:18:00 -05:00
Rodolfo Carvalho
46e93bea09 Remove unused import.
I forgot about this one before!
2011-12-31 20:14:24 -02:00
Rodolfo Carvalho
cbc6a0296b Ask interactively for missing command line arguments.
Instead of complaining that the arguments were not given, ask interactively for input.
This example was the only one to behave differently from the others.
2011-12-31 19:54:14 -02:00
Rodolfo Carvalho
cc63bef179 Remove unused imports in the examples. 2011-12-31 19:50:53 -02:00
Rodolfo Carvalho
cbcfa156c4 Add missing import. 2011-12-31 19:48:03 -02:00
Lance Stout
fa912aeb84 Merge branch 'develop' into develop-1.1 2011-12-31 12:34:17 -05:00
Lance Stout
4a12e1059a Add proxy docs. 2011-12-31 12:33:32 -05:00
Lance Stout
9a5e2ae768 Merge branch 'develop' into develop-1.1 2011-12-31 02:16:08 -05:00
Lance Stout
f9cd051209 Add echo component briefing. 2011-12-31 02:00:54 -05:00
Lance Stout
e0545bf0bc Merge branch 'develop' into develop-1.1 2011-12-31 01:29:12 -05:00
Lance Stout
03bc38f7e3 Add docs on using Iq stanzas. 2011-12-31 01:28:41 -05:00
Lance Stout
4e23a4e08e Merge pull request #130 from rhcarvalho/master
Some small fixes
2011-12-30 20:14:54 -08:00
Lance Stout
d817d64c65 Enable caps stream feature. 2011-12-30 22:34:57 -05:00
Lance Stout
8a29ec67ac Add XEP-0115 plugin.
Finally
2011-12-30 21:45:25 -05:00
Lance Stout
6722b0224a Add option to disable condensing and converting form values.
XEP-0115 needs to use the raw XML character data.
2011-12-30 21:43:39 -05:00
Lance Stout
8eb225bdec Add option for disabling identity and feature deduplication.
XEP-0115 requires detecting duplicates, so we can't always silently
ignore them.
2011-12-30 20:53:18 -05:00
Lance Stout
a7df76a275 Add 'supports' and 'has_identity' node handlers. 2011-12-30 20:52:44 -05:00
Lance Stout
efae8f3369 Automatically use local disco based on the JID. 2011-12-30 20:51:41 -05:00
Lance Stout
a11e6c0b77 Be more lenient on required arguments to disco node handlers. 2011-12-30 20:51:02 -05:00
Lance Stout
1bb0b38868 Make the disco logs nicer. 2011-12-30 20:50:15 -05:00
Rodolfo Carvalho
8cafa8578f Update examples to use the block'' argument instead of the deprecated threaded''. 2011-12-30 17:25:03 -02:00
Rodolfo Carvalho
b74ea47650 Fix docstring of a method of Message stanzas. 2011-12-30 17:08:32 -02:00
Rodolfo Carvalho
2dc230a68b Replace pydns with dnspython in the comments of the examples. 2011-12-30 00:08:05 -02:00
Lance Stout
4df1641689 Add set_info disco handler. 2011-12-28 11:46:13 -05:00
Lance Stout
5ef0b96d5c Fix caching for clients. 2011-12-28 11:37:05 -05:00
Lance Stout
d979b5f2b9 Add caching support to xep_0030.
New plugin configuration options:

    use_cache    - Enable caching disco info results. Defaults to True
    wrap_results - Always return disco results in an Iq stanza. Defaults
                   to False

Node handler changes:

    Handlers now take four arguments: jid, node, ifrom, data

    Most older style handlers will still work, depending on if they
    raise a TypeError for incorrect number of arguments. Handlers that
    used *args may not work.

New get_info options:

    cached - Passing cached=True to get_info() will attempt to load
             results from the cache. If nothing is found, a query
             will be sent as normal. If set to False, the cache
             will be skipped, even if it contains results.

New method:

    supports() - Given a JID/node pair and a feature, return True
                 if the feature is supported, False if not, and
                 None if there was a timeout. By default, the search
                 will use the cache.
2011-12-28 10:16:31 -05:00
Lance Stout
1a61bdb302 Ensure that stanza plugins work as expected if the XML is appended. 2011-12-28 09:53:22 -05:00
Lance Stout
e8545dd2bc Merge branch 'develop-1.1' of github.com:fritzy/SleekXMPP into develop-1.1 2011-12-27 18:05:55 -05:00
Lance Stout
2f2ebb37e4 Merge branch 'develop' into develop-1.1 2011-12-27 18:05:42 -05:00
Lance Stout
522f0dac16 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-12-27 18:03:08 -05:00
Lance Stout
cd5ae944ec Merge pull request #128 from correl/rpc_value_conversion_fix
XEP-0009 tests updated for Python3
2011-12-27 15:03:01 -08:00
Lance Stout
42a86fe0d4 Disconnect when a SyntaxError is found.
This should resolve issue #102
2011-12-27 18:01:26 -05:00
Correl Roush
e928b9c434 XEP-0009: Updated tests to work in python 3 2011-12-20 21:19:51 -05:00
Lance Stout
fb55d9e9d1 Add comma to fix pubsub error conditions.
Fixes issue #127
2011-12-20 12:30:35 -05:00
Lance Stout
74e7e5a291 Merge pull request #125 from correl/rpc_value_conversion_fix
XEP-0009 XML-RPC value conversion fixes and unit tests
2011-12-20 09:29:03 -08:00
Correl Roush
6c58b8cc4b XEP-0009: Updated RPC value conversion code
Updated the XML-RPC value conversion to correctly apply namespaces, and
fixed an error uncovered by the tests in the XML -> Python conversion of
dateTime values.
2011-12-20 02:03:06 -05:00
Correl Roush
2b3d11a7a5 XEP-0009: Added value conversion unit tests
Added tests for bidirectional conversion of all XML-RPC data types
2011-12-20 02:01:34 -05:00
Correl Roush
9950208d06 Fixes Issue #123: Corrected boolean xml to python conversion 2011-12-16 17:41:16 +00:00
Lance Stout
a67e16d1b7 Merge pull request #122 from correl/acl_check_fix
XEP-0009: ACL.check fix
2011-12-15 16:14:29 -08:00
Correl Roush
c98a22e065 Fixed Issue 93: ACL.check jid parameter should be a string value 2011-12-15 21:58:33 +00:00
Lance Stout
8f9d1bcfe0 Merge branch 'develop-1.1' of github.com:fritzy/SleekXMPP into develop-1.1 2011-12-15 12:04:14 -08:00
Lance Stout
a7a2fd1d5b Merge branch 'develop' into develop-1.1 2011-12-15 12:03:52 -08:00
Lance Stout
d496417deb Allow XEP-0082 to return datetime objects without having to format and reparse. 2011-12-15 12:02:08 -08:00
Lance Stout
f6e30edbc4 Log received data AFTER filtering.
This allows applications to filter out sensitive information, such
as passwords, so that it won't appear in the logs.

It does mean that the debug logs will not show the actual received
data, and there will be no indication of tampering, unless the
filter author explicitly logs and notes that a change was made.
2011-12-14 21:14:27 -08:00
Lance Stout
45ed68006f Add tests for filters. 2011-12-13 20:05:31 -08:00
Lance Stout
dcb0d8b00e Merge branch 'develop' into develop-1.1 2011-12-13 09:38:27 -08:00
Lance Stout
116bb6e1b9 Use OrderedDicts instead of regular dictionaries when returning values from forms. 2011-12-13 09:00:45 -08:00
Lance Stout
9c6dde5d22 Ensure that item fields have the proper type.
The item fields were not setting their type based on the reported
field's type attribute, so values were not being encoded properly.

Fixes issue #121
2011-12-13 08:59:39 -08:00
Lance Stout
cb635dcd5a Add parameter docs for add_filter. 2011-12-12 22:37:19 -08:00
Lance Stout
eff3330e75 Add support for incoming/outgoing filters.
A filter accepts and returns a stanza, but potentially modified.

To prevent sending/receiving a stanza, a filter may return None.

Incoming:
    self.add_filter('in', in_filter)

Outgoing:
    self.add_filter('out', out_filter)

Filters are applied in the order thay are added. However, you may
add an order parameter, which is the place in the list to insert the
filter:

    self.add_filter('in', in_filter, order=0)
2011-12-12 22:17:07 -08:00
Lance Stout
fc8a13df5a Allow disco info/items handlers to return full Iq stanzas.
Only allowing handlers to return a DiscoInfo/DiscoItem stanza works
for the majority of cases, but does not allow for the addition of
an RSM stanza, or other extensions.

An Iq stanza returned by a handler must already be configured as
a reply.
2011-12-12 19:38:32 -08:00
Lance Stout
85e9042db6 Pass the Iq stanza to disco item handlers. 2011-12-12 16:34:24 -08:00
Lance Stout
62e6d6fb4c Fix iterable substanzas when added as normal plugin.
If an iterable plugin was an enabled, it wasn't added to
the iterables list.
2011-12-11 17:04:58 -08:00
Lance Stout
16c72e8efd Use UTC for xep_0082.date. 2011-12-09 23:59:33 -08:00
Lance Stout
efe1b9f5a9 Allow sending stanzas on session_end.
May set self.disconnect_wait=True so that all disconnect
calls wait for the send queue to empty, unless explicitly
overridden with wait=False.

The session_end now fires before closing the socket so
that final stanzas may be sent, such as unavailable presences
for components.
2011-12-09 23:56:39 -08:00
Lance Stout
65dbddb6b6 Fix logging when loading plugins. 2011-12-09 20:57:08 -08:00
Lance Stout
2a67a31120 Prevent hang when terminating during delayed connection. 2011-12-07 22:16:58 -08:00
Lance Stout
a720c3348b Updated last bit of core files to use new API format. 2011-12-05 20:37:47 -08:00
Lance Stout
79ac60b6e8 Fix example boilerplate code syntax. 2011-12-05 08:57:57 -08:00
Lance Stout
e01c2d222a More doc updates 2011-12-05 08:55:05 -08:00
Lance Stout
8922e2050a Update the API docs for XMLStream 2011-12-04 20:35:17 -08:00
Lance Stout
a85891c611 Add API docs for the scheduler 2011-12-04 16:43:05 -08:00
Lance Stout
2586fdffda Update api docs for handlers and matchers 2011-12-04 16:26:14 -08:00
Lance Stout
c9dc9ec11e Update supported XEP list 2011-12-04 15:39:49 -08:00
Lance Stout
b9332142c9 Update api docs for JID 2011-12-04 13:42:46 -08:00
Lance Stout
b7b53362e1 Ensure that adhoc command clients have form plugin registered.
The form plugin was being registered on first use for providers,
but not for clients receiving the form.

NOTE: Use of non-form payloads will have this issue - adhoc command
      clients will need to have an expectation beforehand of what
      the command payload will be to properly load stanza plugins.
2011-12-04 01:24:35 -08:00
Lance Stout
68cf66a5fe Ensure that saving a roster item includes the correct subscription value.
Fixes issue #118
2011-11-28 15:00:35 -08:00
Florent Le Coz
4eb7eeb40f Send the encoded data (bytes) and not the str, on the socket. 2011-11-25 01:45:43 +08:00
Lance Stout
a1d64fa215 Experimental support for handling SSL write errors. 2011-11-23 23:59:05 -08:00
Lance Stout
5f44c0e678 Add docs for filesocket 2011-11-22 16:33:38 -08:00
Lance Stout
b87c4d786d Update tostring docs, plus more doc cleanup 2011-11-22 16:25:33 -08:00
Lance Stout
329b0df3f6 Some more docs house cleaning 2011-11-22 15:25:24 -08:00
Lance Stout
6906c15e8e Update docs for tostring 2011-11-22 15:25:02 -08:00
Lance Stout
ff5421cefc Moar docs! 2011-11-21 23:28:19 -08:00
Lance Stout
4498e992a2 Add more stanzabase docs 2011-11-21 23:17:39 -08:00
Lance Stout
2d610dfdc8 Fix stream handler test for multiple handlers to exist properly. 2011-11-21 22:03:43 -08:00
Lance Stout
2b0a05ee32 Update stanzabase docs 2011-11-21 21:51:19 -08:00
Lance Stout
bc2d0ee9a8 Update docs index 2011-11-20 17:29:54 -08:00
Lance Stout
862a2a1440 Ensure that reconnection happens properly after connection loss.
Calling reconnect() simultaneously from multiple threads (like when
using XEP-0199 keepalive) could break because the connection state
can transition and break the state expectations in one of the
reconnect() calls.
2011-11-20 12:18:37 -08:00
Lance Stout
fba60ffff1 Convert daemon threads back into normal threads.
This may need to be reverted if CTRL-C handling breaks, but everything
works fine so far in testing.

Resolves issue #95.
2011-11-20 12:17:35 -08:00
Lance Stout
d1a945a305 Tidy up logging some more 2011-11-19 19:18:43 -08:00
Lance Stout
685b9ab102 Fix logging exceptions from formatting issues. 2011-11-19 19:08:27 -08:00
Lance Stout
24f27c0fe3 Pass generic connection errors to XMLStream.exception() 2011-11-19 19:01:07 -08:00
Lance Stout
3019c82d8a Use a list comprehension instead of filter() to work with Python3. 2011-11-19 18:49:18 -08:00
Lance Stout
f9d0b55ca3 Add unit test for copying stanzas when passed to events. 2011-11-19 18:43:38 -08:00
Lance Stout
b54cc97e4c Merge remote-tracking branch 'vijayp/master' into HEAD
Conflicts:
	examples/ping.py
	sleekxmpp/basexmpp.py
	sleekxmpp/clientxmpp.py
	sleekxmpp/features/feature_bind/bind.py
	sleekxmpp/features/feature_mechanisms/mechanisms.py
	sleekxmpp/plugins/gmail_notify.py
	sleekxmpp/plugins/jobs.py
	sleekxmpp/plugins/xep_0009/remote.py
	sleekxmpp/plugins/xep_0009/rpc.py
	sleekxmpp/plugins/xep_0012.py
	sleekxmpp/plugins/xep_0045.py
	sleekxmpp/plugins/xep_0050/adhoc.py
	sleekxmpp/plugins/xep_0078/legacyauth.py
	sleekxmpp/plugins/xep_0085/chat_states.py
	sleekxmpp/plugins/xep_0199/ping.py
	sleekxmpp/plugins/xep_0224/attention.py
	sleekxmpp/xmlstream/handler/waiter.py
	sleekxmpp/xmlstream/matcher/xmlmask.py
	sleekxmpp/xmlstream/xmlstream.py

Conflicts:
	examples/ping.py
	sleekxmpp/basexmpp.py
	sleekxmpp/clientxmpp.py
	sleekxmpp/features/feature_bind/bind.py
	sleekxmpp/features/feature_mechanisms/mechanisms.py
	sleekxmpp/plugins/gmail_notify.py
	sleekxmpp/plugins/jobs.py
	sleekxmpp/plugins/xep_0009/remote.py
	sleekxmpp/plugins/xep_0009/rpc.py
	sleekxmpp/plugins/xep_0012.py
	sleekxmpp/plugins/xep_0045.py
	sleekxmpp/plugins/xep_0050/adhoc.py
	sleekxmpp/plugins/xep_0078/legacyauth.py
	sleekxmpp/plugins/xep_0085/chat_states.py
	sleekxmpp/plugins/xep_0199/ping.py
	sleekxmpp/plugins/xep_0224/attention.py
	sleekxmpp/xmlstream/handler/waiter.py
	sleekxmpp/xmlstream/matcher/xmlmask.py
	sleekxmpp/xmlstream/xmlstream.py
2011-11-19 18:23:26 -08:00
Vijay Pandurangan
e3b9d5abbf double copy 2011-11-19 16:03:17 -08:00
Vijay Pandurangan
2332970cf2 elide unnecessary copy 2011-11-19 16:02:41 -08:00
Vijay Pandurangan
48af3d3322 remove unnecessary copies when only one handler matches. This was taking up ~ 15% of CPU on moderate load. 2011-11-19 15:59:38 -08:00
Lance Stout
429c94d6a9 Tidy up logging calls. 2011-11-19 12:07:57 -08:00
Vijay Pandurangan
deb52ad350 This change stops sleekxmpp from spending huge amounts of time unnecessarily computing logging data that may never be used. This is a HUGE performance improvement; in some of my test runs, unnecessary string creation was accounting for > 60% of all CPU time.
Note that using % in a string will _always_ perform the sting substitutions, because the strings are constructed before the function is called. So log.debug('%s' % expensiveoperation()) will take about the same CPU time whether or not the logging level is DEBUG or INFO. if you use , no substitutions are performed unless the string is actually logged
2011-11-20 03:39:05 +08:00
Vijay Pandurangan
6f3cc77bb5 This change stops sleekxmpp from spending huge amounts of time unnecessarily computing logging data that may never be used. This is a HUGE performance improvement; in some of my test runs, unnecessary string creation was accounting for > 60% of all CPU time.
Note that using % in a string will _always_ perform the sting substitutions, because the strings are constructed before the function is called. So log.debug('%s' % expensiveoperation()) will take about the same CPU time whether or not the logging level is DEBUG or INFO. if you use , no substitutions are performed unless the string is actually logged
2011-11-19 11:30:44 -08:00
Lance Stout
1baf139ca4 Bump next release version to 1.0-RC4 2011-11-18 16:40:17 -08:00
Lance Stout
7945b3e738 Remove the config_component example in favor of echo_component.
The roster portion of the example is too outdated.
2011-11-18 16:26:02 -08:00
Lance Stout
d4c1ff5309 Also fire changed_status when the status text changes for a resource. 2011-11-18 13:57:41 -08:00
Lance Stout
22868c3924 Fix changed_status event
Once again only fires when a resource's presence show value changes.
2011-11-18 13:39:02 -08:00
Lance Stout
2de1be188c Add echo component example. 2011-11-17 12:25:56 -08:00
Lance Stout
9faecec2db Simplify boilerplate example. 2011-11-14 12:00:21 -08:00
Lance Stout
5d7111fe3b Update list of stable releases. 2011-11-14 11:46:07 -08:00
Lance Stout
0c86f8288d No need to continue processing loop if an error ocurred and auto_reconnect=False. 2011-11-14 11:21:05 -08:00
Lance Stout
5a6a65fd9f Fix typo 2011-11-14 11:20:53 -08:00
Lance Stout
43c4d23896 Explicitly test for inequality in JIDs.
Fixes issue #113
2011-11-14 09:15:43 -08:00
Lance Stout
9f9e8db814 Add use_ssl parameter to ClientXMPP.connect 2011-11-11 01:52:18 -08:00
Lance Stout
b8efcc7cf0 Don't just call self.disconnect in self.reconnect.
It messes up the auto_reconnect value and causes the XML processing
loop to spin wildly with errors on a stream disconnect.
2011-11-08 19:23:53 -08:00
Lance Stout
2f29d18e53 Use setuptools if available. 2011-11-08 07:01:16 -08:00
Lance Stout
888e286a09 Continue trying to reconnect, even if the attempt fails.
The transition from disconnected to connected states must be done in a
loop in case the transition fails, not just once and hope it worked.
2011-11-07 01:13:34 -08:00
Lance Stout
1a93a187f0 Fix a crash when removing a contact.
Original author: louiz
2011-11-06 08:33:03 -08:00
Lance Stout
a8d5da5091 Restore original behaviour for auto_authorize and auto_subscribe.
The change to using the new roster broke the original auto_* values
and used per-roster versions. The original auto_* values will now set
the behaviour globally. Use the per-roster values to override for a
specific JID.
2011-11-06 08:25:29 -08:00
Lance Stout
e2720fac9e FIX SCRAM-SHA-1-PLUS
The mechanism name was being correctly de-plussed, but then we used the
original, -PLUS, name to extract the hash, finding SHA-1-PLUS and therefore
finding no match.

Test-Information:

Tested with Sleek against an Isode M-Link with SCRAM-SHA-1-PLUS available.

Author: dwd
2011-10-27 15:16:54 -04:00
Lance Stout
4374729f20 Update the docs for XEP-0060 publish method. 2011-10-11 20:37:50 -04:00
Lance Stout
87999333cb Fix MUC methods to optionally specify the sending JID.
Should fix issue #107
2011-10-10 11:31:03 -04:00
Lance Stout
335dc2927b Break reference cycle to fix potential memory leaks for callback handlers. 2011-10-08 17:31:30 -04:00
Lance Stout
ccbef6b696 Fix typos in the roster update method. 2011-10-07 18:13:50 -04:00
Lance Stout
3e384d3cfe XEP-0009 will likely be updated to use <base64 /> instead of <Base64 />
Both are supported when reading, but <base64 /> will be used for output.
2011-10-05 12:09:50 -04:00
Lance Stout
e33949c397 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-10-04 10:37:42 -04:00
Lance Stout
eccac859ad Fix missing import statement.
Fixes issue #105
2011-10-04 10:36:52 -04:00
Lance Stout
7dd586f2fd Merge pull request #104 from correl/develop
Make RPC events threaded
2011-10-03 13:19:16 -07:00
Correl Roush
3607c5b792 Make RPC events threaded
Allows, for example, an RPC service to make remote RPC calls with its
own connection without blocking its own thread waiting for the result.
2011-10-03 14:32:48 -04:00
Lance Stout
e37adace62 Allow SASL mechanism to be set when creating a ClientXMPP instance.
Instead of using:

    ClientXMPP(jid, password, plugin_config={
        'feature_mechanisms': {'use_mech': 'SOME-MECH'}})

You can use:

    ClientXMPP(jid, password, sasl_mech='SOME-MECH')

If you need to change the mechanism after instantiation, use:

    xmpp['feature_mechanisms'].sasl.mech = 'SCRAM-MD5'
2011-09-28 22:48:30 -04:00
Lance Stout
d10f591bf4 Expand live stream testing capabilities. 2011-09-28 17:26:29 -04:00
Lance Stout
262da78ca7 Fix del_event_handler for Python3 (different semantics for filter()).
Fixes issue #103
2011-09-23 12:03:49 -04:00
Lance Stout
0b83edf439 Fix regression for handling the case where the server terminates the stream.
The processing loop was continuing to call __read_xml after </stream>
was received, which caused SyntaxErrors (can't find starting element).

This should fix issue #102
2011-09-22 01:32:44 -04:00
Nathan Fritz
cf7fcf496e SyntaxError requires a restart 2011-09-19 11:53:09 -07:00
Lance Stout
1765271f84 Make get_node_config block by default. 2011-09-02 11:52:56 -07:00
Lance Stout
0ec79f8dc3 Tweak setup.py, and bump dev version to RC3. 2011-09-01 16:47:30 -07:00
Lance Stout
6f72c05ebf Add whitespace keepalive option.
May be disabled by setting:
    self.whitespace_keepalive = False

The keepalive interval can be adjusted using:
    self.whitespace_keepalive_interval = 300

The default interval is 5min.
2011-09-01 16:24:09 -07:00
Nathan Fritz
20cacc84ba remove ping schedule on disconnect 2011-09-01 15:51:43 -07:00
Lance Stout
24a14a0284 Mark pubsub state stanzas as non-standard. 2011-09-01 15:29:05 -07:00
Lance Stout
982c2d9b83 Add tests for pubsub error stanzas 2011-09-01 15:26:54 -07:00
Lance Stout
efa4a9b330 More stanza cleanup for pubsub. 2011-09-01 14:20:58 -07:00
Lance Stout
39ec1cff19 Some more minor cleanup. 2011-09-01 14:03:11 -07:00
Lance Stout
24c5f8d374 Clean up pubsub#event stanzas. 2011-09-01 14:01:58 -07:00
Lance Stout
d6b0158ddb Clean up pubsub#owner stanzas. 2011-09-01 13:47:55 -07:00
Lance Stout
7e5e9542e9 Add support for notify attribute when retracting an item. 2011-09-01 13:36:11 -07:00
Lance Stout
d7fc2aaa9c Add ability to get global/node default subscription options. 2011-09-01 13:25:35 -07:00
Lance Stout
8471a485d1 Clean up pubsub stanzas. 2011-09-01 13:12:26 -07:00
Lance Stout
462b375c8f Owners can modify subscriptions/affiliations. With tests.
94% coverage for the main pubsub plugin! (91% including stanzas)
2011-09-01 12:09:24 -07:00
Lance Stout
afbd506cfc Users can retrieve their affiliations now, with tests. 2011-09-01 11:30:55 -07:00
Lance Stout
ec01e45ed1 Add ability for a user to get retrieve subscriptions, with tests. 2011-09-01 11:19:25 -07:00
Lance Stout
993829b23f Add tests for pubsub subscription options. 2011-09-01 10:44:14 -07:00
Lance Stout
002257b820 Add tests for retrieving pubsub items. 2011-09-01 09:27:10 -07:00
Lance Stout
0af35c2224 Fix memory reference bugs. 2011-09-01 00:50:45 -07:00
Lance Stout
76bc0a2ba6 XEP-0060 v1.13 dictates publishing/retracting one item at a time. 2011-08-31 23:48:22 -07:00
Lance Stout
d2dc4824ee Simplify pubsub tests.
We don't really care about empty responses, so let's use block=False.
2011-08-31 21:52:17 -07:00
Lance Stout
3f9ca0366b Add test for purging a pubsub node. 2011-08-31 21:09:25 -07:00
Lance Stout
b68785e19e Retract stanzas are behaving oddly when using stanza values. 2011-08-31 16:03:32 -07:00
Lance Stout
a1bbb719e1 Test publishing multiple items, and with options. 2011-08-31 15:04:46 -07:00
Lance Stout
46f23f7348 Test publishng an item with options. 2011-08-31 14:55:37 -07:00
Lance Stout
09252baa71 Test publishing a single item. 2011-08-31 14:31:20 -07:00
Lance Stout
3623a7a16a More pubsub unit tests! 2011-08-31 14:05:29 -07:00
Lance Stout
cc504ab07c Fix pubsub get_items.
- item_ids checked for None
- pubsub node is set
2011-08-31 10:56:43 -07:00
Lance Stout
2500a0649b Fix requesting pubsub node configuration, and add tests.
- <default /> doesn't have a type attribute in the XEP
- <configure /> isn't used anymore for requesting default configuration
2011-08-31 10:43:33 -07:00
Lance Stout
5ec4e4a026 Added pubsub error stanza.
iq['error']['pubsub']['condition']
iq['error']['pubsub']['unsupported']
2011-08-31 00:42:37 -07:00
Lance Stout
c3df4dd052 Create a tox config for automating tests for different Python versions.
To use:
    sudo pip install tox
    tox
2011-08-31 00:00:12 -07:00
Lance Stout
730c3fada0 Add tests for pubsub unsubscribe. 2011-08-30 23:18:13 -07:00
Lance Stout
628978fc8c Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-30 23:11:11 -07:00
Nathan Fritz
7fb9d68714 fixed form accessors in pubsub stanzas 2011-08-30 23:10:13 -07:00
Lance Stout
e0a1c477d0 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-30 23:03:51 -07:00
Nathan Fritz
b70565720f fixed test further... but now I have an out of order problem 2011-08-30 23:03:04 -07:00
Lance Stout
33ac0c9dd6 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-30 22:45:08 -07:00
Nathan Fritz
4699bdff60 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-30 22:44:34 -07:00
Nathan Fritz
354641a3ce added publish-options element 2011-08-30 22:44:19 -07:00
Lance Stout
58a43e40c7 Get/set pubsub subscription options. 2011-08-30 22:27:21 -07:00
Lance Stout
6b7fde10d3 Test pubsub subscribe. 2011-08-30 22:27:02 -07:00
Lance Stout
13fdab0139 Test and fix XEP-0060 delete_node() 2011-08-30 21:57:11 -07:00
Lance Stout
2ce617b2ce Fix typo 2011-08-30 09:24:46 -07:00
Lance Stout
63e0496c30 Finish up all major actions in the current XEP-0060.
Still need tests and docs.
2011-08-29 23:05:14 -07:00
Lance Stout
850e3bb99b Stub out missing functionality for pubsub 2011-08-29 21:38:41 -07:00
Lance Stout
2d90deb96a The ifrom parameter doesn't need special treatment. 2011-08-26 22:06:32 -07:00
Lance Stout
3fb3f63e51 Add docs + extended Iq send arguments to pubsub methods. 2011-08-26 16:57:37 -07:00
Lance Stout
d12949ff1c Fix typos in XEP-0060, start of docs and tests. 2011-08-26 12:14:57 -07:00
Lance Stout
e3e985220e Simplify the main process loop. 2011-08-25 17:08:20 -07:00
Lance Stout
802dd8393d Make the timeout for event queue checks configurable.
Now defaults xmlstream.WAIT_TIMEOUT, and settable with
self.wait_timeout.

The new default timeout is 1sec instead of 5sec.
2011-08-25 16:45:34 -07:00
Lance Stout
fe6bc31c60 Added XMLStream.configure_dns.
This can be overridden to do custom configuration for the DNS resolver,
or any other DNS related tasks such as calling the system's res_init().
2011-08-25 16:18:26 -07:00
Lance Stout
2162d6042e Session timeout now defaults to 45sec, but can be adjusted.
e.g.

    self.session_timeout = 15

It is also managed by XMLStream instead of ClientXMPP now.
2011-08-25 15:40:13 -07:00
Lance Stout
b8a4ffece9 Handle sending stanzas in chunks if the socket has poor performance. 2011-08-25 15:08:45 -07:00
Lance Stout
d929e0deb2 Shutdown socket before closing. 2011-08-25 13:48:43 -07:00
Lance Stout
4c08c9c524 Update scheduler with locks and ability to remove tasks.
Scheduled tasks must have a unique name.
2011-08-25 13:34:30 -07:00
Lance Stout
63b8444abe Add overridable method self.configure_socket().
Allows for setting app specific socket timeouts and other socket options.
2011-08-25 00:22:26 -07:00
Lance Stout
82546d776d Fix tests in Python3. 2011-08-25 00:21:53 -07:00
Lance Stout
84f9505a8d Fix handling of DNS exceptions. 2011-08-24 22:40:57 -07:00
Lance Stout
ede59ab40e Clean and get setup.py working once and for all.
Fixes:
    README.rst now included
    Double line spacing removed from long_description
    Source package now includes tests, examples, etc using Manifest.in
    README.rst typos fixed
    Added README.rst section on installing dnspython for Python3
    Version bumped to RC2
    Version is now taken from sleekxmpp.version.__version__ without
        having to pull in the entire library
    Added 'test' command for setup.py
    Simplified testall.py
    Docs build cleanly from source package after installation
2011-08-24 22:09:02 -07:00
Lance Stout
2a80824076 Remove extra debugging code that made it into a commit. 2011-08-23 14:14:21 -07:00
Lance Stout
f92f96325a Make Iq exceptions more discoverable and simpler to use.
IqError and IqTimeout now extend XMPPError, so if you don't care
about the difference, you can use:

    try:
        self.do_something_with_iqs()
    except XMPPError:
        # Error? Timeout? I don't care!
        pass

If you do need to distinguish between timeouts and error replies,
you can still continue to use:

    try:
        self.do_somethin_with_iqs()
    except IqError as err:
        pass
    except IqTimeout:
        pass

If you don't catch any Iq errors and you're processing a stanza
then an error response will be sent, just like normal if you raise
XMPPError or any other exception, except that the error messages
will be generic to prevent leaking too much information.
2011-08-19 01:04:20 -07:00
Lance Stout
b98555c512 Update the README
Now includes how to generate the docs, run tests, and the basic
boilerplate for Sleek based projects.
2011-08-18 16:32:06 -07:00
Lance Stout
e02a42a008 Route all unhandled exceptions through XMLStream.exception.
Or through an equivalent override.
2011-08-18 16:12:51 -07:00
Lance Stout
3e51126e18 PEP8 edits 2011-08-18 02:46:48 -07:00
Lance Stout
a714fa82b2 Remove extra, unhelpful presence debug log. 2011-08-18 02:46:08 -07:00
Lance Stout
e86e6eae81 Up the timeout to 30sec instead of 10sec. 2011-08-18 01:10:25 -07:00
Lance Stout
592c25f352 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-18 01:07:21 -07:00
Lance Stout
015f662249 Update examples to work with Python3 (raw_input vs input) 2011-08-18 01:06:59 -07:00
Lance Stout
8d998d71a3 Update README (renamed to README.rst so Github will render it) 2011-08-18 01:04:59 -07:00
Nathan Fritz
f75b6bf955 added inline documentation for new dns methods 2011-08-18 01:04:01 -07:00
Nathan Fritz
fb78bf0996 fixed manual address definition 2011-08-18 00:59:27 -07:00
Lance Stout
cd7cd30b4c Fix exceptions for Python3 2011-08-18 00:47:07 -07:00
Nathan Fritz
4ea22ff69b Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-18 00:35:37 -07:00
Nathan Fritz
3853898ab3 DNS is now properly checked and different answers are tried for each reconnect until exhausted 2011-08-18 00:35:18 -07:00
Lance Stout
7d8aa4157b Add an example for dumping the roster to the command line. 2011-08-18 00:08:52 -07:00
Lance Stout
3fc20e10f5 Add some convenience methods to rosters.
Can now use len(self.client_roster) to get the number of JIDs in
the roster, and self.client_roster.groups() to get a dict of
groups and the JIDs in those groups.
2011-08-18 00:07:37 -07:00
Lance Stout
004eabf809 Update plugins that use Iq stanzas to work with new exceptions. 2011-08-17 21:30:47 -07:00
Lance Stout
62230fc970 Return '' instead of None from form fields with no values. 2011-08-17 21:22:03 -07:00
Lance Stout
961668d420 Add guide for sending a message and then disconnecting. 2011-08-17 21:21:37 -07:00
Lance Stout
01061a0355 More documentation!
Finished the echo bot quickstart.

Added placeholders for other guides we need.
2011-08-13 20:58:53 -07:00
Lance Stout
9fdd85d9f1 I've seen people complain about Sleek taking so long to disconnect.
Added logging to say that we're waiting for the server to end the stream
from its end.
2011-08-13 08:58:07 -07:00
Lance Stout
331db30f8f Add form.field back in for backwards compatibility. 2011-08-13 08:34:23 -07:00
Lance Stout
017d7ec62b Add tests for setting a form's type to 'submit' or 'cancel'.
Form fields now remember their current type if the type is deleted. This
allows for fields to properly format their values if set after the form
has been changed to the 'submit' type.
2011-08-13 01:28:18 -07:00
Lance Stout
76826b5495 The todo1.0 list isn't needed any longer :)
The last few plugins that were in the list will be cleaned up in 1.1
or 1.2 - XEP-0012, XEP-0009, XEP-0033, XEP-0045, and gmail_notify.
2011-08-13 00:16:36 -07:00
Lance Stout
de315ff6d8 Fix typo. 2011-08-13 00:16:25 -07:00
Lance Stout
c26b716164 Update XEP-0050 to use new IQ exceptions.
IqError is now caught and forwarded to the command error handler referenced
in the session.

Errors are now caught and processed by the session's error handler
whether or not the results Iq stanza includes the <command> substanza.

Added the option for blocking command calls. The blocking option is set
during start_command with block=True. Subsequent command flow methods use
session['block'] to determine their blocking behaviour.

If you use blocking commands, then you will need to wrap your command calls
in a try/except block for IqTimeout exceptions.
2011-08-13 00:10:06 -07:00
Lance Stout
dcaddb8042 Include new XEP-0004 directories in setup.py 2011-08-12 23:56:14 -07:00
Lance Stout
5ef197e5fd Start of docs for 1.0 2011-08-12 17:33:32 -07:00
Lance Stout
52ed02bd06 Update .gitignore 2011-08-12 17:22:27 -07:00
Lance Stout
bd427849fb Reduce the maximum delay between connection retries to 10min. 2011-08-12 17:17:05 -07:00
Lance Stout
127d7acb91 Missing commas in setup.py 2011-08-12 16:53:08 -07:00
Lance Stout
484efff156 Merge branch 'develop' into roster
Conflicts:
	setup.py
	sleekxmpp/clientxmpp.py
2011-08-12 16:47:58 -07:00
Nathan Fritz
8f1d0e7a79 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-12 16:36:03 -07:00
Nathan Fritz
88184ff955 fixed indenting and merged in exceptions branch 2011-08-12 16:35:36 -07:00
Nathan Fritz
bd8c110f00 Merge branch 'exceptions' into develop 2011-08-12 16:35:15 -07:00
Nathan Fritz
0050c51124 updated pubsub plugin to use stanzas 2011-08-12 16:32:09 -07:00
Lance Stout
9b7ed73f95 Reorganize XEP-0004.
Changes:
    May now use underscored method names
    form.field is replaced by form['fields']
    form.get_fields no longer accepts use_dict parameter, it always
        returns an OrderedDict now
    form.set_fields will accept either an OrderedDict, or a list
        of (var, dict) tuples as before.
    Setting the form type to 'submit' will remove extra meta data
        from the form fields, leaving just the 'var' and 'value'
    Setting the form type to 'cancel' will remove all fields.
2011-08-11 21:59:55 -07:00
Nathan Fritz
a189cb8333 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2011-08-10 13:37:49 -07:00
Nathan Fritz
0d4825d3ea added send_client example 2011-08-10 13:37:36 -07:00
Lance Stout
156b3200e3 Don't include ping stanza in the ping result. 2011-08-10 09:05:43 -07:00
Lance Stout
572becad44 Enable forcing a specififc SASL mech:
xmpp = ClientXMPP(jid, password, {
    'feature_mechanisms': {'use_mech':'PLAIN'}})
2011-08-09 00:51:49 -07:00
Lance Stout
75f23d1130 Fix XEP-0078 using the new stream feature workflow.
Honestly, this is mainly just a demo/proof of concept that we
can handle dependencies and ordering issues with stream features.

DON'T use XEP-0078 if you are able to use the normal SASL method,
which should be the case unless you are dealing with a very old
XMPP server implementation.
2011-08-06 12:30:56 -07:00
Lance Stout
e83fae3a6f Save the stream ID when the stream starts. 2011-08-06 00:44:32 -07:00
Lance Stout
5be5b8c02b If no config for a plugin is given, try using self.plugin_config.
Sleek loads a few plugins by default, which made it difficult to
configure or even disable them.

Now, if a plugin is registered without any configuration, then
sleek will try finding a configuration in self.plugin_config.
2011-08-06 00:41:14 -07:00
Lance Stout
6c4cb2bf00 Merge branch 'master' into develop
Adds hotfix for ANONYMOUS mech support.

Conflicts:
	sleekxmpp/__init__.py
2011-08-05 14:08:32 -07:00
Lance Stout
148a23579c Hotfix for ANONYMOUS mech support.
Updates version to 1.0-Beta6.1
2011-08-05 14:06:58 -07:00
Lance Stout
ea95811c4c The next release will be 1.0 RC1 2011-08-05 09:01:50 -07:00
Lance Stout
08cb5f42e7 Update the info in setup.py
I thought I had done this a long time ago, but it must have been in a
lost branch. *shrug*

It's too late for Beta6, so I've manually updated the PyPI entry.
2011-08-05 09:00:55 -07:00
Lance Stout
9abf37bbd1 Ignore Manifest and dist dir in git. 2011-08-05 09:00:42 -07:00
Lance Stout
89cffd43f4 Merge branch 'develop' into roster
Conflicts:
	setup.py
2011-08-04 11:52:17 -07:00
Lance Stout
d7fe724145 Merge branch 'develop' into exceptions 2011-07-27 19:36:04 -07:00
Lance Stout
ad978700fc Merge branch 'develop' into roster 2011-07-27 19:35:42 -07:00
Lance Stout
20df6348a4 Merge branch 'develop' into exceptions 2011-07-03 00:39:14 -07:00
Lance Stout
48fb7006f7 Merge branch 'develop' into roster 2011-07-03 00:39:02 -07:00
Lance Stout
7057984831 Merge branch 'develop' into roster 2011-07-01 15:19:05 -07:00
Lance Stout
847510c6b5 Merge branch 'develop' into exceptions 2011-06-20 16:27:39 -07:00
Lance Stout
774e0f2022 Merge branch 'develop' into roster 2011-06-20 16:27:25 -07:00
Lance Stout
d1e12cd46f Need to store unavailable presence as last sent if broadcasted. 2011-06-18 14:39:17 -07:00
Lance Stout
adf6d49fd1 Store unavailable presence as last sent presence. 2011-06-18 14:36:19 -07:00
Lance Stout
0826a44d4b Added roster package to setup.py 2011-06-18 14:32:09 -07:00
Lance Stout
ce145b04ac Integrate roster with ClientXMPP.
Roster updates are now passed through to the roster when using
self.update_roster, etc.
2011-06-16 16:09:15 -07:00
Lance Stout
29d775e675 Integrate roster with BaseXMPP.
Last sent stanzas are saved regardless of if the roster is used
directly or self.send_presence
2011-06-16 16:03:31 -07:00
Lance Stout
251a47db8c Split roster.py into a directory. 2011-06-16 14:15:22 -07:00
Lance Stout
e4b3a191d6 Merge branch 'develop' into roster
Conflicts:
	sleekxmpp/basexmpp.py
2011-06-15 10:57:25 -07:00
Lance Stout
393d702e77 Merge branch 'develop' into exceptions 2011-06-15 10:56:49 -07:00
Lance Stout
a3597d6deb Merge branch 'develop' into roster
Conflicts:
	sleekxmpp/basexmpp.py
2011-06-14 14:24:25 -07:00
Lance Stout
8fada4d015 Merge branch 'develop' into exceptions 2011-06-14 14:18:40 -07:00
Lance Stout
6d59f55fd4 Merge branch 'develop' into exceptions 2011-06-10 15:15:01 -07:00
Lance Stout
937dce8e65 Merge branch 'develop' into roster 2011-06-10 15:14:37 -07:00
Lance Stout
5c1562f36b Merge branch 'develop' into exceptions 2011-06-08 10:02:38 -07:00
Lance Stout
8eb59072b4 Merge branch 'develop' into roster 2011-06-08 10:01:52 -07:00
Lance Stout
20d053807d IqTimeout now references the original sent stanza.
A little extra bit of docs for IqError.
2011-06-01 15:28:33 -07:00
Lance Stout
8aa4396e44 Begin experimental use of exceptions.
Provides IqTimeout and IqError which are raised when an Iq response
does not arrive in time, or it arrives with type='error'.
2011-06-01 15:17:22 -07:00
Lance Stout
788a5b73f9 Merge branch 'develop' into roster 2011-06-01 15:17:04 -07:00
Lance Stout
5ed27bf5f6 Merge branch 'develop' into roster 2011-05-31 10:59:14 -07:00
Lance Stout
62bdaab7c7 Merge branch 'develop' into roster 2011-05-25 15:53:24 -07:00
Lance Stout
bb2bc64d15 Merge branch 'develop' into roster 2011-05-20 21:40:37 -04:00
Lance Stout
baa1eaf73a Fix test for Python3.
Issue of dict_keys vs list data types.
2011-05-20 21:36:09 -04:00
Lance Stout
4c7da3899e Merge branch 'develop' into roster
Conflicts:
	tests/test_stream_roster.py
2011-05-20 21:26:45 -04:00
Lance Stout
4d3593ac86 Merge branch 'develop' into roster
Conflicts:
	tests/test_stream_roster.py
2011-05-20 21:12:53 -04:00
Lance Stout
c49a8e9114 Save progress 2011-05-20 17:42:40 -04:00
Lance Stout
d3bd9cd31d Merge branch 'develop' into roster 2011-05-20 13:46:36 -04:00
Lance Stout
e3b14bc5a9 Merge branch 'develop' into roster
Conflicts:
	sleekxmpp/clientxmpp.py
	tests/test_stream_roster.py
2011-05-20 13:23:48 -04:00
Lance Stout
8e46aa7054 Merge branch 'develop' into roster 2011-04-26 16:33:32 -04:00
Nathan Fritz
8a22597180 added has_jid to roster 2011-04-15 17:43:12 -07:00
Nathan Fritz
e919906c8c Pubsub/Unsubscribe was not getting registered 2011-04-14 17:34:33 -07:00
Nathan Fritz
46dc6eac88 remove roster item state responsibility from clients 2011-04-14 16:27:27 -07:00
Lance Stout
b9bf30e095 Merge branch 'develop' into roster 2011-04-11 14:23:39 -04:00
Lance Stout
b60c51ef13 Merge branch 'develop' into roster 2011-04-08 16:52:20 -04:00
Lance Stout
6b05938573 Merge branch 'develop' into roster 2011-04-08 16:41:45 -04:00
Lance Stout
77601f7262 Merge branch 'develop' into roster 2011-03-24 13:15:00 -04:00
Lance Stout
d9be51b2ef Merge branch 'develop' into roster 2011-03-24 09:36:26 -04:00
Lance Stout
393259c24b Merge branch 'develop' into roster 2011-03-23 10:01:10 -04:00
Lance Stout
756c4c032f Merge branch 'develop' into roster 2011-03-22 20:48:09 -04:00
Lance Stout
e1360ae049 Merge branch 'develop' into roster 2011-03-22 12:00:01 -04:00
Lance Stout
b048f8d733 Merge branch 'develop' into roster 2011-03-18 17:36:35 -04:00
Lance Stout
f65f88325b Merge branch 'develop' into roster 2011-03-18 15:51:27 -04:00
Lance Stout
42c8f6ae87 Merge branch 'develop' into roster 2011-02-24 16:19:45 -05:00
Lance Stout
e4f3b777f9 Reset the roster on disconnect instead of replacing it. 2011-02-14 16:24:49 -05:00
Lance Stout
a278f79bdb Merge branch 'develop' into roster
Conflicts:
	sleekxmpp/clientxmpp.py
2011-02-14 16:18:44 -05:00
Lance Stout
606c369173 Some more roster tweaks. 2011-02-08 19:15:50 -05:00
Lance Stout
3c871920b1 Make the roster backend settable. 2011-02-02 12:05:34 -05:00
Lance Stout
de6170a13d Merge branch 'develop' into roster
Conflicts:
	sleekxmpp/basexmpp.py
2011-02-02 09:13:22 -05:00
Lance Stout
65931bb384 Merge branch 'develop' into roster 2011-01-13 22:16:46 -05:00
Lance Stout
a5d53b3349 Fix method call error. 2011-01-10 16:33:30 -05:00
Lance Stout
4487a90623 Add self.client_roster to make things simpler for clients. 2011-01-10 16:28:49 -05:00
Lance Stout
05da8cc3d1 Merge branch 'develop' into roster 2011-01-10 16:27:18 -05:00
Lance Stout
23e499998f Merge branch 'develop' into roster 2011-01-09 10:04:09 -05:00
Lance Stout
c156a4f723 Merge branch 'develop' into roster 2011-01-05 16:53:33 -05:00
Lance Stout
3657bf6636 Merge branch 'develop' into roster 2010-12-21 11:33:40 -05:00
Lance Stout
adade2e5ec Merge branch 'develop' into roster 2010-12-16 22:03:56 -05:00
Lance Stout
c16913c999 Merge branch 'develop' into roster
Conflicts:
	sleekxmpp/basexmpp.py
2010-12-13 14:36:53 -05:00
Lance Stout
12b61365ad Merge branch 'develop' of github.com:fritzy/SleekXMPP into roster 2010-11-18 01:18:06 -05:00
Lance Stout
9214dc6610 Add rename_node method to disco plugin. 2010-11-18 01:12:11 -05:00
Lance Stout
58b95e4ae4 Merge branch 'develop' of github.com:fritzy/SleekXMPP into roster 2010-11-18 00:44:51 -05:00
Lance Stout
debf909359 Merge branch 'develop' into roster 2010-11-17 14:33:09 -05:00
Lance Stout
0d4d84b2fa Cleaned basexmpp.py 2010-11-17 10:13:45 -05:00
Lance Stout
d2aca3e7e0 Remove extraneous files. 2010-11-17 02:04:36 -05:00
Lance Stout
26aca2b789 Merge branch 'roster' of github.com:fritzy/SleekXMPP into roster
Conflicts:
	sleekxmpp/basexmpp.py
	sleekxmpp/roster.py
	sleekxmpp/test/sleektest.py
	tests/test_stream_presence.py
	tests/test_stream_roster.py
2010-11-17 02:01:12 -05:00
Lance Stout
5424ede413 More cleanup. 2010-11-17 01:54:30 -05:00
Lance Stout
20112f8e16 More docs! 2010-11-17 01:49:51 -05:00
Lance Stout
4260a754e5 Added more docs. 2010-11-17 01:49:51 -05:00
Lance Stout
ce30f72738 Added docs for main Roster class. 2010-11-17 01:49:51 -05:00
Lance Stout
69d430dd75 Cleaned up names. 2010-11-17 01:49:51 -05:00
Lance Stout
673545c7e4 First pass at integrating the new roster manager. 2010-11-17 01:49:19 -05:00
Lance Stout
4f69a03bb1 More cleanup. 2010-10-27 15:02:21 -04:00
Lance Stout
c2c18acd6a More docs! 2010-10-27 13:36:23 -04:00
Lance Stout
12ead36f96 Added more docs. 2010-10-27 10:51:58 -04:00
Lance Stout
41a642e06c Added docs for main Roster class. 2010-10-27 09:27:00 -04:00
Lance Stout
c6ed4b8a1d Cleaned up names. 2010-10-27 08:09:50 -04:00
Lance Stout
65aa6573df First pass at integrating the new roster manager. 2010-10-26 23:47:17 -04:00
600 changed files with 46406 additions and 15785 deletions

15
.gitignore vendored
View File

@@ -1,2 +1,15 @@
*.pyc
*.py[co]
build/
dist/
MANIFEST
docs/_build/
*.swp
.tox/
.coverage
slixmpp.egg-info/
.ropeproject/
4913
*~
.baboon/
.DS_STORE
.idea/

10
.travis.yml Normal file
View File

@@ -0,0 +1,10 @@
language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
install:
- "pip install ."
script: testall.py

14
CONTRIBUTING.rst Normal file
View File

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

View File

@@ -1,5 +1,6 @@
Pre-requisites:
- Python 3.1 or 2.6
- Python 3.4
- Cython 0.22 and libidn, optionally (making JID faster by compiling the stringprep module)
Install:
> python3 setup.py install
@@ -9,4 +10,4 @@ Root install:
To test:
> cd examples
> python echo_client.py -v -j [USER@example.com] -p [PASSWORD]
> python3 echo_client.py -d -j [USER@example.com] -p [PASSWORD]

64
LICENSE
View File

@@ -21,8 +21,8 @@ THE SOFTWARE.
Licences of Bundled Third Pary Code
-----------------------------------
Licenses of Bundled Third Party Code
------------------------------------
dateutil - Extensions to the standard python 2.3+ datetime module.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -69,8 +69,8 @@ modification, are permitted provided that the following conditions are met:
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Red Innovation nor the names of its contributors
may be used to endorse or promote products derived from this software
* Neither the name of Red Innovation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY RED INNOVATION ``AS IS'' AND ANY
@@ -119,7 +119,7 @@ SUELTA A PURE-PYTHON SASL CLIENT LIBRARY
This software is subject to "The MIT License"
Copyright 2007-2010 David Alan Cridland
Copyright 2004-2013 David Alan Cridland
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -138,3 +138,57 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
python-gnupg: A Python wrapper for the GNU Privacy Guard
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright (c) 2008-2012 by Vinay Sajip.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name(s) of the copyright holder(s) may not be used to endorse or
promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
socksipy: A Python SOCKS client module.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright 2006 Dan-Haim. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of Dan Haim nor the names of his contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.

7
MANIFEST.in Normal file
View File

@@ -0,0 +1,7 @@
include README.rst
include LICENSE
include run_tests.py
include slixmpp/stringprep.pyx
recursive-include docs Makefile *.bat *.py *.rst *.css *.ttf *.png
recursive-include examples *.py
recursive-include tests *.py

50
README
View File

@@ -1,50 +0,0 @@
SleekXMPP is an XMPP library written for Python 3.1+ (with 2.6 compatibility).
Hosted at http://wiki.github.com/fritzy/SleekXMPP/
Featured in examples in XMPP: The Definitive Guide by Kevin Smith, Remko Tronçon, and Peter Saint-Andre
If you're coming here from The Definitive Guide, please read http://wiki.github.com/fritzy/SleekXMPP/xmpp-the-definitive-guide
Requirements:
We try to keep requirements to a minimum, but we suggest that you install http://dnspython.org although it isn't strictly required.
If you do not install this library, you may need to specify the server/port for services that use SRV records (like GTalk).
"sudo pip install dnspython" on a *nix system with pip installed.
SleekXMPP has several design goals/philosophies:
- Low number of dependencies.
- Every XEP as a plugin.
- Rewarding to work with.
The goals for 1.0 include (and we're getting close):
- Nearly Full test coverage of stanzas.
- Wide range of functional tests.
- Stanza objects for all interaction with the stream
- Documentation on using and extending SleekXMPP.
- Complete documentation on all implemented stanza objects
- Documentation on all examples used in XMPP: The Definitive Guide
1.1 will include:
- More functional and unit tests
- PEP-8 compliance
- XEP-225 support
Since 0.2, here's the Changelog:
- MANY bugfixes
- Re-implementation of handlers/threading to greatly simplify and remove bugs (no more spawning threads in handlers)
- Stanza objects for jabber:client and all implemented XEPs
- Raising XMPPError for jabber:client and extended errors in handlers
- Robust error handling and better insurance of iq responses
- Stanza objects have made life a lot easier!
- Massive audit/cleanup.
Credits
----------------
Main Author: Nathan Fritz fritz@netflint.net
Contributors: Kevin Smith & Lance Stout
Patches: Remko Tronçon
Dave Cridland, for his Suelta SASL library.
Feel free to add fritzy@netflint.net to your roster for direct support and comments.
Join sleekxmpp-discussion@googlegroups.com / http://groups.google.com/group/sleekxmpp-discussion for email discussion.
Join sleek@conference.jabber.org for groupchat discussion.

139
README.rst Normal file
View File

@@ -0,0 +1,139 @@
Slixmpp
#########
Slixmpp is an MIT licensed XMPP library for Python 3.4+. It is a fork of
SleekXMPP.
Slixmpp's goals is to only rewrite the core of the library (the low level
socket handling, the timers, the events dispatching) in order to remove all
threads.
Building
--------
Slixmpp can make use of cython to improve performance on critical modules.
To do that, **cython3** is necessary along with **libidn** headers.
Otherwise, no compilation is needed. Building is done by running setup.py::
python3 setup.py build_ext --inplace
Documentation and Testing
-------------------------
Documentation can be found both inline in the code, and as a Sphinx project in ``/docs``.
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 Slixmpp::
python run_tests.py
The Slixmpp Boilerplate
-------------------------
Projects using Slixmpp tend to follow a basic pattern for setting up client/component
connections and configuration. Here is the gist of the boilerplate needed for a Slixmpp
based project. See the documetation or examples directory for more detailed archetypes for
Slixmpp projects::
import logging
from slixmpp import ClientXMPP
from slixmpp.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('somejid@example.com', 'use_getpass')
xmpp.connect()
xmpp.process(forever=True)
Slixmpp Credits
---------------
**Maintainers:**
- Florent Le Coz (`louiz@louiz.org <xmpp:louiz@louiz.org?message>`_),
- Mathieu Pasquet (`mathieui@mathieui.net <xmpp:mathieui@mathieui.net?message>`_),
**Contributors:**
- Emmanuel Gil Peyrot (`Link mauve <xmpp:linkmauve@linkmauve.fr?message>`_)
- 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)
-------------------
**Main Author:** Nathan Fritz
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
`@fritzy <http://twitter.com/fritzy>`_
Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP
<http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of
the XMPP Council.
**Co-Author:** Lance Stout
`lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,
`@lancestout <http://twitter.com/lancestout>`_
**Contributors:**
- Brian Beggs (`macdiesel <http://github.com/macdiesel>`_)
- Dann Martens (`dannmartens <http://github.com/dannmartens>`_)
- Florent Le Coz (`louiz <http://github.com/louiz>`_)
- Kevin Smith (`Kev <http://github.com/Kev>`_, http://kismith.co.uk)
- Remko Tronçon (`remko <http://github.com/remko>`_, http://el-tramo.be)
- Te-jé Rogers (`te-je <http://github.com/te-je>`_)
- Thom Nichols (`tomstrummer <http://github.com/tomstrummer>`_)

View File

@@ -1,171 +0,0 @@
import logging
import sleekxmpp
from optparse import OptionParser
from xml.etree import cElementTree as ET
import os
import time
import sys
import unittest
import sleekxmpp.plugins.xep_0004
from sleekxmpp.xmlstream.matcher.stanzapath import StanzaPath
from sleekxmpp.xmlstream.handler.waiter import Waiter
try:
import configparser
except ImportError:
import ConfigParser as configparser
try:
import queue
except ImportError:
import Queue as queue
class TestClient(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.waitforstart = queue.Queue()
def start(self, event):
self.getRoster()
self.sendPresence()
self.waitforstart.put(True)
class TestPubsubServer(unittest.TestCase):
statev = {}
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
def setUp(self):
pass
def test001getdefaultconfig(self):
"""Get the default node config"""
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode2')
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode3')
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode4')
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode5')
result = self.xmpp1['xep_0060'].getNodeConfig(self.pshost)
self.statev['defaultconfig'] = result
self.failUnless(isinstance(result, sleekxmpp.plugins.xep_0004.Form))
def test002createdefaultnode(self):
"""Create a node without config"""
self.failUnless(self.xmpp1['xep_0060'].create_node(self.pshost, 'testnode1'))
def test003deletenode(self):
"""Delete recently created node"""
self.failUnless(self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode1'))
def test004createnode(self):
"""Create a node with a config"""
self.statev['defaultconfig'].field['pubsub#access_model'].setValue('open')
self.statev['defaultconfig'].field['pubsub#notify_retract'].setValue(True)
self.statev['defaultconfig'].field['pubsub#persist_items'].setValue(True)
self.statev['defaultconfig'].field['pubsub#presence_based_delivery'].setValue(True)
p = self.xmpp2.Presence()
p['to'] = self.pshost
p.send()
self.failUnless(self.xmpp1['xep_0060'].create_node(self.pshost, 'testnode2', self.statev['defaultconfig'], ntype='job'))
def test005reconfigure(self):
"""Retrieving node config and reconfiguring"""
nconfig = self.xmpp1['xep_0060'].getNodeConfig(self.pshost, 'testnode2')
self.failUnless(nconfig, "No configuration returned")
#print("\n%s ==\n %s" % (nconfig.getValues(), self.statev['defaultconfig'].getValues()))
self.failUnless(nconfig.getValues() == self.statev['defaultconfig'].getValues(), "Configuration does not match")
self.failUnless(self.xmpp1['xep_0060'].setNodeConfig(self.pshost, 'testnode2', nconfig))
def test006subscribetonode(self):
"""Subscribe to node from account 2"""
self.failUnless(self.xmpp2['xep_0060'].subscribe(self.pshost, "testnode2"))
def test007publishitem(self):
"""Publishing item"""
item = ET.Element('{http://netflint.net/protocol/test}test')
w = Waiter('wait publish', StanzaPath('message/pubsub_event/items'))
self.xmpp2.registerHandler(w)
#result = self.xmpp1['xep_0060'].setItem(self.pshost, "testnode2", (('test1', item),))
result = self.xmpp1['jobs'].createJob(self.pshost, "testnode2", 'test1', item)
msg = w.wait(5) # got to get a result in 5 seconds
self.failUnless(msg != False, "Account #2 did not get message event")
#result = self.xmpp1['xep_0060'].setItem(self.pshost, "testnode2", (('test2', item),))
result = self.xmpp1['jobs'].createJob(self.pshost, "testnode2", 'test2', item)
w = Waiter('wait publish2', StanzaPath('message/pubsub_event/items'))
self.xmpp2.registerHandler(w)
self.xmpp2['jobs'].claimJob(self.pshost, 'testnode2', 'test1')
msg = w.wait(5) # got to get a result in 5 seconds
self.xmpp2['jobs'].claimJob(self.pshost, 'testnode2', 'test2')
self.xmpp2['jobs'].finishJob(self.pshost, 'testnode2', 'test1')
self.xmpp2['jobs'].finishJob(self.pshost, 'testnode2', 'test2')
print result
#need to add check for update
def test900cleanup(self):
"Cleaning up"
#self.failUnless(self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode2'), "Could not delete test node.")
time.sleep(10)
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")
optp.add_option("-n","--nodenum", dest="nodenum", default="1", help="set node number to use")
optp.add_option("-p","--pubsub", dest="pubsub", default="1", help="set pubsub host to use")
opts,args = optp.parse_args()
logging.basicConfig(level=opts.loglevel, format='%(levelname)-8s %(message)s')
#load xml config
logging.info("Loading config file: %s" % opts.configfile)
config = configparser.RawConfigParser()
config.read(opts.configfile)
#init
logging.info("Account 1 is %s" % config.get('account1', 'jid'))
xmpp1 = TestClient(config.get('account1','jid'), config.get('account1','pass'))
logging.info("Account 2 is %s" % config.get('account2', 'jid'))
xmpp2 = TestClient(config.get('account2','jid'), config.get('account2','pass'))
xmpp1.registerPlugin('xep_0004')
xmpp1.registerPlugin('xep_0030')
xmpp1.registerPlugin('xep_0060')
xmpp1.registerPlugin('xep_0199')
xmpp1.registerPlugin('jobs')
xmpp2.registerPlugin('xep_0004')
xmpp2.registerPlugin('xep_0030')
xmpp2.registerPlugin('xep_0060')
xmpp2.registerPlugin('xep_0199')
xmpp2.registerPlugin('jobs')
if not config.get('account1', 'server'):
# we don't know the server, but the lib can probably figure it out
xmpp1.connect()
else:
xmpp1.connect((config.get('account1', 'server'), 5222))
xmpp1.process(threaded=True)
#init
if not config.get('account2', 'server'):
# we don't know the server, but the lib can probably figure it out
xmpp2.connect()
else:
xmpp2.connect((config.get('account2', 'server'), 5222))
xmpp2.process(threaded=True)
TestPubsubServer.xmpp1 = xmpp1
TestPubsubServer.xmpp2 = xmpp2
TestPubsubServer.pshost = config.get('settings', 'pubsub')
xmpp1.waitforstart.get(True)
xmpp2.waitforstart.get(True)
testsuite = unittest.TestLoader().loadTestsFromTestCase(TestPubsubServer)
alltests_suite = unittest.TestSuite([testsuite])
result = unittest.TextTestRunner(verbosity=2).run(alltests_suite)
xmpp1.disconnect()
xmpp2.disconnect()

View File

@@ -1,233 +0,0 @@
import logging
import sleekxmpp
from optparse import OptionParser
from xml.etree import cElementTree as ET
import os
import time
import sys
import unittest
import sleekxmpp.plugins.xep_0004
from sleekxmpp.xmlstream.matcher.stanzapath import StanzaPath
from sleekxmpp.xmlstream.handler.waiter import Waiter
try:
import configparser
except ImportError:
import ConfigParser as configparser
try:
import queue
except ImportError:
import Queue as queue
class TestClient(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.waitforstart = queue.Queue()
def start(self, event):
self.getRoster()
self.sendPresence()
self.waitforstart.put(True)
class TestPubsubServer(unittest.TestCase):
statev = {}
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
def setUp(self):
pass
def test001getdefaultconfig(self):
"""Get the default node config"""
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode2')
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode3')
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode4')
self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode5')
result = self.xmpp1['xep_0060'].getNodeConfig(self.pshost)
self.statev['defaultconfig'] = result
self.failUnless(isinstance(result, sleekxmpp.plugins.xep_0004.Form))
def test002createdefaultnode(self):
"""Create a node without config"""
self.failUnless(self.xmpp1['xep_0060'].create_node(self.pshost, 'testnode1'))
def test003deletenode(self):
"""Delete recently created node"""
self.failUnless(self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode1'))
def test004createnode(self):
"""Create a node with a config"""
self.statev['defaultconfig'].field['pubsub#access_model'].setValue('open')
self.statev['defaultconfig'].field['pubsub#notify_retract'].setValue(True)
self.failUnless(self.xmpp1['xep_0060'].create_node(self.pshost, 'testnode2', self.statev['defaultconfig']))
def test005reconfigure(self):
"""Retrieving node config and reconfiguring"""
nconfig = self.xmpp1['xep_0060'].getNodeConfig(self.pshost, 'testnode2')
self.failUnless(nconfig, "No configuration returned")
#print("\n%s ==\n %s" % (nconfig.getValues(), self.statev['defaultconfig'].getValues()))
self.failUnless(nconfig.getValues() == self.statev['defaultconfig'].getValues(), "Configuration does not match")
self.failUnless(self.xmpp1['xep_0060'].setNodeConfig(self.pshost, 'testnode2', nconfig))
def test006subscribetonode(self):
"""Subscribe to node from account 2"""
self.failUnless(self.xmpp2['xep_0060'].subscribe(self.pshost, "testnode2"))
def test007publishitem(self):
"""Publishing item"""
item = ET.Element('{http://netflint.net/protocol/test}test')
w = Waiter('wait publish', StanzaPath('message/pubsub_event/items'))
self.xmpp2.registerHandler(w)
result = self.xmpp1['xep_0060'].setItem(self.pshost, "testnode2", (('test1', item),))
msg = w.wait(5) # got to get a result in 5 seconds
self.failUnless(msg != False, "Account #2 did not get message event")
self.failUnless(result)
#need to add check for update
def test008updateitem(self):
"""Updating item"""
item = ET.Element('{http://netflint.net/protocol/test}test', {'someattr': 'hi there'})
w = Waiter('wait publish', StanzaPath('message/pubsub_event/items'))
self.xmpp2.registerHandler(w)
result = self.xmpp1['xep_0060'].setItem(self.pshost, "testnode2", (('test1', item),))
msg = w.wait(5) # got to get a result in 5 seconds
self.failUnless(msg != False, "Account #2 did not get message event")
self.failUnless(result)
#need to add check for update
def test009deleteitem(self):
"""Deleting item"""
w = Waiter('wait retract', StanzaPath('message/pubsub_event/items@node=testnode2'))
self.xmpp2.registerHandler(w)
result = self.xmpp1['xep_0060'].deleteItem(self.pshost, "testnode2", "test1")
self.failUnless(result, "Got error when deleting item.")
msg = w.wait(1)
self.failUnless(msg != False, "Did not get retract notice.")
def test010unsubscribenode(self):
"Unsubscribing Account #2"
self.failUnless(self.xmpp2['xep_0060'].unsubscribe(self.pshost, "testnode2"), "Got error response when unsubscribing.")
def test011createcollectionnode(self):
"Create a collection node w/ Account #2"
self.failUnless(self.xmpp2['xep_0060'].create_node(self.pshost, "testnode3", self.statev['defaultconfig'], True), "Could not create collection node")
def test012subscribecollection(self):
"Subscribe Account #1 to collection"
self.failUnless(self.xmpp1['xep_0060'].subscribe(self.pshost, "testnode3"))
def test013assignnodetocollection(self):
"Assign node to collection"
self.failUnless(self.xmpp2['xep_0060'].addNodeToCollection(self.pshost, 'testnode2', 'testnode3'))
def test014publishcollection(self):
"""Publishing item to collection child"""
item = ET.Element('{http://netflint.net/protocol/test}test')
w = Waiter('wait publish2', StanzaPath('message/pubsub_event/items@node=testnode2'))
self.xmpp1.registerHandler(w)
result = self.xmpp2['xep_0060'].setItem(self.pshost, "testnode2", (('test2', item),))
msg = w.wait(5) # got to get a result in 5 seconds
self.failUnless(msg != False, "Account #1 did not get message event: perhaps node was advertised incorrectly?")
self.failUnless(result)
# def test016speedtest(self):
# "Uncached speed test"
# import time
# start = time.time()
# for y in range(0, 50000, 1000):
# start2 = time.time()
# for x in range(y, y+1000):
# self.failUnless(self.xmpp1['xep_0060'].subscribe(self.pshost, "testnode4", subscribee="testuser%s@whatever" % x))
# print time.time() - start2
# seconds = time.time() - start
# print "--", seconds
# print "---------"
# time.sleep(15)
# self.failUnless(self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode4'), "Could not delete non-cached test node")
# def test015speedtest(self):
# "cached speed test"
# result = self.xmpp1['xep_0060'].getNodeConfig(self.pshost)
# self.statev['defaultconfig'] = result
# self.statev['defaultconfig'].field['pubsub#node_type'].setValue("leaf")
# self.statev['defaultconfig'].field['sleek#saveonchange'].setValue(True)
# self.failUnless(self.xmpp1['xep_0060'].create_node(self.pshost, 'testnode4', self.statev['defaultconfig']))
# self.statev['defaultconfig'].field['sleek#saveonchange'].setValue(False)
# self.failUnless(self.xmpp1['xep_0060'].create_node(self.pshost, 'testnode5', self.statev['defaultconfig']))
# start = time.time()
# for y in range(0, 50000, 1000):
# start2 = time.time()
# for x in range(y, y+1000):
# self.failUnless(self.xmpp1['xep_0060'].subscribe(self.pshost, "testnode5", subscribee="testuser%s@whatever" % x))
# print time.time() - start2
# seconds = time.time() - start
# print "--", seconds
def test900cleanup(self):
"Cleaning up"
self.failUnless(self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode2'), "Could not delete test node.")
self.failUnless(self.xmpp1['xep_0060'].deleteNode(self.pshost, 'testnode3'), "Could not delete collection node")
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")
optp.add_option("-n","--nodenum", dest="nodenum", default="1", help="set node number to use")
optp.add_option("-p","--pubsub", dest="pubsub", default="1", help="set pubsub host to use")
opts,args = optp.parse_args()
logging.basicConfig(level=opts.loglevel, format='%(levelname)-8s %(message)s')
#load xml config
logging.info("Loading config file: %s" % opts.configfile)
config = configparser.RawConfigParser()
config.read(opts.configfile)
#init
logging.info("Account 1 is %s" % config.get('account1', 'jid'))
xmpp1 = TestClient(config.get('account1','jid'), config.get('account1','pass'))
logging.info("Account 2 is %s" % config.get('account2', 'jid'))
xmpp2 = TestClient(config.get('account2','jid'), config.get('account2','pass'))
xmpp1.registerPlugin('xep_0004')
xmpp1.registerPlugin('xep_0030')
xmpp1.registerPlugin('xep_0060')
xmpp1.registerPlugin('xep_0199')
xmpp2.registerPlugin('xep_0004')
xmpp2.registerPlugin('xep_0030')
xmpp2.registerPlugin('xep_0060')
xmpp2.registerPlugin('xep_0199')
if not config.get('account1', 'server'):
# we don't know the server, but the lib can probably figure it out
xmpp1.connect()
else:
xmpp1.connect((config.get('account1', 'server'), 5222))
xmpp1.process(threaded=True)
#init
if not config.get('account2', 'server'):
# we don't know the server, but the lib can probably figure it out
xmpp2.connect()
else:
xmpp2.connect((config.get('account2', 'server'), 5222))
xmpp2.process(threaded=True)
TestPubsubServer.xmpp1 = xmpp1
TestPubsubServer.xmpp2 = xmpp2
TestPubsubServer.pshost = config.get('settings', 'pubsub')
xmpp1.waitforstart.get(True)
xmpp2.waitforstart.get(True)
testsuite = unittest.TestLoader().loadTestsFromTestCase(TestPubsubServer)
alltests_suite = unittest.TestSuite([testsuite])
result = unittest.TextTestRunner(verbosity=2).run(alltests_suite)
xmpp1.disconnect()
xmpp2.disconnect()

View File

@@ -1,13 +0,0 @@
[settings]
enabled=true
pubsub=pubsub.recon
[account1]
jid=fritzy@recon
pass=testing123
server=
[account2]
jid=fritzy2@recon
pass=testing123
server=

View File

@@ -1,350 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
import sleekxmpp
from optparse import OptionParser
from xml.etree import cElementTree as ET
import os
import time
import sys
import Queue
import thread
class testps(sleekxmpp.ClientXMPP):
def __init__(self, jid, password, ssl=False, plugin_config = {}, plugin_whitelist=[], nodenum=0, pshost=None):
sleekxmpp.ClientXMPP.__init__(self, jid, password, ssl, plugin_config, plugin_whitelist)
self.registerPlugin('xep_0004')
self.registerPlugin('xep_0030')
self.registerPlugin('xep_0060')
self.registerPlugin('xep_0092')
self.add_handler("<message xmlns='jabber:client'><event xmlns='http://jabber.org/protocol/pubsub#event' /></message>", self.pubsubEventHandler, name='Pubsub Event', threaded=True)
self.add_event_handler("session_start", self.start, threaded=True)
self.add_handler("<iq type='error' />", self.handleError, name='Iq Error')
self.events = Queue.Queue()
self.default_config = None
self.ps = self.plugin['xep_0060']
self.node = "pstestnode_%s"
self.pshost = pshost
if pshost is None:
self.pshost = self.boundjid.host
self.nodenum = int(nodenum)
self.leafnode = self.nodenum + 1
self.collectnode = self.nodenum + 2
self.lasterror = ''
self.sprintchars = 0
self.defaultconfig = None
self.tests = ['test_defaultConfig', 'test_createDefaultNode', 'test_getNodes', 'test_deleteNode', 'test_createWithConfig', 'test_reconfigureNode', 'test_subscribeToNode', 'test_addItem', 'test_updateItem', 'test_deleteItem', 'test_unsubscribeNode', 'test_createCollection', 'test_subscribeCollection', 'test_addNodeCollection', 'test_deleteNodeCollection', 'test_addCollectionNode', 'test_deleteCollectionNode', 'test_unsubscribeNodeCollection', 'test_deleteCollection']
self.passed = 0
self.width = 120
def start(self, event):
#TODO: make this configurable
self.getRoster()
self.sendPresence(ppriority=20)
thread.start_new(self.test_all, tuple())
def sprint(self, msg, end=False, color=False):
length = len(msg)
if color:
if color == "red":
color = "1;31"
elif color == "green":
color = "0;32"
msg = "%s%s%s" % ("\033[%sm" % color, msg, "\033[0m")
if not end:
sys.stdout.write(msg)
self.sprintchars += length
else:
self.sprint("%s%s" % ("." * (self.width - self.sprintchars - length), msg))
print('')
self.sprintchars = 0
sys.stdout.flush()
def pubsubEventHandler(self, xml):
for item in xml.findall('{http://jabber.org/protocol/pubsub#event}event/{http://jabber.org/protocol/pubsub#event}items/{http://jabber.org/protocol/pubsub#event}item'):
self.events.put(item.get('id', '__unknown__'))
for item in xml.findall('{http://jabber.org/protocol/pubsub#event}event/{http://jabber.org/protocol/pubsub#event}items/{http://jabber.org/protocol/pubsub#event}retract'):
self.events.put(item.get('id', '__unknown__'))
for item in xml.findall('{http://jabber.org/protocol/pubsub#event}event/{http://jabber.org/protocol/pubsub#event}collection/{http://jabber.org/protocol/pubsub#event}disassociate'):
self.events.put(item.get('node', '__unknown__'))
for item in xml.findall('{http://jabber.org/protocol/pubsub#event}event/{http://jabber.org/protocol/pubsub#event}collection/{http://jabber.org/protocol/pubsub#event}associate'):
self.events.put(item.get('node', '__unknown__'))
def handleError(self, xml):
error = xml.find('{jabber:client}error')
self.lasterror = error.getchildren()[0].tag.split('}')[-1]
def test_all(self):
print("Running Publish-Subscribe Tests")
version = self.plugin['xep_0092'].getVersion(self.pshost)
if version:
print("%s %s on %s" % (version.get('name', 'Unknown Server'), version.get('version', 'v?'), version.get('os', 'Unknown OS')))
print("=" * self.width)
for test in self.tests:
testfunc = getattr(self, test)
self.sprint("%s" % testfunc.__doc__)
if testfunc():
self.sprint("Passed", True, "green")
self.passed += 1
else:
if not self.lasterror:
self.lasterror = 'No response'
self.sprint("Failed (%s)" % self.lasterror, True, "red")
self.lasterror = ''
print("=" * self.width)
self.sprint("Cleaning up...")
#self.ps.deleteNode(self.pshost, self.node % self.nodenum)
self.ps.deleteNode(self.pshost, self.node % self.leafnode)
#self.ps.deleteNode(self.pshost, self.node % self.collectnode)
self.sprint("Done", True, "green")
self.disconnect()
self.sprint("%s" % self.passed, False, "green")
self.sprint("/%s Passed -- " % len(self.tests))
if len(self.tests) - self.passed:
self.sprint("%s" % (len(self.tests) - self.passed), False, "red")
else:
self.sprint("%s" % (len(self.tests) - self.passed), False, "green")
self.sprint(" Failed Tests")
print
#print "%s/%s Passed -- %s Failed Tests" % (self.passed, len(self.tests), len(self.tests) - self.passed)
def test_defaultConfig(self):
"Retreiving default configuration"
result = self.ps.getNodeConfig(self.pshost)
if result is False or result is None:
return False
else:
self.defaultconfig = result
try:
self.defaultconfig.field['pubsub#access_model'].setValue('open')
except KeyError:
pass
try:
self.defaultconfig.field['pubsub#notify_retract'].setValue(True)
except KeyError:
pass
return True
def test_createDefaultNode(self):
"Creating default node"
return self.ps.create_node(self.pshost, self.node % self.nodenum)
def test_getNodes(self):
"Getting list of nodes"
self.ps.getNodes(self.pshost)
self.ps.getItems(self.pshost, 'blog')
return True
def test_deleteNode(self):
"Deleting node"
return self.ps.deleteNode(self.pshost, self.node % self.nodenum)
def test_createWithConfig(self):
"Creating node with config"
if self.defaultconfig is None:
self.lasterror = "No Avail Config"
return False
return self.ps.create_node(self.pshost, self.node % self.leafnode, self.defaultconfig)
def test_reconfigureNode(self):
"Retrieving node config and reconfiguring"
nconfig = self.ps.getNodeConfig(self.pshost, self.node % self.leafnode)
if nconfig == False:
return False
return self.ps.setNodeConfig(self.pshost, self.node % self.leafnode, nconfig)
def test_subscribeToNode(self):
"Subscribing to node"
return self.ps.subscribe(self.pshost, self.node % self.leafnode)
def test_addItem(self):
"Adding item, waiting for notification"
item = ET.Element('test')
result = self.ps.setItem(self.pshost, self.node % self.leafnode, (('test_node1', item),))
if result == False:
return False
try:
event = self.events.get(True, 10)
except Queue.Empty:
return False
if event == 'test_node1':
return True
return False
def test_updateItem(self):
"Updating item, waiting for notification"
item = ET.Element('test')
item.attrib['crap'] = 'yup, right here'
result = self.ps.setItem(self.pshost, self.node % self.leafnode, (('test_node1', item),))
if result == False:
return False
try:
event = self.events.get(True, 10)
except Queue.Empty:
return False
if event == 'test_node1':
return True
return False
def test_deleteItem(self):
"Deleting item, waiting for notification"
result = self.ps.deleteItem(self.pshost, self.node % self.leafnode, 'test_node1')
if result == False:
return False
try:
event = self.events.get(True, 10)
except Queue.Empty:
self.lasterror = "No Notification"
return False
if event == 'test_node1':
return True
return False
def test_unsubscribeNode(self):
"Unsubscribing from node"
return self.ps.unsubscribe(self.pshost, self.node % self.leafnode)
def test_createCollection(self):
"Creating collection node"
return self.ps.create_node(self.pshost, self.node % self.collectnode, self.defaultconfig, True)
def test_subscribeCollection(self):
"Subscribing to collection node"
return self.ps.subscribe(self.pshost, self.node % self.collectnode)
def test_addNodeCollection(self):
"Assigning node to collection, waiting for notification"
config = self.ps.getNodeConfig(self.pshost, self.node % self.leafnode)
if not config or config is None:
self.lasterror = "Config Error"
return False
try:
config.field['pubsub#collection'].setValue(self.node % self.collectnode)
except KeyError:
self.sprint("...Missing Field...", False, "red")
config.addField('pubsub#collection', value=self.node % self.collectnode)
if not self.ps.setNodeConfig(self.pshost, self.node % self.leafnode, config):
return False
try:
event = self.events.get(True, 10)
except Queue.Empty:
self.lasterror = "No Notification"
return False
if event == self.node % self.leafnode:
return True
return False
def test_deleteNodeCollection(self):
"Removing node assignment to collection, waiting for notification"
config = self.ps.getNodeConfig(self.pshost, self.node % self.leafnode)
if not config or config is None:
self.lasterror = "Config Error"
return False
try:
config.field['pubsub#collection'].delValue(self.node % self.collectnode)
except KeyError:
self.sprint("...Missing Field...", False, "red")
config.addField('pubsub#collection', value='')
if not self.ps.setNodeConfig(self.pshost, self.node % self.leafnode, config):
return False
try:
event = self.events.get(True, 10)
except Queue.Empty:
self.lasterror = "No Notification"
return False
if event == self.node % self.leafnode:
return True
return False
def test_addCollectionNode(self):
"Assigning node from collection, waiting for notification"
config = self.ps.getNodeConfig(self.pshost, self.node % self.collectnode)
if not config or config is None:
self.lasterror = "Config Error"
return False
try:
config.field['pubsub#children'].setValue(self.node % self.leafnode)
except KeyError:
self.sprint("...Missing Field...", False, "red")
config.addField('pubsub#children', value=self.node % self.leafnode)
if not self.ps.setNodeConfig(self.pshost, self.node % self.collectnode, config):
return False
try:
event = self.events.get(True, 10)
except Queue.Empty:
self.lasterror = "No Notification"
return False
if event == self.node % self.leafnode:
return True
return False
def test_deleteCollectionNode(self):
"Removing node from collection, waiting for notification"
config = self.ps.getNodeConfig(self.pshost, self.node % self.collectnode)
if not config or config is None:
self.lasterror = "Config Error"
return False
try:
config.field['pubsub#children'].delValue(self.node % self.leafnode)
except KeyError:
self.sprint("...Missing Field...", False, "red")
config.addField('pubsub#children', value='')
if not self.ps.setNodeConfig(self.pshost, self.node % self.collectnode, config):
return False
try:
event = self.events.get(True, 10)
except Queue.Empty:
self.lasterror = "No Notification"
return False
if event == self.node % self.leafnode:
return True
return False
def test_unsubscribeNodeCollection(self):
"Unsubscribing from collection"
return self.ps.unsubscribe(self.pshost, self.node % self.collectnode)
def test_deleteCollection(self):
"Deleting collection"
return self.ps.deleteNode(self.pshost, self.node % self.collectnode)
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")
optp.add_option("-n","--nodenum", dest="nodenum", default="1", help="set node number to use")
optp.add_option("-p","--pubsub", dest="pubsub", default="1", help="set pubsub host to use")
opts,args = optp.parse_args()
logging.basicConfig(level=opts.loglevel, format='%(levelname)-8s %(message)s')
#load xml config
logging.info("Loading config file: %s" % opts.configfile)
config = ET.parse(os.path.expanduser(opts.configfile)).find('auth')
#init
logging.info("Logging in as %s" % config.attrib['jid'])
plugin_config = {}
plugin_config['xep_0092'] = {'name': 'SleekXMPP Example', 'version': '0.1-dev'}
plugin_config['xep_0199'] = {'keepalive': True, 'timeout': 30, 'frequency': 300}
con = testps(config.attrib['jid'], config.attrib['pass'], plugin_config=plugin_config, plugin_whitelist=[], nodenum=opts.nodenum, pshost=opts.pubsub)
if not config.get('server', None):
# we don't know the server, but the lib can probably figure it out
con.connect()
else:
con.connect((config.attrib['server'], 5222))
con.process(threaded=False)
print("")

1
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
_build/*

130
docs/Makefile Normal file
View File

@@ -0,0 +1,130 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Slixmpp.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Slixmpp.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Slixmpp"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Slixmpp"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

452
docs/_static/agogo.css vendored Normal file
View File

@@ -0,0 +1,452 @@
/*
* agogo.css_t
* ~~~~~~~~~~~
*
* Sphinx stylesheet -- agogo theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
* {
margin: 0px;
padding: 0px;
}
body {
font-family: "Verdana", Arial, sans-serif;
line-height: 1.4em;
color: black;
background-color: #eeeeec;
}
/* Page layout */
div.header, div.content, div.footer {
width: 70em;
margin-left: auto;
margin-right: auto;
}
div.header-wrapper {
background: url(bgtop.png) top left repeat-x;
border-bottom: 3px solid #2e3436;
}
/* Default body styles */
a {
color: #ce5c00;
}
div.bodywrapper a, div.footer a {
text-decoration: underline;
}
.clearer {
clear: both;
}
.left {
float: left;
}
.right {
float: right;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
h1, h2, h3, h4 {
font-family: "Georgia", "Times New Roman", serif;
font-weight: normal;
color: #3465a4;
margin-bottom: .8em;
}
h1 {
color: #204a87;
}
h2 {
padding-bottom: .5em;
border-bottom: 1px solid #3465a4;
}
a.headerlink {
visibility: hidden;
color: #dddddd;
padding-left: .3em;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
img {
border: 0;
}
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 2px 7px 1px 7px;
border-left: 0.2em solid black;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
/* Header */
div.header {
padding-top: 10px;
padding-bottom: 10px;
}
div.header h1 {
font-family: "Georgia", "Times New Roman", serif;
font-weight: normal;
font-size: 180%;
letter-spacing: .08em;
}
div.header h1 a {
color: white;
}
div.header div.rel {
margin-top: 1em;
}
div.header div.rel a {
color: #fcaf3e;
letter-spacing: .1em;
text-transform: uppercase;
}
p.logo {
float: right;
}
img.logo {
border: 0;
}
/* Content */
div.content-wrapper {
background-color: white;
padding-top: 20px;
padding-bottom: 20px;
}
div.document {
width: 50em;
float: left;
}
div.body {
padding-right: 2em;
text-align: justify;
}
div.document ul {
margin: 1.5em;
list-style-type: square;
}
div.document dd {
margin-left: 1.2em;
margin-top: .4em;
margin-bottom: 1em;
}
div.document .section {
margin-top: 1.7em;
}
div.document .section:first-child {
margin-top: 0px;
}
div.document div.highlight {
padding: 3px;
background-color: #eeeeec;
border-top: 2px solid #dddddd;
border-bottom: 2px solid #dddddd;
margin-top: .8em;
margin-bottom: .8em;
}
div.document h2 {
margin-top: .7em;
}
div.document p {
margin-bottom: .5em;
}
div.document li.toctree-l1 {
margin-bottom: 1em;
}
div.document .descname {
font-weight: bold;
}
div.document .docutils.literal {
background-color: #eeeeec;
padding: 1px;
}
div.document .docutils.xref.literal {
background-color: transparent;
padding: 0px;
}
div.document blockquote {
margin: 1em;
}
div.document ol {
margin: 1.5em;
}
/* Sidebar */
div.sidebar {
width: 20em;
float: right;
font-size: .9em;
}
div.sidebar a, div.header a {
text-decoration: none;
}
div.sidebar a:hover, div.header a:hover {
text-decoration: underline;
}
div.sidebar h3 {
color: #2e3436;
text-transform: uppercase;
font-size: 130%;
letter-spacing: .1em;
}
div.sidebar ul {
list-style-type: none;
}
div.sidebar li.toctree-l1 a {
display: block;
padding: 1px;
border: 1px solid #dddddd;
background-color: #eeeeec;
margin-bottom: .4em;
padding-left: 3px;
color: #2e3436;
}
div.sidebar li.toctree-l2 a {
background-color: transparent;
border: none;
margin-left: 1em;
border-bottom: 1px solid #dddddd;
}
div.sidebar li.toctree-l3 a {
background-color: transparent;
border: none;
margin-left: 2em;
border-bottom: 1px solid #dddddd;
}
div.sidebar li.toctree-l2:last-child a {
border-bottom: none;
}
div.sidebar li.toctree-l1.current a {
border-right: 5px solid #fcaf3e;
}
div.sidebar li.toctree-l1.current li.toctree-l2 a {
border-right: none;
}
/* Footer */
div.footer-wrapper {
background: url(bgfooter.png) top left repeat-x;
border-top: 4px solid #babdb6;
padding-top: 10px;
padding-bottom: 10px;
min-height: 80px;
}
div.footer, div.footer a {
color: #888a85;
}
div.footer .right {
text-align: right;
}
div.footer .left {
text-transform: uppercase;
}
/* Styles copied from basic theme */
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
clear: both;
text-align: center;
}
.align-right {
text-align: right;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
/* -- viewcode extension ---------------------------------------------------- */
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family:: "Verdana", Arial, sans-serif;
}
div.viewcode-block:target {
margin: -1px -3px;
padding: 0 3px;
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

532
docs/_static/basic.css vendored Normal file
View File

@@ -0,0 +1,532 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
img {
border: 0;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- general body styles --------------------------------------------------- */
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
clear: both;
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #efefef;
width: 40%;
float: right;
-mox-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
p.sidebar-title {
font-weight: bold;
text-transform: uppercase;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.refcount {
color: #060;
}
.optional {
font-size: 1.3em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
tt.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
tt.descclassname {
background-color: transparent;
}
tt.xref, a tt {
background-color: transparent;
font-weight: bold;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

256
docs/_static/default.css vendored Normal file
View File

@@ -0,0 +1,256 @@
/*
* default.css_t
* ~~~~~~~~~~~~~
*
* Sphinx stylesheet -- default theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: sans-serif;
font-size: 100%;
background-color: #11303d;
color: #000;
margin: 0;
padding: 0;
}
div.document {
background-color: #1c4e63;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
div.body {
background-color: #ffffff;
color: #000000;
padding: 0 20px 30px 20px;
}
div.footer {
color: #ffffff;
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #ffffff;
text-decoration: underline;
}
div.related {
background-color: #133f52;
line-height: 30px;
color: #ffffff;
}
div.related a {
color: #ffffff;
}
div.sphinxsidebar {
}
div.sphinxsidebar h3 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.4em;
font-weight: normal;
margin: 0;
padding: 0;
}
div.sphinxsidebar h3 a {
color: #ffffff;
}
div.sphinxsidebar h4 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.3em;
font-weight: normal;
margin: 5px 0 0 0;
padding: 0;
}
div.sphinxsidebar p {
color: #ffffff;
}
div.sphinxsidebar p.topless {
margin: 5px 10px 10px 10px;
}
div.sphinxsidebar ul {
margin: 10px;
padding: 0;
color: #ffffff;
}
div.sphinxsidebar a {
color: #98dbcc;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
/* -- hyperlink styles ------------------------------------------------------ */
a {
color: #355f7c;
text-decoration: none;
}
a:visited {
color: #355f7c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* -- body styles ----------------------------------------------------------- */
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Trebuchet MS', sans-serif;
background-color: #f2f2f2;
font-weight: normal;
color: #20435c;
border-bottom: 1px solid #ccc;
margin: 20px -20px 10px -20px;
padding: 3px 0 3px 10px;
}
div.body h1 { margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 160%; }
div.body h3 { font-size: 140%; }
div.body h4 { font-size: 120%; }
div.body h5 { font-size: 110%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
text-align: justify;
line-height: 130%;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.admonition p {
margin-bottom: 5px;
}
div.admonition pre {
margin-bottom: 5px;
}
div.admonition ul, div.admonition ol {
margin-bottom: 5px;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 5px;
background-color: #eeffcc;
color: #333333;
line-height: 120%;
border: 1px solid #ac9;
border-left: none;
border-right: none;
}
tt {
background-color: #ecf0f3;
padding: 0 1px 0 1px;
font-size: 0.95em;
}
th {
background-color: #ede;
}
.warning tt {
background: #efc2c2;
}
.note tt {
background: #d6d6d6;
}
.viewcode-back {
font-family: sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

BIN
docs/_static/fonts/Museo_Slab_500.otf vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
docs/_static/fonts/OFLGoudyStMTT.ttf vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

431
docs/_static/haiku.css vendored Normal file
View File

@@ -0,0 +1,431 @@
/*
* haiku.css_t
* ~~~~~~~~~~~
*
* Sphinx stylesheet -- haiku theme.
*
* Adapted from http://haiku-os.org/docs/Haiku-doc.css.
* Original copyright message:
*
* Copyright 2008-2009, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Francois Revol <revol@free.fr>
* Stephan Assmus <superstippi@gmx.de>
* Braden Ewing <brewin@gmail.com>
* Humdinger <humdingerb@gmail.com>
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
@font-face {
font-family: "Museo Slab";
font-weight: normal;
font-style: normal;
src: local("Museo Slab"),
url("fonts/Museo_Slab_500.otf") format("opentype");
}
@font-face {
font-family: "Yanone Kaffeesatz";
font-weight: bold;
font-style: normal;
src: local("Yanone Kaffeesatz"),
url("fonts/YanoneKaffeesatz-Bold.ttf") format("truetype");
}
@font-face {
font-family: "Yanone Kaffeesatz";
font-weight: lighter;
font-style: normal;
src: local("Yanone Kaffeesatz"),
url("fonts/YanoneKaffeesatz-Regular.ttf") format("truetype");
}
html {
margin: 0px;
padding: 0px;
background: #FFF url(header.png) top left repeat-x;
}
body {
line-height: 1.5;
margin: auto;
padding: 0px;
font-family: "Helvetica Neueu", Helvetica, sans-serif;
min-width: 30em;
max-width: 70em;
color: #444;
text-align: center;
}
div.footer {
padding: 8px;
font-size: 11px;
text-align: center;
letter-spacing: 0.5px;
}
/* link colors and text decoration */
a:link {
font-weight: bold;
text-decoration: none;
color: #00ADEE;
}
a:visited {
font-weight: bold;
text-decoration: none;
color: #00ADEE;
}
a:hover, a:active {
text-decoration: underline;
color: #F46DBA;
}
/* Some headers act as anchors, don't give them a hover effect */
h1 a:hover, a:active {
text-decoration: none;
color: #CFCFCF;
}
h2 a:hover, a:active {
text-decoration: none;
color: #CFCFCF;
}
h3 a:hover, a:active {
text-decoration: none;
color: #CFCFCF;
}
h4 a:hover, a:active {
text-decoration: none;
color: #CFCFCF;
}
a.headerlink {
color: #a7ce38;
padding-left: 5px;
}
a.headerlink:hover {
color: #a7ce38;
}
/* basic text elements */
div.content {
margin: auto;
margin-top: 20px;
margin-bottom: 50px;
font-size: 0.9em;
width: 700px;
text-align: left;
}
/* heading and navigation */
div.header {
position: relative;
margin: auto;
margin-top: 125px;
height: 85px;
padding: 0 40px;
font-family: "Yanone Kaffeesatz";
text-align: left;
width: 750px;
}
div.header h1 {
font-size: 2.6em;
font-weight: normal;
letter-spacing: 1px;
color: #CFCFCF;
border: 0;
margin: 0;
padding-top: 15px;
font-family: "Yanone Kaffeesatz";
text-shadow: 1px 1px 1px rgba(175, 175, 175, .8);
font-variant: small-caps;
}
div.header h1 a {
font-weight: normal;
color: #00ADEE;
}
div.header h2 {
font-size: 1.3em;
font-weight: normal;
letter-spacing: 1px;
text-transform: uppercase;
color: #aaa;
border: 0;
margin-top: -3px;
padding: 0;
font-family: "Yanone Kaffeesatz";
}
div.header img.rightlogo {
float: right;
}
div.title {
font-size: 1.3em;
font-weight: bold;
color: #CFCFCF;
border-bottom: dotted thin #e0e0e0;
margin-bottom: 25px;
}
div.topnav {
position: relative;
z-index: 0;
}
div.topnav p {
margin: auto;
margin-top: 0;
margin-bottom: 0px;
text-align: right;
font-size: 0.8em;
width: 750px;
}
div.bottomnav {
background: #eeeeee;
}
div.bottomnav p {
margin-right: 40px;
text-align: right;
font-size: 0.8em;
}
a.uplink {
font-weight: normal;
}
/* contents box */
table.index {
margin: 0px 0px 30px 30px;
padding: 1px;
border-width: 1px;
border-style: dotted;
border-color: #e0e0e0;
}
table.index tr.heading {
background-color: #e0e0e0;
text-align: center;
font-weight: bold;
font-size: 1.1em;
}
table.index tr.index {
background-color: #eeeeee;
}
table.index td {
padding: 5px 20px;
}
table.index a:link, table.index a:visited {
font-weight: normal;
text-decoration: none;
color: #4A7389;
}
table.index a:hover, table.index a:active {
text-decoration: underline;
color: #ff4500;
}
/* Haiku User Guide styles and layout */
/* Rounded corner boxes */
/* Common declarations */
div.admonition {
-webkit-border-radius: 10px;
-khtml-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
border-style: dotted;
border-width: thin;
border-color: #dcdcdc;
padding: 10px 15px 10px 15px;
margin-bottom: 15px;
margin-top: 15px;
}
div.note {
padding: 10px 15px 10px 15px;
background-color: #e4ffde;
/*background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat;*/
min-height: 42px;
}
div.warning {
padding: 10px 15px 10px 15px;
background-color: #fffbc6;
/*background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat;*/
min-height: 42px;
}
div.seealso {
background: #e4ffde;
}
/* More layout and styles */
h1 {
font-size: 1.6em;
color: #aaa;
border-bottom: dotted thin #e0e0e0;
margin-top: 30px;
font-family: "Museo Slab";
text-shadow: 1px 1px 1px rgba(175, 175, 175, .25);
}
h2 {
font-size: 1.5em;
font-weight: normal;
color: #aaa;
border-bottom: dotted thin #e0e0e0;
margin-top: 30px;
font-family: "Museo Slab";
text-shadow: 1px 1px 1px rgba(175, 175, 175, .25);
}
h3 {
font-size: 1.4em;
font-weight: normal;
color: #aaa;
margin-top: 30px;
font-family: "Museo Slab";
text-shadow: 1px 1px 1px rgba(175, 175, 175, .25);
}
h4 {
font-size: 1.3em;
font-weight: normal;
color: #CFCFCF;
margin-top: 30px;
}
p {
text-align: justify;
}
p.last {
margin-bottom: 0;
}
ol {
padding-left: 20px;
}
ul {
padding-left: 5px;
margin-top: 3px;
}
li {
line-height: 1.3;
}
div.content ul > li {
-moz-background-clip:border;
-moz-background-inline-policy:continuous;
-moz-background-origin:padding;
background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em;
list-style-image: none;
list-style-type: none;
padding: 0 0 0 1.666em;
margin-bottom: 3px;
}
td {
vertical-align: top;
}
tt {
background-color: #e2e2e2;
font-size: 1.0em;
font-family: monospace;
}
pre {
font-size: 1.1em;
margin: 0 0 12px 0;
padding: 0.8em;
background-image: url(noise_dk.png);
background-color: #222;
}
hr {
border-top: 1px solid #ccc;
border-bottom: 0;
border-right: 0;
border-left: 0;
margin-bottom: 10px;
margin-top: 20px;
}
/* printer only pretty stuff */
@media print {
.noprint {
display: none;
}
/* for acronyms we want their definitions inlined at print time */
acronym[title]:after {
font-size: small;
content: " (" attr(title) ")";
font-style: italic;
}
/* and not have mozilla dotted underline */
acronym {
border: none;
}
div.topnav, div.bottomnav, div.header, table.index {
display: none;
}
div.content {
margin: 0px;
padding: 0px;
}
html {
background: #FFF;
}
}
.viewcode-back {
font-family: "DejaVu Sans", Arial, Helvetica, sans-serif;
}
div.viewcode-block:target {
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
margin: -1px -12px;
padding: 0 12px;
}
#from_andyet {
-webkit-box-shadow: #CCC 0px 0px 3px;
background: rgba(255, 255, 255, 1);
bottom: 0px;
right: 17px;
padding: 3px 10px;
position: fixed;
}
#from_andyet h2 {
background-image: url("images/from_&yet.png");
background-repeat: no-repeat;
height: 29px;
line-height: 0;
text-indent: -9999em;
width: 79px;
margin-top: 0;
margin: 0px;
padding: 0px;
}

BIN
docs/_static/header.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/_static/images/arch_layers.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/_static/images/from_&yet.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

70
docs/_static/ir_black.css vendored Normal file
View File

@@ -0,0 +1,70 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #000000; color: #f6f3e8; }
.highlight .c { color: #7C7C7C; } /* Comment */
.highlight .err { color: #f6f3e8; } /* Error */
.highlight .g { color: #f6f3e8; } /* Generic */
.highlight .k { color: #00ADEE; } /* Keyword */
.highlight .l { color: #f6f3e8; } /* Literal */
.highlight .n { color: #f6f3e8; } /* Name */
.highlight .o { color: #f6f3e8; } /* Operator */
.highlight .x { color: #f6f3e8; } /* Other */
.highlight .p { color: #f6f3e8; } /* Punctuation */
.highlight .cm { color: #7C7C7C; } /* Comment.Multiline */
.highlight .cp { color: #96CBFE; } /* Comment.Preproc */
.highlight .c1 { color: #7C7C7C; } /* Comment.Single */
.highlight .cs { color: #7C7C7C; } /* Comment.Special */
.highlight .gd { color: #f6f3e8; } /* Generic.Deleted */
.highlight .ge { color: #f6f3e8; } /* Generic.Emph */
.highlight .gr { color: #ffffff; background-color: #ff0000 } /* Generic.Error */
.highlight .gh { color: #f6f3e8; font-weight: bold; } /* Generic.Heading */
.highlight .gi { color: #f6f3e8; } /* Generic.Inserted */
.highlight .go { color: #070707; } /* Generic.Output */
.highlight .gp { color: #f6f3e8; } /* Generic.Prompt */
.highlight .gs { color: #f6f3e8; } /* Generic.Strong */
.highlight .gu { color: #f6f3e8; font-weight: bold; } /* Generic.Subheading */
.highlight .gt { color: #ffffff; font-weight: bold; background-color: #FF6C60 } /* Generic.Traceback */
.highlight .kc { color: #6699CC; } /* Keyword.Constant */
.highlight .kd { color: #6699CC; } /* Keyword.Declaration */
.highlight .kn { color: #6699CC; } /* Keyword.Namespace */
.highlight .kp { color: #6699CC; } /* Keyword.Pseudo */
.highlight .kr { color: #6699CC; } /* Keyword.Reserved */
.highlight .kt { color: #FFFFB6; } /* Keyword.Type */
.highlight .ld { color: #f6f3e8; } /* Literal.Date */
.highlight .m { color: #FF73FD; } /* Literal.Number */
.highlight .s { color: #F46DBA;/*#A8FF60;*/ } /* Literal.String */
.highlight .na { color: #f6f3e8; } /* Name.Attribute */
.highlight .nb { color: #f6f3e8; } /* Name.Builtin */
.highlight .nc { color: #f6f3e8; } /* Name.Class */
.highlight .no { color: #99CC99; } /* Name.Constant */
.highlight .nd { color: #f6f3e8; } /* Name.Decorator */
.highlight .ni { color: #E18964; } /* Name.Entity */
.highlight .ne { color: #f6f3e8; } /* Name.Exception */
.highlight .nf { color: #F64DBA; } /* Name.Function */
.highlight .nl { color: #f6f3e8; } /* Name.Label */
.highlight .nn { color: #f6f3e8; } /* Name.Namespace */
.highlight .nx { color: #f6f3e8; } /* Name.Other */
.highlight .py { color: #f6f3e8; } /* Name.Property */
.highlight .nt { color: #00ADEE; } /* Name.Tag */
.highlight .nv { color: #C6C5FE; } /* Name.Variable */
.highlight .ow { color: #ffffff; } /* Operator.Word */
.highlight .w { color: #f6f3e8; } /* Text.Whitespace */
.highlight .mf { color: #FF73FD; } /* Literal.Number.Float */
.highlight .mh { color: #FF73FD; } /* Literal.Number.Hex */
.highlight .mi { color: #FF73FD; } /* Literal.Number.Integer */
.highlight .mo { color: #FF73FD; } /* Literal.Number.Oct */
.highlight .sb { color: #A8FF60; } /* Literal.String.Backtick */
.highlight .sc { color: #A8FF60; } /* Literal.String.Char */
.highlight .sd { color: #A8FF60; } /* Literal.String.Doc */
.highlight .s2 { color: #A8FF60; } /* Literal.String.Double */
.highlight .se { color: #A8FF60; } /* Literal.String.Escape */
.highlight .sh { color: #A8FF60; } /* Literal.String.Heredoc */
.highlight .si { color: #A8FF60; } /* Literal.String.Interpol */
.highlight .sx { color: #A8FF60; } /* Literal.String.Other */
.highlight .sr { color: #A8FF60; } /* Literal.String.Regex */
.highlight .s1 { color: #A8FF60; } /* Literal.String.Single */
.highlight .ss { color: #A8FF60; } /* Literal.String.Symbol */
.highlight .bp { color: #f6f3e8; } /* Name.Builtin.Pseudo */
.highlight .vc { color: #C6C5FE; } /* Name.Variable.Class */
.highlight .vg { color: #C6C5FE; } /* Name.Variable.Global */
.highlight .vi { color: #C6C5FE; } /* Name.Variable.Instance */
.highlight .il { color: #FF73FD; } /* Literal.Number.Integer.Long */

245
docs/_static/nature.css vendored Normal file
View File

@@ -0,0 +1,245 @@
/*
* nature.css_t
* ~~~~~~~~~~~~
*
* Sphinx stylesheet -- nature theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: Arial, sans-serif;
font-size: 100%;
background-color: #111;
color: #555;
margin: 0;
padding: 0;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
hr {
border: 1px solid #B1B4B6;
}
div.document {
background-color: #eee;
}
div.body {
background-color: #ffffff;
color: #3E4349;
padding: 0 30px 30px 30px;
font-size: 0.9em;
}
div.footer {
color: #555;
width: 100%;
padding: 13px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #444;
text-decoration: underline;
}
div.related {
background-color: #6BA81E;
line-height: 32px;
color: #fff;
text-shadow: 0px 1px 0 #444;
font-size: 0.9em;
}
div.related a {
color: #E2F3CC;
}
div.sphinxsidebar {
font-size: 0.75em;
line-height: 1.5em;
}
div.sphinxsidebarwrapper{
padding: 20px 0;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4 {
font-family: Arial, sans-serif;
color: #222;
font-size: 1.2em;
font-weight: normal;
margin: 0;
padding: 5px 10px;
background-color: #ddd;
text-shadow: 1px 1px 0 white
}
div.sphinxsidebar h4{
font-size: 1.1em;
}
div.sphinxsidebar h3 a {
color: #444;
}
div.sphinxsidebar p {
color: #888;
padding: 5px 20px;
}
div.sphinxsidebar p.topless {
}
div.sphinxsidebar ul {
margin: 10px 20px;
padding: 0;
color: #000;
}
div.sphinxsidebar a {
color: #444;
}
div.sphinxsidebar input {
border: 1px solid #ccc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar input[type=text]{
margin-left: 20px;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #005B81;
text-decoration: none;
}
a:hover {
color: #E32E00;
text-decoration: underline;
}
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: Arial, sans-serif;
background-color: #BED4EB;
font-weight: normal;
color: #212224;
margin: 30px 0px 10px 0px;
padding: 5px 0 5px 10px;
text-shadow: 0px 1px 0 white
}
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
line-height: 1.5em;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.highlight{
background-color: white;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 10px;
background-color: White;
color: #222;
line-height: 1.2em;
border: 1px solid #C6C9CB;
font-size: 1.1em;
margin: 1.5em 0 1.5em 0;
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
-moz-box-shadow: 1px 1px 1px #d8d8d8;
}
tt {
background-color: #ecf0f3;
color: #222;
/* padding: 1px 2px; */
font-size: 1.1em;
font-family: monospace;
}
.viewcode-back {
font-family: Arial, sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

BIN
docs/_static/noise_dk.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

70
docs/_static/pygments.css vendored Normal file
View File

@@ -0,0 +1,70 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #000000; color: #f6f3e8; }
.highlight .c { color: #7C7C7C; } /* Comment */
.highlight .err { color: #f6f3e8; } /* Error */
.highlight .g { color: #f6f3e8; } /* Generic */
.highlight .k { color: #00ADEE; } /* Keyword */
.highlight .l { color: #f6f3e8; } /* Literal */
.highlight .n { color: #f6f3e8; } /* Name */
.highlight .o { color: #f6f3e8; } /* Operator */
.highlight .x { color: #f6f3e8; } /* Other */
.highlight .p { color: #f6f3e8; } /* Punctuation */
.highlight .cm { color: #7C7C7C; } /* Comment.Multiline */
.highlight .cp { color: #96CBFE; } /* Comment.Preproc */
.highlight .c1 { color: #7C7C7C; } /* Comment.Single */
.highlight .cs { color: #7C7C7C; } /* Comment.Special */
.highlight .gd { color: #f6f3e8; } /* Generic.Deleted */
.highlight .ge { color: #f6f3e8; } /* Generic.Emph */
.highlight .gr { color: #ffffff; background-color: #ff0000 } /* Generic.Error */
.highlight .gh { color: #f6f3e8; font-weight: bold; } /* Generic.Heading */
.highlight .gi { color: #f6f3e8; } /* Generic.Inserted */
.highlight .go { color: #070707; } /* Generic.Output */
.highlight .gp { color: #f6f3e8; } /* Generic.Prompt */
.highlight .gs { color: #f6f3e8; } /* Generic.Strong */
.highlight .gu { color: #f6f3e8; font-weight: bold; } /* Generic.Subheading */
.highlight .gt { color: #ffffff; font-weight: bold; background-color: #FF6C60 } /* Generic.Traceback */
.highlight .kc { color: #6699CC; } /* Keyword.Constant */
.highlight .kd { color: #6699CC; } /* Keyword.Declaration */
.highlight .kn { color: #6699CC; } /* Keyword.Namespace */
.highlight .kp { color: #6699CC; } /* Keyword.Pseudo */
.highlight .kr { color: #6699CC; } /* Keyword.Reserved */
.highlight .kt { color: #FFFFB6; } /* Keyword.Type */
.highlight .ld { color: #f6f3e8; } /* Literal.Date */
.highlight .m { color: #FF73FD; } /* Literal.Number */
.highlight .s { color: #F46DBA;/*#A8FF60;*/ } /* Literal.String */
.highlight .na { color: #f6f3e8; } /* Name.Attribute */
.highlight .nb { color: #f6f3e8; } /* Name.Builtin */
.highlight .nc { color: #f6f3e8; } /* Name.Class */
.highlight .no { color: #99CC99; } /* Name.Constant */
.highlight .nd { color: #f6f3e8; } /* Name.Decorator */
.highlight .ni { color: #E18964; } /* Name.Entity */
.highlight .ne { color: #f6f3e8; } /* Name.Exception */
.highlight .nf { color: #F64DBA; } /* Name.Function */
.highlight .nl { color: #f6f3e8; } /* Name.Label */
.highlight .nn { color: #f6f3e8; } /* Name.Namespace */
.highlight .nx { color: #f6f3e8; } /* Name.Other */
.highlight .py { color: #f6f3e8; } /* Name.Property */
.highlight .nt { color: #00ADEE; } /* Name.Tag */
.highlight .nv { color: #C6C5FE; } /* Name.Variable */
.highlight .ow { color: #ffffff; } /* Operator.Word */
.highlight .w { color: #f6f3e8; } /* Text.Whitespace */
.highlight .mf { color: #FF73FD; } /* Literal.Number.Float */
.highlight .mh { color: #FF73FD; } /* Literal.Number.Hex */
.highlight .mi { color: #FF73FD; } /* Literal.Number.Integer */
.highlight .mo { color: #FF73FD; } /* Literal.Number.Oct */
.highlight .sb { color: #A8FF60; } /* Literal.String.Backtick */
.highlight .sc { color: #A8FF60; } /* Literal.String.Char */
.highlight .sd { color: #A8FF60; } /* Literal.String.Doc */
.highlight .s2 { color: #A8FF60; } /* Literal.String.Double */
.highlight .se { color: #A8FF60; } /* Literal.String.Escape */
.highlight .sh { color: #A8FF60; } /* Literal.String.Heredoc */
.highlight .si { color: #A8FF60; } /* Literal.String.Interpol */
.highlight .sx { color: #A8FF60; } /* Literal.String.Other */
.highlight .sr { color: #A8FF60; } /* Literal.String.Regex */
.highlight .s1 { color: #A8FF60; } /* Literal.String.Single */
.highlight .ss { color: #A8FF60; } /* Literal.String.Symbol */
.highlight .bp { color: #f6f3e8; } /* Name.Builtin.Pseudo */
.highlight .vc { color: #C6C5FE; } /* Name.Variable.Class */
.highlight .vg { color: #C6C5FE; } /* Name.Variable.Global */
.highlight .vi { color: #C6C5FE; } /* Name.Variable.Instance */
.highlight .il { color: #FF73FD; } /* Literal.Number.Integer.Long */

339
docs/_static/sphinxdoc.css vendored Normal file
View File

@@ -0,0 +1,339 @@
/*
* sphinxdoc.css_t
* ~~~~~~~~~~~~~~~
*
* Sphinx stylesheet -- sphinxdoc theme. Originally created by
* Armin Ronacher for Werkzeug.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
'Verdana', sans-serif;
font-size: 14px;
letter-spacing: -0.01em;
line-height: 150%;
text-align: center;
background-color: #BFD1D4;
color: black;
padding: 0;
border: 1px solid #aaa;
margin: 0px 80px 0px 80px;
min-width: 740px;
}
div.document {
background-color: white;
text-align: left;
background-image: url(contents.png);
background-repeat: repeat-x;
}
div.bodywrapper {
margin: 0 240px 0 0;
border-right: 1px solid #ccc;
}
div.body {
margin: 0;
padding: 0.5em 20px 20px 20px;
}
div.related {
font-size: 1em;
}
div.related ul {
background-image: url(navigation.png);
height: 2em;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
}
div.related ul li {
margin: 0;
padding: 0;
height: 2em;
float: left;
}
div.related ul li.right {
float: right;
margin-right: 5px;
}
div.related ul li a {
margin: 0;
padding: 0 5px 0 5px;
line-height: 1.75em;
color: #EE9816;
}
div.related ul li a:hover {
color: #3CA8E7;
}
div.sphinxsidebarwrapper {
padding: 0;
}
div.sphinxsidebar {
margin: 0;
padding: 0.5em 15px 15px 0;
width: 210px;
float: right;
font-size: 1em;
text-align: left;
}
div.sphinxsidebar h3, div.sphinxsidebar h4 {
margin: 1em 0 0.5em 0;
font-size: 1em;
padding: 0.1em 0 0.1em 0.5em;
color: white;
border: 1px solid #86989B;
background-color: #AFC1C4;
}
div.sphinxsidebar h3 a {
color: white;
}
div.sphinxsidebar ul {
padding-left: 1.5em;
margin-top: 7px;
padding: 0;
line-height: 130%;
}
div.sphinxsidebar ul ul {
margin-left: 20px;
}
div.footer {
background-color: #E3EFF1;
color: #86989B;
padding: 3px 8px 3px 0;
clear: both;
font-size: 0.8em;
text-align: right;
}
div.footer a {
color: #86989B;
text-decoration: underline;
}
/* -- body styles ----------------------------------------------------------- */
p {
margin: 0.8em 0 0.5em 0;
}
a {
color: #CA7900;
text-decoration: none;
}
a:hover {
color: #2491CF;
}
div.body a {
text-decoration: underline;
}
h1 {
margin: 0;
padding: 0.7em 0 0.3em 0;
font-size: 1.5em;
color: #11557C;
}
h2 {
margin: 1.3em 0 0.2em 0;
font-size: 1.35em;
padding: 0;
}
h3 {
margin: 1em 0 -0.3em 0;
font-size: 1.2em;
}
div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
color: black!important;
}
h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
display: none;
margin: 0 0 0 0.3em;
padding: 0 0.2em 0 0.2em;
color: #aaa!important;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
h5:hover a.anchor, h6:hover a.anchor {
display: inline;
}
h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
h5 a.anchor:hover, h6 a.anchor:hover {
color: #777;
background-color: #eee;
}
a.headerlink {
color: #c60f0f!important;
font-size: 1em;
margin-left: 6px;
padding: 0 4px 0 4px;
text-decoration: none!important;
}
a.headerlink:hover {
background-color: #ccc;
color: white!important;
}
cite, code, tt {
font-family: 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
font-size: 0.95em;
letter-spacing: 0.01em;
}
tt {
background-color: #f2f2f2;
border-bottom: 1px solid #ddd;
color: #333;
}
tt.descname, tt.descclassname, tt.xref {
border: 0;
}
hr {
border: 1px solid #abc;
margin: 2em;
}
a tt {
border: 0;
color: #CA7900;
}
a tt:hover {
color: #2491CF;
}
pre {
font-family: 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
font-size: 0.95em;
letter-spacing: 0.015em;
line-height: 120%;
padding: 0.5em;
border: 1px solid #ccc;
background-color: #f8f8f8;
}
pre a {
color: inherit;
text-decoration: underline;
}
td.linenos pre {
padding: 0.5em 0;
}
div.quotebar {
background-color: #f8f8f8;
max-width: 250px;
float: right;
padding: 2px 7px;
border: 1px solid #ccc;
}
div.topic {
background-color: #f8f8f8;
}
table {
border-collapse: collapse;
margin: 0 -0.5em 0 -0.5em;
}
table td, table th {
padding: 0.2em 0.5em 0.2em 0.5em;
}
div.admonition, div.warning {
font-size: 0.9em;
margin: 1em 0 1em 0;
border: 1px solid #86989B;
background-color: #f7f7f7;
padding: 0;
}
div.admonition p, div.warning p {
margin: 0.5em 1em 0.5em 1em;
padding: 0;
}
div.admonition pre, div.warning pre {
margin: 0.4em 1em 0.4em 1em;
}
div.admonition p.admonition-title,
div.warning p.admonition-title {
margin: 0;
padding: 0.1em 0 0.1em 0.5em;
color: white;
border-bottom: 1px solid #86989B;
font-weight: bold;
background-color: #AFC1C4;
}
div.warning {
border: 1px solid #940000;
}
div.warning p.admonition-title {
background-color: #CF0000;
border-bottom-color: #940000;
}
div.admonition ul, div.admonition ol,
div.warning ul, div.warning ol {
margin: 0.1em 0.5em 0.5em 3em;
padding: 0;
}
div.versioninfo {
margin: 1em 0 0 0;
border: 1px solid #ccc;
background-color: #DDEAF0;
padding: 8px;
line-height: 1.3em;
font-size: 0.9em;
}
.viewcode-back {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
'Verdana', sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

70
docs/_templates/layout.html vendored Normal file
View File

@@ -0,0 +1,70 @@
{#
haiku/layout.html
~~~~~~~~~~~~~~~~~
Sphinx layout template for the haiku theme.
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{% extends "basic/layout.html" %}
{% set script_files = script_files + ['_static/theme_extras.js'] %}
{% set css_files = css_files + ['_static/print.css'] %}
{# do not display relbars #}
{% block relbar1 %}{% endblock %}
{% block relbar2 %}{% endblock %}
{% macro nav() %}
<p>
{%- block haikurel1 %}
{%- endblock %}
{%- if prev %}
«&#160;&#160;<a href="{{ prev.link|e }}">{{ prev.title }}</a>
&#160;&#160;::&#160;&#160;
{%- endif %}
<a class="uplink" href="{{ pathto(master_doc) }}">{{ _('Contents') }}</a>
{%- if next %}
&#160;&#160;::&#160;&#160;
<a href="{{ next.link|e }}">{{ next.title }}</a>&#160;&#160;»
{%- endif %}
{%- block haikurel2 %}
{%- endblock %}
</p>
{% endmacro %}
{% block content %}
<div class="header">
{%- block haikuheader %}
{%- if theme_full_logo != "false" %}
<a href="{{ pathto('index') }}">
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
</a>
{%- else %}
{%- if logo -%}
<img class="rightlogo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
{%- endif -%}
<h1 class="heading"><a href="{{ pathto('index') }}">
<span>{{ title|striptags }}</span></a></h1>
<h2 class="heading"><span>{{ shorttitle|e }}</span></h2>
{%- endif %}
{%- endblock %}
</div>
<div class="topnav">
{{ nav() }}
</div>
<div class="content">
{#{%- if display_toc %}
<div id="toc">
<h3>Table Of Contents</h3>
{{ toc }}
</div>
{%- endif %}#}
{% block body %}{% endblock %}
</div>
<div class="bottomnav">
{{ nav() }}
</div>
<a id="from_andyet" href="http://andyet.net"><h2>From &amp;yet</h2></a>
{% endblock %}

8
docs/api/basexmpp.rst Normal file
View File

@@ -0,0 +1,8 @@
========
BaseXMPP
========
.. module:: slixmpp.basexmpp
.. autoclass:: BaseXMPP
:members:

8
docs/api/clientxmpp.rst Normal file
View File

@@ -0,0 +1,8 @@
==========
ClientXMPP
==========
.. module:: slixmpp.clientxmpp
.. autoclass:: ClientXMPP
:members:

View File

@@ -0,0 +1,8 @@
=============
ComponentXMPP
=============
.. module:: slixmpp.componentxmpp
.. autoclass:: ComponentXMPP
:members:

14
docs/api/exceptions.rst Normal file
View File

@@ -0,0 +1,14 @@
Exceptions
==========
.. module:: slixmpp.exceptions
.. autoexception:: XMPPError
:members:
.. autoexception:: IqError
:members:
.. autoexception:: IqTimeout
:members:

8
docs/api/stanza/iq.rst Normal file
View File

@@ -0,0 +1,8 @@
IQ Stanza
=========
.. module:: slixmpp.stanza
.. autoclass:: Iq
:members:

View File

@@ -0,0 +1,7 @@
Message Stanza
==============
.. module:: slixmpp.stanza
.. autoclass:: Message
:members:

View File

@@ -0,0 +1,8 @@
Presence Stanza
===============
.. module:: slixmpp.stanza
.. autoclass:: Presence
:members:

View File

@@ -0,0 +1,8 @@
Root Stanza
===========
.. module:: slixmpp.stanza.rootstanza
.. autoclass:: RootStanza
:members:

View File

@@ -0,0 +1,28 @@
Stanza Handlers
===============
The Basic Handler
-----------------
.. module:: slixmpp.xmlstream.handler.base
.. autoclass:: BaseHandler
:members:
Callback
--------
.. module:: slixmpp.xmlstream.handler
.. autoclass:: Callback
:members:
CoroutineCallback
-----------------
.. autoclass:: CoroutineCallback
:members:
Waiter
------
.. autoclass:: Waiter
:members:

View File

@@ -0,0 +1,7 @@
Jabber IDs (JID)
=================
.. module:: slixmpp.jid
.. autoclass:: JID
:members:

View File

@@ -0,0 +1,41 @@
Stanza Matchers
===============
The Basic Matcher
-----------------
.. module:: slixmpp.xmlstream.matcher.base
.. autoclass:: MatcherBase
:members:
ID Matching
-----------
.. module:: slixmpp.xmlstream.matcher.id
.. autoclass:: MatcherId
:members:
Stanza Path Matching
--------------------
.. module:: slixmpp.xmlstream.matcher.stanzapath
.. autoclass:: StanzaPath
:members:
XPath
-----
.. module:: slixmpp.xmlstream.matcher.xpath
.. autoclass:: MatchXPath
:members:
XMLMask
-------
.. module:: slixmpp.xmlstream.matcher.xmlmask
.. autoclass:: MatchXMLMask
:members:

View File

@@ -0,0 +1,123 @@
.. _stanzabase:
==============
Stanza Objects
==============
.. module:: slixmpp.xmlstream.stanzabase
The :mod:`~slixmpp.xmlstream.stanzabase` module provides a wrapper for the
standard :mod:`~xml.etree.ElementTree` module that makes working with XML
less painful. Instead of having to manually move up and down an element
tree and insert subelements and attributes, you can interact with an object
that behaves like a normal dictionary or JSON object, which silently maps
keys to XML attributes and elements behind the scenes.
Overview
--------
The usefulness of this layer grows as the XML you have to work with
becomes nested. The base unit here, :class:`ElementBase`, can map to a
single XML element, or several depending on how advanced of a mapping
is desired from interface keys to XML structures. For example, a single
:class:`ElementBase` derived class could easily describe:
.. code-block:: xml
<message to="user@example.com" from="friend@example.com">
<body>Hi!</body>
<x:extra>
<x:item>Custom item 1</x:item>
<x:item>Custom item 2</x:item>
<x:item>Custom item 3</x:item>
</x:extra>
</message>
If that chunk of XML were put in the :class:`ElementBase` instance
``msg``, we could extract the data from the XML using::
>>> msg['extra']
['Custom item 1', 'Custom item 2', 'Custom item 3']
Provided we set up the handler for the ``'extra'`` interface to load the
``<x:item>`` element content into a list.
The key concept is that given an XML structure that will be repeatedly
used, we can define a set of :term:`interfaces` which when we read from,
write to, or delete, will automatically manipulate the underlying XML
as needed. In addition, some of these interfaces may in turn reference
child objects which expose interfaces for particularly complex child
elements of the original XML chunk.
.. seealso::
:ref:`create-stanza-interfaces`.
Because the :mod:`~slixmpp.xmlstream.stanzabase` module was developed
as part of an `XMPP <http://xmpp.org>`_ library, these chunks of XML are
referred to as :term:`stanzas <stanza>`, and in Slixmpp we refer to a
subclass of :class:`ElementBase` which defines the interfaces needed for
interacting with a given :term:`stanza` a :term:`stanza object`.
To make dealing with more complicated and nested :term:`stanzas <stanza>`
or XML chunks easier, :term:`stanza objects <stanza object>` can be
composed in two ways: as iterable child objects or as plugins. Iterable
child stanzas, or :term:`substanzas <substanza>`, are accessible through a
special ``'substanzas'`` interface. This option is useful for stanzas which
may contain more than one of the same kind of element. When there is
only one child element, the plugin method is more useful. For plugins,
a parent stanza object delegates one of its XML child elements to the
plugin stanza object. Here is an example:
.. code-block:: xml
<iq type="result">
<query xmlns="http://jabber.org/protocol/disco#info">
<identity category="client" type="bot" name="Slixmpp Bot" />
</query>
</iq>
We can can arrange this stanza into two objects: an outer, wrapper object for
dealing with the ``<iq />`` element and its attributes, and a plugin object to
control the ``<query />`` payload element. If we give the plugin object the
name ``'disco_info'`` (using its :attr:`ElementBase.plugin_attrib` value), then
we can access the plugin as so::
>>> iq['disco_info']
'<query xmlns="http://jabber.org/protocol/disco#info">
<identity category="client" type="bot" name="Slixmpp Bot" />
</query>'
We can then drill down through the plugin object's interfaces as desired::
>>> iq['disco_info']['identities']
[('client', 'bot', 'Slixmpp Bot')]
Plugins may also add new interfaces to the parent stanza object as if they
had been defined by the parent directly, and can also override the behaviour
of an interface defined by the parent.
.. seealso::
- :ref:`create-stanza-plugins`
- :ref:`create-extension-plugins`
- :ref:`override-parent-interfaces`
Registering Stanza Plugins
--------------------------
.. autofunction:: register_stanza_plugin
ElementBase
-----------
.. autoclass:: ElementBase
:members:
:private-members:
:special-members:
StanzaBase
----------
.. autoclass:: StanzaBase
:members:

View File

@@ -0,0 +1,47 @@
.. module:: slixmpp.xmlstream.tostring
.. _tostring:
XML Serialization
=================
Since the XML layer of Slixmpp is based on :mod:`~xml.etree.ElementTree`,
why not just use the built-in :func:`~xml.etree.ElementTree.tostring`
method? The answer is that using that method produces ugly results when
using namespaces. The :func:`tostring()` method used here intelligently
hides namespaces when able and does not introduce excessive namespace
prefixes::
>>> from slixmpp.xmlstream.tostring import tostring
>>> from xml.etree import cElementTree as ET
>>> xml = ET.fromstring('<foo xmlns="bar"><baz /></foo>')
>>> ET.tostring(xml)
'<ns0:foo xmlns:ns0="bar"><ns0:baz /></foo>'
>>> tostring(xml)
'<foo xmlns="bar"><baz /></foo>'
As a side effect of this namespace hiding, using :func:`tostring()` may
produce unexpected results depending on how the :func:`tostring()` method
is invoked. For example, when sending XML on the wire, the main XMPP
stanzas with their namespace of ``jabber:client`` will not include the
namespace because that is already declared by the stream header. But, if
you create a :class:`~slixmpp.stanza.message.Message` instance and dump
it to the terminal, the ``jabber:client`` namespace will appear.
.. autofunction:: slixmpp.xmlstream.tostring
Escaping Special Characters
---------------------------
In order to prevent errors when sending arbitrary text as the textual
content of an XML element, certain characters must be escaped. These
are: ``&``, ``<``, ``>``, ``"``, and ``'``. The default escaping
mechanism is to replace those characters with their equivalent escape
entities: ``&amp;``, ``&lt;``, ``&gt;``, ``&apos;``, and ``&quot;``.
In the future, the use of CDATA sections may be allowed to reduce the
size of escaped text or for when other XMPP processing agents do not
undertand these entities.
..
autofunction:: xml_escape

View File

@@ -0,0 +1,8 @@
==========
XML Stream
==========
.. module:: slixmpp.xmlstream.xmlstream
.. autoclass:: XMLStream
:members:

150
docs/architecture.rst Normal file
View File

@@ -0,0 +1,150 @@
.. index:: XMLStream, BaseXMPP, ClientXMPP, ComponentXMPP
Slixmpp Architecture
======================
The core of Slixmpp is contained in four classes: ``XMLStream``,
``BaseXMPP``, ``ClientXMPP``, and ``ComponentXMPP``. Along side this
stack is a library for working with XML objects that eliminates most
of the tedium of creating/manipulating XML.
.. image:: _static/images/arch_layers.png
:height: 300px
:align: center
.. index:: XMLStream
The Foundation: XMLStream
-------------------------
:class:`~slixmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic
class whose purpose is to read and write from a bi-directional XML stream.
It also allows for callback functions to execute when XML matching given
patterns is received; these callbacks are also referred to as :term:`stream
handlers <stream handler>`. The class also provides a basic eventing system
which can be triggered either manually or on a timed schedule.
The event loop
~~~~~~~~~~~~~~
:class:`~slixmpp.xmlstream.xmlstream.XMLStream` instances inherit the
:class:`asyncio.BaseProtocol` class, and therefore do not have to handle
reads and writes directly, but receive data through
:meth:`~slixmpp.xmlstream.xmlstream.XMLStream.data_received` and write
data in the socket transport.
Upon receiving data, :term:`stream handlers <stream handler>` are run
immediately, except if they are coroutines, in which case they are
scheduled using :meth:`asyncio.async`.
:term:`Event handlers <event handler>` (which are called inside
:term:`stream handlers <stream handler>`) work the same way.
How XML Text is Turned into Action
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To demonstrate the flow of information, let's consider what happens
when this bit of XML is received (with an assumed namespace of
``jabber:client``):
.. code-block:: xml
<message to="user@example.com" from="friend@example.net">
<body>Hej!</body>
</message>
#. **Convert XML strings into objects.**
Incoming text is parsed and converted into XML objects (using
ElementTree) which are then wrapped into what are referred to as
:term:`Stanza objects <stanza object>`. The appropriate class for the
new object is determined using a map of namespaced element names to
classes.
Our incoming XML is thus turned into a :class:`~slixmpp.stanza.Message`
:term:`stanza object` because the namespaced element name
``{jabber:client}message`` is associated with the class
:class:`~slixmpp.stanza.Message`.
#. **Match stanza objects to callbacks.**
These objects are then compared against the stored patterns associated
with the registered callback handlers.
Each handler matching our :term:`stanza object` is then added to a list.
#. **Processing callbacks**
Every handler in the list is then called with the :term:`stanza object`
as a parameter; if the handler is a
:class:`~slixmpp.xmlstream.handler.CoroutineCallback`
then it will be scheduled in the event loop using :meth:`asyncio.async`
instead of run.
#. **Raise Custom Events**
Since a :term:`stream handler` shouldn't block, if extensive processing
for a stanza is required (such as needing to send and receive an
:class:`~slixmpp.stanza.Iq` stanza), then custom events must be used.
These events are not explicitly tied to the incoming XML stream and may
be raised at any time.
In contrast to :term:`stream handlers <stream handler>`, these functions
are referred to as :term:`event handlers <event handler>`.
The code for :meth:`BaseXMPP._handle_message` follows this pattern, and
raises a ``'message'`` event
.. code-block:: python
self.event('message', msg)
#. **Process Custom Events**
The :term:`event handlers <event handler>` are then executed, passing
the stanza as the only argument.
.. note::
Events may be raised without needing :term:`stanza objects <stanza object>`.
For example, you could use ``self.event('custom', {'a': 'b'})``.
You don't even need any arguments: ``self.event('no_parameters')``.
However, every event handler MUST accept at least one argument.
Finally, after a long trek, our message is handed off to the user's
custom handler in order to do awesome stuff::
reply = msg.reply()
reply['body'] = "Hey! This is awesome!"
reply.send()
.. index:: BaseXMPP, XMLStream
Raising XMPP Awareness: BaseXMPP
--------------------------------
While :class:`~slixmpp.xmlstream.xmlstream.XMLStream` attempts to shy away
from anything too XMPP specific, :class:`~slixmpp.basexmpp.BaseXMPP`'s
sole purpose is to provide foundational support for sending and receiving
XMPP stanzas. This support includes registering the basic message,
presence, and iq stanzas, methods for creating and sending stanzas, and
default handlers for incoming messages and keeping track of presence
notifications.
The plugin system for adding new XEP support is also maintained by
:class:`~slixmpp.basexmpp.BaseXMPP`.
.. index:: ClientXMPP, BaseXMPP
ClientXMPP
----------
:class:`~slixmpp.clientxmpp.ClientXMPP` extends
:class:`~slixmpp.clientxmpp.BaseXMPP` with additional logic for connecting
to an XMPP server by performing DNS lookups. It also adds support for stream
features such as STARTTLS and SASL.
.. index:: ComponentXMPP, BaseXMPP
ComponentXMPP
-------------
:class:`~slixmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of
:class:`~slixmpp.basexmpp.BaseXMPP` that implements the component handshake
protocol.

222
docs/conf.py Normal file
View File

@@ -0,0 +1,222 @@
# -*- coding: utf-8 -*-
#
# Slixmpp documentation build configuration file, created by
# sphinx-quickstart on Tue Aug 9 22:27:06 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Slixmpp'
copyright = u'2011, Nathan Fritz, Lance Stout'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.1'
# The full version, including alpha/beta/rc tags.
release = '1.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'tango'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'haiku'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {'headingcolor': '#CFCFCF', 'linkcolor': '#4A7389'}
# 00ADEE
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = 'slixmpp'
# A shorter title for the navigation bar. Default is the same as html_title.
html_short_title = '%s Documentation' % release
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
html_additional_pages = {
}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'Slixmppdoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'Slixmpp.tex', u'Slixmpp Documentation',
u'Nathan Fritz, Lance Stout', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'slixmpp', u'Slixmpp Documentation',
[u'Nathan Fritz, Lance Stout'], 1)
]
intersphinx_mapping = {'python': ('http://docs.python.org/3.4', 'python-objects.inv')}

682
docs/create_plugin.rst Normal file
View File

@@ -0,0 +1,682 @@
.. _create-plugin:
Creating a Slixmpp Plugin
===========================
One of the goals of Slixmpp is to provide support for every draft or final
XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, Slixmpp has a
plugin mechanism for adding the functionalities required by each XEP. But even
though plugins were made to quickly implement and prototype the official XMPP
extensions, there is no reason you can't create your own plugin to implement
your own custom XMPP-based protocol.
This guide will help walk you through the steps to
implement a rudimentary version of `XEP-0077 In-band
Registration <http://xmpp.org/extensions/xep-0077.html>`_. In-band registration
was implemented in example 14-6 (page 223) of `XMPP: The Definitive
Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no Slixmpp
plugin for XEP-0077 at the time of writing. We will partially fix that issue
here by turning the example implementation from *XMPP: The Definitive Guide*
into a plugin. Again, note that this will not a complete implementation, and a
different, more robust, official plugin for XEP-0077 may be added to Slixmpp
in the future.
.. note::
The example plugin created in this guide is for the server side of the
registration process only. It will **NOT** be able to register new accounts
on an XMPP server.
First Steps
-----------
Every plugin inherits from the class :mod:`BasePlugin <slixmpp.plugins.base.BasePlugin`,
and must include a ``plugin_init`` method. While the
plugins distributed with Slixmpp must be placed in the plugins directory
``slixmpp/plugins`` to be loaded, custom plugins may be loaded from any
module. To do so, use the following form when registering the plugin:
.. code-block:: python
self.register_plugin('myplugin', module=mod_containing_my_plugin)
The plugin name must be the same as the plugin's class name.
Now, we can open our favorite text editors and create ``xep_0077.py`` in
``Slixmpp/slixmpp/plugins``. We want to do some basic house-keeping and
declare the name and description of the XEP we are implementing. If you
are creating your own custom plugin, you don't need to include the ``xep``
attribute.
.. code-block:: python
"""
Creating a Slixmpp Plugin
This is a minimal implementation of XEP-0077 to serve
as a tutorial for creating Slixmpp plugins.
"""
from slixmpp.plugins.base import BasePlugin
class xep_0077(BasePlugin):
"""
XEP-0077 In-Band Registration
"""
def plugin_init(self):
self.description = "In-Band Registration"
self.xep = "0077"
Now that we have a basic plugin, we need to edit
``slixmpp/plugins/__init__.py`` to include our new plugin by adding
``'xep_0077'`` to the ``__all__`` declaration.
Interacting with Other Plugins
------------------------------
In-band registration is a feature that should be advertised through `Service
Discovery <http://xmpp.org/extensions/xep-0030.html>`_. To do that, we tell the
``xep_0030`` plugin to add the ``"jabber:iq:register"`` feature. We put this
call in a method named ``post_init`` which will be called once the plugin has
been loaded; by doing so we advertise that we can do registrations only after we
finish activating the plugin.
The ``post_init`` method needs to call ``BasePlugin.post_init(self)``
which will mark that ``post_init`` has been called for the plugin. Once the
Slixmpp object begins processing, ``post_init`` will be called on any plugins
that have not already run ``post_init``. This allows you to register plugins and
their dependencies without needing to worry about the order in which you do so.
**Note:** by adding this call we have introduced a dependency on the XEP-0030
plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. Slixmpp
does not automatically load plugin dependencies for you.
.. code-block:: python
def post_init(self):
BasePlugin.post_init(self)
self.xmpp['xep_0030'].add_feature("jabber:iq:register")
Creating Custom Stanza Objects
------------------------------
Now, the IQ stanzas needed to implement our version of XEP-0077 are not very
complex, and we could just interact with the XML objects directly just like
in the *XMPP: The Definitive Guide* example. However, creating custom stanza
objects is good practice.
We will create a new ``Registration`` stanza. Following the *XMPP: The
Definitive Guide* example, we will add support for a username and password
field. We also need two flags: ``registered`` and ``remove``. The ``registered``
flag is sent when an already registered user attempts to register, along with
their registration data. The ``remove`` flag is a request to unregister a user's
account.
Adding additional `fields specified in
XEP-0077 <http://xmpp.org/extensions/xep-0077.html#registrar-formtypes-register>`_
will not be difficult and is left as an exercise for the reader.
Our ``Registration`` class needs to start with a few descriptions of its
behaviour:
* ``namespace``
The namespace our stanza object lives in. In this case,
``"jabber:iq:register"``.
* ``name``
The name of the root XML element. In this case, the ``query`` element.
* ``plugin_attrib``
The name to access this type of stanza. In particular, given a
registration stanza, the ``Registration`` object can be found using:
``iq_object['register']``.
* ``interfaces``
A list of dictionary-like keys that can be used with the stanza object.
When using ``"key"``, if there exists a method of the form ``getKey``,
``setKey``, or``delKey`` (depending on context) then the result of calling
that method will be returned. Otherwise, the value of the attribute ``key``
of the main stanza element is returned if one exists.
**Note:** The accessor methods currently use title case, and not camel case.
Thus if you need to access an item named ``"methodName"`` you will need to
use ``getMethodname``. This naming convention might change to full camel
case in a future version of Slixmpp.
* ``sub_interfaces``
A subset of ``interfaces``, but these keys map to the text of any
subelements that are direct children of the main stanza element. Thus,
referencing ``iq_object['register']['username']`` will either execute
``getUsername`` or return the value in the ``username`` element of the
query.
If you need to access an element, say ``elem``, that is not a direct child
of the main stanza element, you will need to add ``getElem``, ``setElem``,
and ``delElem``. See the note above about naming conventions.
.. code-block:: python
from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
from slixmpp import Iq
class Registration(ElementBase):
namespace = 'jabber:iq:register'
name = 'query'
plugin_attrib = 'register'
interfaces = set(('username', 'password', 'registered', 'remove'))
sub_interfaces = interfaces
def getRegistered(self):
present = self.xml.find('{%s}registered' % self.namespace)
return present is not None
def getRemove(self):
present = self.xml.find('{%s}remove' % self.namespace)
return present is not None
def setRegistered(self, registered):
if registered:
self.addField('registered')
else:
del self['registered']
def setRemove(self, remove):
if remove:
self.addField('remove')
else:
del self['remove']
def addField(self, name):
itemXML = ET.Element('{%s}%s' % (self.namespace, name))
self.xml.append(itemXML)
Setting a ``sub_interface`` attribute to ``""`` will remove that subelement.
Since we want to include empty registration fields in our form, we need the
``addField`` method to add the empty elements.
Since the ``registered`` and ``remove`` elements are just flags, we need to add
custom logic to enforce the binary behavior.
Extracting Stanzas from the XML Stream
--------------------------------------
Now that we have a custom stanza object, we need to be able to detect when we
receive one. To do this, we register a stream handler that will pattern match
stanzas off of the XML stream against our stanza object's element name and
namespace. To do so, we need to create a ``Callback`` object which contains
an XML fragment that can identify our stanza type. We can add this handler
registration to our ``plugin_init`` method.
Also, we need to associate our ``Registration`` class with IQ stanzas;
that requires the use of the ``register_stanza_plugin`` function (in
``slixmpp.xmlstream.stanzabase``) which takes the class of a parent stanza
type followed by the substanza type. In our case, the parent stanza is an IQ
stanza, and the substanza is our registration query.
The ``__handleRegistration`` method referenced in the callback will be our
handler function to process registration requests.
.. code-block:: python
def plugin_init(self):
self.description = "In-Band Registration"
self.xep = "0077"
self.xmpp.register_handler(
Callback('In-Band Registration',
MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns),
self.__handleRegistration))
register_stanza_plugin(Iq, Registration)
Handling Incoming Stanzas and Triggering Events
-----------------------------------------------
There are six situations that we need to handle to finish our implementation of
XEP-0077.
**Registration Form Request from a New User:**
.. code-block:: xml
<iq type="result">
<query xmlns="jabber:iq:register">
<username />
<password />
</query>
</iq>
**Registration Form Request from an Existing User:**
.. code-block:: xml
<iq type="result">
<query xmlns="jabber:iq:register">
<registered />
<username>Foo</username>
<password>hunter2</password>
</query>
</iq>
**Unregister Account:**
.. code-block:: xml
<iq type="result">
<query xmlns="jabber:iq:register" />
</iq>
**Incomplete Registration:**
.. code-block:: xml
<iq type="error">
<query xmlns="jabber:iq:register">
<username>Foo</username>
</query>
<error code="406" type="modify">
<not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
</error>
</iq>
**Conflicting Registrations:**
.. code-block:: xml
<iq type="error">
<query xmlns="jabber:iq:register">
<username>Foo</username>
<password>hunter2</password>
</query>
<error code="409" type="cancel">
<conflict xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
</error>
</iq>
**Successful Registration:**
.. code-block:: xml
<iq type="result">
<query xmlns="jabber:iq:register" />
</iq>
Cases 1 and 2: Registration Requests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Responding to registration requests depends on if the requesting user already
has an account. If there is an account, the response should include the
``registered`` flag and the user's current registration information. Otherwise,
we just send the fields for our registration form.
We will handle both cases by creating a ``sendRegistrationForm`` method that
will create either an empty of full form depending on if we provide it with
user data. Since we need to know which form fields to include (especially if we
add support for the other fields specified in XEP-0077), we will also create a
method ``setForm`` which will take the names of the fields we wish to include.
.. code-block:: python
def plugin_init(self):
self.description = "In-Band Registration"
self.xep = "0077"
self.form_fields = ('username', 'password')
... remainder of plugin_init
...
def __handleRegistration(self, iq):
if iq['type'] == 'get':
# Registration form requested
userData = self.backend[iq['from'].bare]
self.sendRegistrationForm(iq, userData)
def setForm(self, *fields):
self.form_fields = fields
def sendRegistrationForm(self, iq, userData=None):
reg = iq['register']
if userData is None:
userData = {}
else:
reg['registered'] = True
for field in self.form_fields:
data = userData.get(field, '')
if data:
# Add field with existing data
reg[field] = data
else:
# Add a blank field
reg.addField(field)
iq.reply().set_payload(reg.xml)
iq.send()
Note how we are able to access our ``Registration`` stanza object with
``iq['register']``.
A User Backend
++++++++++++++
You might have noticed the reference to ``self.backend``, which is an object
that abstracts away storing and retrieving user information. Since it is not
much more than a dictionary, we will leave the implementation details to the
final, full source code example.
Case 3: Unregister an Account
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The next simplest case to consider is responding to a request to remove
an account. If we receive a ``remove`` flag, we instruct the backend to
remove the user's account. Since your application may need to know about
when users are registered or unregistered, we trigger an event using
``self.xmpp.event('unregister_user', iq)``. See the component examples below for
how to respond to that event.
.. code-block:: python
def __handleRegistration(self, iq):
if iq['type'] == 'get':
# Registration form requested
userData = self.backend[iq['from'].bare]
self.sendRegistrationForm(iq, userData)
elif iq['type'] == 'set':
# Remove an account
if iq['register']['remove']:
self.backend.unregister(iq['from'].bare)
self.xmpp.event('unregistered_user', iq)
iq.reply().send()
return
Case 4: Incomplete Registration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For the next case we need to check the user's registration to ensure it has all
of the fields we wanted. The simple option that we will use is to loop over the
field names and check each one; however, this means that all fields we send to
the user are required. Adding optional fields is left to the reader.
Since we have received an incomplete form, we need to send an error message back
to the user. We have to send a few different types of errors, so we will also
create a ``_sendError`` method that will add the appropriate ``error`` element
to the IQ reply.
.. code-block:: python
def __handleRegistration(self, iq):
if iq['type'] == 'get':
# Registration form requested
userData = self.backend[iq['from'].bare]
self.sendRegistrationForm(iq, userData)
elif iq['type'] == 'set':
if iq['register']['remove']:
# Remove an account
self.backend.unregister(iq['from'].bare)
self.xmpp.event('unregistered_user', iq)
iq.reply().send()
return
for field in self.form_fields:
if not iq['register'][field]:
# Incomplete Registration
self._sendError(iq, '406', 'modify', 'not-acceptable'
"Please fill in all fields.")
return
...
def _sendError(self, iq, code, error_type, name, text=''):
iq.reply().set_payload(iq['register'].xml)
iq.error()
iq['error']['code'] = code
iq['error']['type'] = error_type
iq['error']['condition'] = name
iq['error']['text'] = text
iq.send()
Cases 5 and 6: Conflicting and Successful Registration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We are down to the final decision on if we have a successful registration. We
send the user's data to the backend with the ``self.backend.register`` method.
If it returns ``True``, then registration has been successful. Otherwise,
there has been a conflict with usernames and registration has failed. Like
with unregistering an account, we trigger an event indicating that a user has
been registered by using ``self.xmpp.event('registered_user', iq)``. See the
component examples below for how to respond to this event.
.. code-block:: python
def __handleRegistration(self, iq):
if iq['type'] == 'get':
# Registration form requested
userData = self.backend[iq['from'].bare]
self.sendRegistrationForm(iq, userData)
elif iq['type'] == 'set':
if iq['register']['remove']:
# Remove an account
self.backend.unregister(iq['from'].bare)
self.xmpp.event('unregistered_user', iq)
iq.reply().send()
return
for field in self.form_fields:
if not iq['register'][field]:
# Incomplete Registration
self._sendError(iq, '406', 'modify', 'not-acceptable',
"Please fill in all fields.")
return
if self.backend.register(iq['from'].bare, iq['register']):
# Successful registration
self.xmpp.event('registered_user', iq)
iq.reply().set_payload(iq['register'].xml)
iq.send()
else:
# Conflicting registration
self._sendError(iq, '409', 'cancel', 'conflict',
"That username is already taken.")
Example Component Using the XEP-0077 Plugin
-------------------------------------------
Alright, the moment we've been working towards - actually using our plugin to
simplify our other applications. Here is a basic component that simply manages
user registrations and sends the user a welcoming message when they register,
and a farewell message when they delete their account.
Note that we have to register the ``'xep_0030'`` plugin first,
and that we specified the form fields we wish to use with
``self.xmpp.plugin['xep_0077'].setForm('username', 'password')``.
.. code-block:: python
import slixmpp.componentxmpp
class Example(slixmpp.componentxmpp.ComponentXMPP):
def __init__(self, jid, password):
slixmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888)
self.register_plugin('xep_0030')
self.register_plugin('xep_0077')
self.plugin['xep_0077'].setForm('username', 'password')
self.add_event_handler("registered_user", self.reg)
self.add_event_handler("unregistered_user", self.unreg)
def reg(self, iq):
msg = "Welcome! %s" % iq['register']['username']
self.send_message(iq['from'], msg, mfrom=self.fulljid)
def unreg(self, iq):
msg = "Bye! %s" % iq['register']['username']
self.send_message(iq['from'], msg, mfrom=self.fulljid)
**Congratulations!** We now have a basic, functioning implementation of
XEP-0077.
Complete Source Code for XEP-0077 Plugin
----------------------------------------
Here is a copy of a more complete implementation of the plugin we created, but
with some additional registration fields implemented.
.. code-block:: python
"""
Creating a Slixmpp Plugin
This is a minimal implementation of XEP-0077 to serve
as a tutorial for creating Slixmpp plugins.
"""
from slixmpp.plugins.base import BasePlugin
from slixmpp.xmlstream.handler.callback import Callback
from slixmpp.xmlstream.matcher.xpath import MatchXPath
from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
from slixmpp import Iq
import copy
class Registration(ElementBase):
namespace = 'jabber:iq:register'
name = 'query'
plugin_attrib = 'register'
interfaces = set(('username', 'password', 'email', 'nick', 'name',
'first', 'last', 'address', 'city', 'state', 'zip',
'phone', 'url', 'date', 'misc', 'text', 'key',
'registered', 'remove', 'instructions'))
sub_interfaces = interfaces
def getRegistered(self):
present = self.xml.find('{%s}registered' % self.namespace)
return present is not None
def getRemove(self):
present = self.xml.find('{%s}remove' % self.namespace)
return present is not None
def setRegistered(self, registered):
if registered:
self.addField('registered')
else:
del self['registered']
def setRemove(self, remove):
if remove:
self.addField('remove')
else:
del self['remove']
def addField(self, name):
itemXML = ET.Element('{%s}%s' % (self.namespace, name))
self.xml.append(itemXML)
class UserStore(object):
def __init__(self):
self.users = {}
def __getitem__(self, jid):
return self.users.get(jid, None)
def register(self, jid, registration):
username = registration['username']
def filter_usernames(user):
return user != jid and self.users[user]['username'] == username
conflicts = filter(filter_usernames, self.users.keys())
if conflicts:
return False
self.users[jid] = registration
return True
def unregister(self, jid):
del self.users[jid]
class xep_0077(BasePlugin):
"""
XEP-0077 In-Band Registration
"""
def plugin_init(self):
self.description = "In-Band Registration"
self.xep = "0077"
self.form_fields = ('username', 'password')
self.form_instructions = ""
self.backend = UserStore()
self.xmpp.register_handler(
Callback('In-Band Registration',
MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns),
self.__handleRegistration))
register_stanza_plugin(Iq, Registration)
def post_init(self):
BasePlugin.post_init(self)
self.xmpp['xep_0030'].add_feature("jabber:iq:register")
def __handleRegistration(self, iq):
if iq['type'] == 'get':
# Registration form requested
userData = self.backend[iq['from'].bare]
self.sendRegistrationForm(iq, userData)
elif iq['type'] == 'set':
if iq['register']['remove']:
# Remove an account
self.backend.unregister(iq['from'].bare)
self.xmpp.event('unregistered_user', iq)
iq.reply().send()
return
for field in self.form_fields:
if not iq['register'][field]:
# Incomplete Registration
self._sendError(iq, '406', 'modify', 'not-acceptable',
"Please fill in all fields.")
return
if self.backend.register(iq['from'].bare, iq['register']):
# Successful registration
self.xmpp.event('registered_user', iq)
reply = iq.reply()
reply.set_payload(iq['register'].xml)
reply.send()
else:
# Conflicting registration
self._sendError(iq, '409', 'cancel', 'conflict',
"That username is already taken.")
def setForm(self, *fields):
self.form_fields = fields
def setInstructions(self, instructions):
self.form_instructions = instructions
def sendRegistrationForm(self, iq, userData=None):
reg = iq['register']
if userData is None:
userData = {}
else:
reg['registered'] = True
if self.form_instructions:
reg['instructions'] = self.form_instructions
for field in self.form_fields:
data = userData.get(field, '')
if data:
# Add field with existing data
reg[field] = data
else:
# Add a blank field
reg.addField(field)
reply = iq.reply()
reply.set_payload(reg.xml)
reply.send()
def _sendError(self, iq, code, error_type, name, text=''):
reply = iq.reply()
reply.set_payload(iq['register'].xml)
reply.error()
reply['error']['code'] = code
reply['error']['type'] = error_type
reply['error']['condition'] = name
reply['error']['text'] = text
reply.send()

47
docs/differences.rst Normal file
View File

@@ -0,0 +1,47 @@
.. _differences:
Differences from SleekXMPP
==========================
**Python 3.4+ only**
slixmpp will only work on python 3.4 and above.
**Stanza copies**
The same stanza object is given through all the handlers; a handler that
edits the stanza object should make its own copy.
**Replies**
Because stanzas are not copied anymore,
:meth:`Stanza.reply() <.StanzaBase.reply>` calls
(for :class:`IQs <.Iq>`, :class:`Messages <.Message>`, etc)
now return a new object instead of editing the stanza object
in-place.
**Block and threaded arguments**
All the functions that had a ``threaded=`` or ``block=`` argument
do not have it anymore. Also, :meth:`.Iq.send` **does not block
anymore**.
**Coroutine facilities**
**See** :ref:`using_asyncio`
If an event handler is a coroutine, it will be called asynchronously
in the event loop instead of inside the event caller.
A CoroutineCallback class has been added to create coroutine stream
handlers, which will be also handled in the event loop.
The :class:`~.slixmpp.stanza.Iq` objects :meth:`~.slixmpp.stanza.Iq.send`
method now **always** return a :class:`~.asyncio.Future` which result will be set
to the IQ reply when it is received, or to ``None`` if the IQ is not of
type ``get`` or ``set``.
Many plugins (WIP) calls which retrieve information also return the same
future.
**Architectural differences**
slixmpp does not have an event queue anymore, and instead processes
handlers directly after receiving the XML stanza.
.. note::
If you find something that doesnt work but should, please report it.

282
docs/event_index.rst Normal file
View File

@@ -0,0 +1,282 @@
Event Index
===========
.. glossary::
:sorted:
connected
- **Data:** ``{}``
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
Signal that a connection has been made with the XMPP server, but a session
has not yet been established.
connection_failed
- **Data:** ``{}`` or ``Failure Stanza`` if available
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
Signal that a connection can not be established after number of attempts.
changed_status
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.roster.item.RosterItem`
Triggered when a presence stanza is received from a JID with a show type
different than the last presence stanza from the same JID.
changed_subscription
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
Triggered whenever a presence stanza with a type of ``subscribe``,
``subscribed``, ``unsubscribe``, or ``unsubscribed`` is received.
Note that if the values ``xmpp.auto_authorize`` and ``xmpp.auto_subscribe``
are set to ``True`` or ``False``, and not ``None``, then Slixmpp will
either accept or reject all subscription requests before your event handlers
are called. Set these values to ``None`` if you wish to make more complex
subscription decisions.
chatstate_active
- **Data:**
- **Source:**
chatstate_composing
- **Data:**
- **Source:**
chatstate_gone
- **Data:**
- **Source:**
chatstate_inactive
- **Data:**
- **Source:**
chatstate_paused
- **Data:**
- **Source:**
disco_info
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoInfo`
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
Triggered whenever a ``disco#info`` result stanza is received.
disco_items
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoItems`
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
Triggered whenever a ``disco#items`` result stanza is received.
disconnected
- **Data:** ``{}``
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
Signal that the connection with the XMPP server has been lost.
entity_time
- **Data:**
- **Source:**
failed_auth
- **Data:** ``{}``
- **Source:** :py:class:`~slixmpp.ClientXMPP`, :py:class:`~slixmpp.plugins.xep_0078.xep_0078`
Signal that the server has rejected the provided login credentials.
gmail_notify
- **Data:** ``{}``
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
gmail_messages
- **Data:** :py:class:`~slixmpp.Iq`
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
got_online
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.roster.item.RosterItem`
If a presence stanza is received from a JID which was previously marked as
offline, and the presence has a show type of '``chat``', '``dnd``', '``away``',
or '``xa``', then this event is triggered as well.
got_offline
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.roster.item.RosterItem`
Signal that an unavailable presence stanza has been received from a JID.
groupchat_invite
- **Data:**
- **Source:**
groupchat_direct_invite
- **Data:** :py:class:`~slixmpp.Message`
- **Source:** :py:class:`~slixmpp.plugins.xep_0249.direct`
groupchat_message
- **Data:** :py:class:`~slixmpp.Message`
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
Triggered whenever a message is received from a multi-user chat room.
groupchat_presence
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
Triggered whenever a presence stanza is received from a user in a multi-user chat room.
groupchat_subject
- **Data:** :py:class:`~slixmpp.Message`
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
Triggered whenever the subject of a multi-user chat room is changed, or announced when joining a room.
killed
- **Data:**
- **Source:**
last_activity
- **Data:**
- **Source:**
message
- **Data:** :py:class:`~slixmpp.Message`
- **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>`
Makes the contents of message stanzas available whenever one is received. Be
sure to check the message type in order to handle error messages.
message_error
- **Data:** :py:class:`~slixmpp.Message`
- **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>`
Makes the contents of message stanzas available whenever one is received.
Only handler messages with an ``error`` type.
message_form
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
Currently the same as :term:`message_xform`.
message_xform
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
Triggered whenever a data form is received inside a message.
muc::[room]::got_offline
- **Data:**
- **Source:**
muc::[room]::got_online
- **Data:**
- **Source:**
muc::[room]::message
- **Data:**
- **Source:**
muc::[room]::presence
- **Data:**
- **Source:**
presence_available
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``available``' is received.
presence_error
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``error``' is received.
presence_form
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
This event is present in the XEP-0004 plugin code, but is currently not used.
presence_probe
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``probe``' is received.
presence_subscribe
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``subscribe``' is received.
presence_subscribed
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``subscribed``' is received.
presence_unavailable
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``unavailable``' is received.
presence_unsubscribe
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``unsubscribe``' is received.
presence_unsubscribed
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``unsubscribed``' is received.
roster_update
- **Data:** :py:class:`~slixmpp.stanza.Roster`
- **Source:** :py:class:`~slixmpp.ClientXMPP`
An IQ result containing roster entries is received.
sent_presence
- **Data:** ``{}``
- **Source:** :py:class:`~slixmpp.roster.multi.Roster`
Signal that an initial presence stanza has been written to the XML stream.
session_end
- **Data:** ``{}``
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
Signal that a connection to the XMPP server has been lost and the current
stream session has ended. Currently equivalent to :term:`disconnected`, but
implementations of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
distinguish between the two events.
Plugins that maintain session-based state should clear themselves when
this event is fired.
session_start
- **Data:** ``{}``
- **Source:** :py:class:`ClientXMPP <slixmpp.ClientXMPP>`,
:py:class:`ComponentXMPP <slixmpp.ComponentXMPP>`
:py:class:`XEP-0078 <slixmpp.plugins.xep_0078>`
Signal that a connection to the XMPP server has been made and a session has been established.
socket_error
- **Data:** ``Socket`` exception object
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
stream_error
- **Data:** :py:class:`~slixmpp.stanza.StreamError`
- **Source:** :py:class:`~slixmpp.BaseXMPP`

2
docs/features.rst Normal file
View File

@@ -0,0 +1,2 @@
How to Use Stream Features
==========================

View File

@@ -0,0 +1,67 @@
.. _echocomponent:
=================================
Create and Run a Server Component
=================================
.. note::
If you have any issues working through this quickstart guide
join the chat room at `slixmpp@muc.poez.io
<xmpp:slixmpp@muc.poez.io?join>`_.
If you have not yet installed Slixmpp, do so now by either checking out a version
with `Git <http://git.poez.io/slixmpp>`_.
Many XMPP applications eventually graduate to requiring to run as a server
component in order to meet scalability requirements. To demonstrate how to
turn an XMPP client bot into a component, we'll turn the echobot example
(:ref:`echobot`) into a component version.
The first difference is that we will add an additional import statement:
.. code-block:: python
from slixmpp.componentxmpp import ComponentXMPP
Likewise, we will change the bot's class definition to match:
.. code-block:: python
class EchoComponent(ComponentXMPP):
def __init__(self, jid, secret, server, port):
ComponentXMPP.__init__(self, jid, secret, server, port)
A component instance requires two extra parameters compared to a client
instance: ``server`` and ``port``. These specifiy the name and port of
the XMPP server that will be accepting the component. For example, for
a MUC component, the following could be used:
.. code-block:: python
muc = ComponentXMPP('muc.slixmpp.com', '******', 'slixmpp.com', 5555)
.. note::
The ``server`` value is **NOT** derived from the provided JID for the
component, unlike with client connections.
One difference with the component version is that we do not have
to handle the :term:`session_start` event if we don't wish to deal
with presence.
The other, main difference with components is that the
``'from'`` value for every stanza must be explicitly set, since
components may send stanzas from multiple JIDs. To do so,
the :meth:`~slixmpp.basexmpp.BaseXMPP.send_message()` and
:meth:`~slixmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters
``mfrom`` and ``pfrom``, respectively. For any method that uses
:class:`~slixmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used.
Final Product
-------------
.. include:: ../../examples/echo_component.py
:literal:

View File

@@ -0,0 +1,349 @@
.. _echobot:
===============================
Slixmpp Quickstart - Echo Bot
===============================
.. note::
If you have any issues working through this quickstart guide
join the chat room at `slixmpp@muc.poez.io
<xmpp:slixmpp@muc.poez.io?join>`_.
If you have not yet installed Slixmpp, do so now by either checking out a version
with `Git <http://git.poez.io/slixmpp>`_.
As a basic starting project, we will create an echo bot which will reply to any
messages sent to it. We will also go through adding some basic command line configuration
for enabling or disabling debug log outputs and setting the username and password
for the bot.
For the command line options processing, we will use the built-in ``optparse``
module and the ``getpass`` module for reading in passwords.
TL;DR Just Give Me the Code
---------------------------
As you wish: :ref:`the completed example <echobot_complete>`.
Overview
--------
To get started, here is a brief outline of the structure that the final project will have:
.. code-block:: python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import asyncio
import logging
import getpass
from optparse import OptionParser
import slixmpp
'''Here we will create out echo bot class'''
if __name__ == '__main__':
'''Here we will configure and read command line options'''
'''Here we will instantiate our echo bot'''
'''Finally, we connect the bot and start listening for messages'''
Creating the EchoBot Class
--------------------------
There are three main types of entities within XMPP — servers, components, and
clients. Since our echo bot will only be responding to a few people, and won't need
to remember thousands of users, we will use a client connection. A client connection
is the same type that you use with your standard IM client such as Pidgin or Psi.
Slixmpp comes with a :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` class
which we can extend to add our message echoing feature. :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>`
requires the parameters ``jid`` and ``password``, so we will let our ``EchoBot`` class accept those
as well.
.. code-block:: python
class EchoBot(slixmpp.ClientXMPP):
def __init__(self, jid, password):
super().__init__(jid, password)
Handling Session Start
~~~~~~~~~~~~~~~~~~~~~~
The XMPP spec requires clients to broadcast its presence and retrieve its roster (buddy list) once
it connects and establishes a session with the XMPP server. Until these two tasks are completed,
some servers may not deliver or send messages or presence notifications to the client. So we now
need to be sure that we retrieve our roster and send an initial presence once the session has
started. To do that, we will register an event handler for the :term:`session_start` event.
.. code-block:: python
def __init__(self, jid, password):
super().__init__(jid, password)
self.add_event_handler('session_start', self.start)
Since we want the method ``self.start`` to execute when the :term:`session_start` event is triggered,
we also need to define the ``self.start`` handler.
.. code-block:: python
def start(self, event):
self.send_presence()
self.get_roster()
.. warning::
Not sending an initial presence and retrieving the roster when using a client instance can
prevent your program from receiving presence notifications or messages depending on the
XMPP server you have chosen.
Our event handler, like every event handler, accepts a single parameter which typically is the stanza
that was received that caused the event. In this case, ``event`` will just be an empty dictionary since
there is no associated data.
Our first task of sending an initial presence is done using :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>`.
Calling :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest
stanza allowed in XMPP:
.. code-block:: xml
<presence />
The second requirement is fulfilled using :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>`, which
will send an IQ stanza requesting the roster to the server and then wait for the response. You may be wondering
what :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return
value. The roster data is saved by an internal handler to ``self.roster``, and in the case of a :class:`ClientXMPP
<slixmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and
``self.client_roster`` is that ``self.roster`` supports storing roster information for multiple JIDs, which is useful
for components, whereas ``self.client_roster`` stores roster data for just the client's JID.)
It is possible for a timeout to occur while waiting for the server to respond, which can happen if the
network is excessively slow or the server is no longer responding. In that case, an :class:`IQTimeout
<slixmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <slixmpp.exceptions.IQError>` exception can
be raised if the request contained bad data or requested the roster for the wrong user. In either case, you can wrap the
``get_roster()`` call in a ``try``/``except`` block to retry the roster retrieval process.
The XMPP stanzas from the roster retrieval process could look like this:
.. code-block:: xml
<iq type="get">
<query xmlns="jabber:iq:roster" />
</iq>
<iq type="result" to="echobot@example.com" from="example.com">
<query xmlns="jabber:iq:roster">
<item jid="friend@example.com" subscription="both" />
</query>
</iq>
Responding to Messages
~~~~~~~~~~~~~~~~~~~~~~
Now that an ``EchoBot`` instance handles :term:`session_start`, we can begin receiving and
responding to messages. Now we can register a handler for the :term:`message` event that is raised
whenever a messsage is received.
.. code-block:: python
def __init__(self, jid, password):
super().__init__(jid, password)
self.add_event_handler('session_start', self.start)
self.add_event_handler('message', self.message)
The :term:`message` event is fired whenever a ``<message />`` stanza is received, including for
group chat messages, errors, etc. Properly responding to messages thus requires checking the
``'type'`` interface of the message :term:`stanza object`. For responding to only messages
addressed to our bot (and not from a chat room), we check that the type is either ``normal``
or ``chat``. (Other potential types are ``error``, ``headline``, and ``groupchat``.)
.. code-block:: python
def message(self, msg):
if msg['type'] in ('normal', 'chat'):
msg.reply("Thanks for sending:\n%s" % msg['body']).send()
Let's take a closer look at the ``.reply()`` method used above. For message stanzas,
``.reply()`` accepts the parameter ``body`` (also as the first positional argument),
which is then used as the value of the ``<body />`` element of the message.
Setting the appropriate ``to`` JID is also handled by ``.reply()``.
Another way to have sent the reply message would be to use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`,
which is a convenience method for generating and sending a message based on the values passed to it. If we were to use
this method, the above code would look as so:
.. code-block:: python
def message(self, msg):
if msg['type'] in ('normal', 'chat'):
self.send_message(mto=msg['from'],
mbody='Thanks for sending:\n%s' % msg['body'])
Whichever method you choose to use, the results in action will look like this:
.. code-block:: xml
<message to="echobot@example.com" from="someuser@example.net" type="chat">
<body>Hej!</body>
</message>
<message to="someuser@example.net" type="chat">
<body>Thanks for sending:
Hej!</body>
</message>
.. note::
XMPP does not require stanzas sent by a client to include a ``from`` attribute, and
leaves that responsibility to the XMPP server. However, if a sent stanza does
include a ``from`` attribute, it must match the full JID of the client or some
servers will reject it. Slixmpp thus leaves out the ``from`` attribute when replying
using a client connection.
Command Line Arguments and Logging
----------------------------------
While this isn't part of Slixmpp itself, we do want our echo bot program to be able
to accept a JID and password from the command line instead of hard coding them. We will
use the ``optparse`` module for this, though there are several alternative methods, including
the newer ``argparse`` module.
We want to accept three parameters: the JID for the echo bot, its password, and a flag for
displaying the debugging logs. We also want these to be optional parameters, since passing
a password directly through the command line can be a security risk.
.. code-block:: python
if __name__ == '__main__':
optp = OptionParser()
optp.add_option('-d', '--debug', help='set logging to DEBUG',
action='store_const', dest='loglevel',
const=logging.DEBUG, default=logging.INFO)
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
opts, args = optp.parse_args()
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
Since we included a flag for enabling debugging logs, we need to configure the
``logging`` module to behave accordingly.
.. code-block:: python
if __name__ == '__main__':
# .. option parsing from above ..
logging.basicConfig(level=opts.loglevel,
format='%(levelname)-8s %(message)s')
Connecting to the Server and Processing
---------------------------------------
There are three steps remaining until our echo bot is complete:
1. We need to instantiate the bot.
2. The bot needs to connect to an XMPP server.
3. We have to instruct the bot to start running and processing messages.
Creating the bot is straightforward, but we can also perform some configuration
at this stage. For example, let's say we want our bot to support `service discovery
<http://xmpp.org/extensions/xep-0030.html>`_ and `pings <http://xmpp.org/extensions/xep-0199.html>`_:
.. code-block:: python
if __name__ == '__main__':
# .. option parsing and logging steps from above
xmpp = EchoBot(opts.jid, opts.password)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0199') # Ping
If the ``EchoBot`` class had a hard dependency on a plugin, we could register that plugin in
the ``EchoBot.__init__`` method instead.
.. note::
If you are using the OpenFire server, you will need to include an additional
configuration step. OpenFire supports a different version of SSL than what
most servers and Slixmpp support.
.. code-block:: python
import ssl
xmpp.ssl_version = ssl.PROTOCOL_SSLv3
Now we're ready to connect and begin echoing messages. If you have the package
``aiodns`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method
will perform a DNS query to find the appropriate server to connect to for the
given JID. If you do not have ``aiodns``, then Slixmpp will attempt to
connect to the hostname used by the JID, unless an address tuple is supplied
to :meth:`slixmpp.clientxmpp.ClientXMPP`.
.. code-block:: python
if __name__ == '__main__':
# .. option parsing & echo bot configuration
if xmpp.connect():
xmpp.process(block=True)
else:
print('Unable to connect')
To begin responding to messages, you'll see we called :meth:`slixmpp.basexmpp.BaseXMPP.process`
which will start the event handling, send queue, and XML reader threads. It will also call
the :meth:`slixmpp.plugins.base.BasePlugin.post_init` method on all registered plugins. By
passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the
main processing loop in the main thread of execution. The :meth:`slixmpp.basexmpp.BaseXMPP.process`
call will not return until after Slixmpp disconnects. If you need to run the client in the background
for another program, use ``block=False`` to spawn the processing loop in its own thread.
.. note::
Before 1.0, controlling the blocking behaviour of :meth:`slixmpp.basexmpp.BaseXMPP.process` was
done via the ``threaded`` argument. This arrangement was a source of confusion because some users
interpreted that as controlling whether or not Slixmpp used threads at all, instead of how
the processing loop itself was spawned.
The statements ``xmpp.process(threaded=False)`` and ``xmpp.process(block=True)`` are equivalent.
.. _echobot_complete:
The Final Product
-----------------
Here then is what the final result should look like after working through the guide above. The code
can also be found in the Slixmpp `examples directory <http://git.poez.io/slixmpp/tree/examples>`_.
.. compound::
You can run the code using:
.. code-block:: sh
python echobot.py -d -j echobot@example.com
which will prompt for the password and then begin echoing messages. To test, open
your regular IM client and start a chat with the echo bot. Messages you send to it should
be mirrored back to you. Be careful if you are using the same JID for the echo bot that
you also have logged in with another IM client. Messages could be routed to your IM client instead
of the bot.
.. include:: ../../examples/echo_client.py
:literal:

182
docs/getting_started/iq.rst Normal file
View File

@@ -0,0 +1,182 @@
Send/Receive IQ Stanzas
=======================
Unlike :class:`~slixmpp.stanza.message.Message` and
:class:`~slixmpp.stanza.presence.Presence` stanzas which only use
text data for basic usage, :class:`~slixmpp.stanza.iq.Iq` stanzas
require using XML payloads, and generally entail creating a new
Slixmpp plugin to provide the necessary convenience methods to
make working with them easier.
Basic Use
---------
XMPP's use of :class:`~slixmpp.stanza.iq.Iq` stanzas is built around
namespaced ``<query />`` elements. For clients, just sending the
empty ``<query />`` element will suffice for retrieving information. For
example, a very basic implementation of service discovery would just
need to be able to send:
.. code-block:: xml
<iq to="user@example.com" type="get" id="1">
<query xmlns="http://jabber.org/protocol/disco#info" />
</iq>
Creating Iq Stanzas
~~~~~~~~~~~~~~~~~~~
Slixmpp provides built-in support for creating basic :class:`~slixmpp.stanza.iq.Iq`
stanzas this way. The relevant methods are:
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq`
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_get`
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_set`
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_result`
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_error`
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_query`
These methods all follow the same pattern: create or modify an existing
:class:`~slixmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based
on the method name, and finally add a ``<query />`` element with the given
namespace. For example, to produce the query above, you would use:
.. code-block:: python
self.make_iq_get(queryxmlns='http://jabber.org/protocol/disco#info',
ito='user@example.com')
Sending Iq Stanzas
~~~~~~~~~~~~~~~~~~
Once an :class:`~slixmpp.stanza.iq.Iq` stanza is created, sending it
over the wire is done using its :meth:`~slixmpp.stanza.iq.Iq.send()`
method, like any other stanza object. However, there are a few extra
options to control how to wait for the query's response.
These options are:
* ``block``: The default behaviour is that :meth:`~slixmpp.stanza.iq.Iq.send()`
will block until a response is received and the response stanza will be the
return value. Setting ``block`` to ``False`` will cause the call to return
immediately. In which case, you will need to arrange some way to capture
the response stanza if you need it.
* ``timeout``: When using the blocking behaviour, the call will eventually
timeout with an error. The default timeout is 30 seconds, but this may
be overidden two ways. To change the timeout globally, set:
.. code-block:: python
self.response_timeout = 10
To change the timeout for a single call, the ``timeout`` parameter works:
.. code-block:: python
iq.send(timeout=60)
* ``callback``: When not using a blocking call, using the ``callback``
argument is a simple way to register a handler that will execute
whenever a response is finally received. Using this method, there
is no timeout limit. In case you need to remove the callback, the
name of the newly created callback is returned.
.. code-block:: python
cb_name = iq.send(callback=self.a_callback)
# ... later if we need to cancel
self.remove_handler(cb_name)
Properly working with :class:`~slixmpp.stanza.iq.Iq` stanzas requires
handling the intended, normal flow, error responses, and timed out
requests. To make this easier, two exceptions may be thrown by
:meth:`~slixmpp.stanza.iq.Iq.send()`: :exc:`~slixmpp.exceptions.IqError`
and :exc:`~slixmpp.exceptions.IqTimeout`. These exceptions only
apply to the default, blocking calls.
.. code-block:: python
try:
resp = iq.send()
# ... do stuff with expected Iq result
except IqError as e:
err_resp = e.iq
# ... handle error case
except IqTimeout:
# ... no response received in time
pass
If you do not care to distinguish between errors and timeouts, then you
can combine both cases with a generic :exc:`~slixmpp.exceptions.XMPPError`
exception:
.. code-block:: python
try:
resp = iq.send()
except XMPPError:
# ... Don't care about the response
pass
Advanced Use
------------
Going beyond the basics provided by Slixmpp requires building at least a
rudimentary Slixmpp plugin to create a :term:`stanza object` for
interfacting with the :class:`~slixmpp.stanza.iq.Iq` payload.
.. seealso::
* :ref:`create-plugin`
* :ref:`work-with-stanzas`
* :ref:`using-handlers-matchers`
The typical way to respond to :class:`~slixmpp.stanza.iq.Iq` requests is
to register stream handlers. As an example, suppose we create a stanza class
named ``CustomXEP`` which uses the XML element ``<query xmlns="custom-xep" />``,
and has a :attr:`~slixmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value
of ``custom_xep``.
There are two types of incoming :class:`~slixmpp.stanza.iq.Iq` requests:
``get`` and ``set``. You can register a handler that will accept both and then
filter by type as needed, as so:
.. code-block:: python
self.register_handler(Callback(
'CustomXEP Handler',
StanzaPath('iq/custom_xep'),
self._handle_custom_iq))
# ...
def _handle_custom_iq(self, iq):
if iq['type'] == 'get':
# ...
pass
elif iq['type'] == 'set':
# ...
pass
else:
# ... This will capture error responses too
pass
If you want to filter out query types beforehand, you can adjust the matching
filter by using ``@type=get`` or ``@type=set`` if you are using the recommended
:class:`~slixmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher.
.. code-block:: python
self.register_handler(Callback(
'CustomXEP Handler',
StanzaPath('iq@type=get/custom_xep'),
self._handle_custom_iq_get))
# ...
def _handle_custom_iq_get(self, iq):
assert(iq['type'] == 'get')

View File

@@ -0,0 +1,200 @@
.. _mucbot:
=========================
Mulit-User Chat (MUC) Bot
=========================
.. note::
If you have any issues working through this quickstart guide
join the chat room at `slixmpp@muc.poez.io
<xmpp:slixmpp@muc.poez.io?join>`_.
If you have not yet installed Slixmpp, do so now by either checking out a version
from `Git <http://git.poez.io/slixmpp>`_.
Now that you've got the basic gist of using Slixmpp by following the
echobot example (:ref:`echobot`), we can use one of the bundled plugins
to create a very popular XMPP starter project: a `Multi-User Chat`_
(MUC) bot. Our bot will login to an XMPP server, join an MUC chat room
and "lurk" indefinitely, responding with a generic message to anyone
that mentions its nickname. It will also greet members as they join the
chat room.
.. _`multi-user chat`: http://xmpp.org/extensions/xep-0045.html
Joining The Room
----------------
As usual, our code will be based on the pattern explained in :ref:`echobot`.
To start, we create an ``MUCBot`` class based on
:class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and which accepts
parameters for the JID of the MUC room to join, and the nick that the
bot will use inside the chat room. We also register an
:term:`event handler` for the :term:`session_start` event.
.. code-block:: python
import slixmpp
class MUCBot(slixmpp.ClientXMPP):
def __init__(self, jid, password, room, nick):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.room = room
self.nick = nick
self.add_event_handler("session_start", self.start)
After initialization, we also need to register the MUC (XEP-0045) plugin
so that we can make use of the group chat plugin's methods and events.
.. code-block:: python
xmpp.register_plugin('xep_0045')
Finally, we can make our bot join the chat room once an XMPP session
has been established:
.. code-block:: python
def start(self, event):
self.get_roster()
self.send_presence()
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
``join_muc`` method of the MUC plugin.
.. note::
The :attr:`plugin <slixmpp.basexmpp.BaseXMPP.plugin>` attribute is
dictionary that maps to instances of plugins that we have previously
registered, by their names.
Adding Functionality
--------------------
Currently, our bot just sits dormantly inside the chat room, but we
would like it to respond to two distinct events by issuing a generic
message in each case to the chat room. In particular, when a member
mentions the bot's nickname inside the chat room, and when a member
joins the chat room.
Responding to Mentions
~~~~~~~~~~~~~~~~~~~~~~
Whenever a user mentions our bot's nickname in chat, our bot will
respond with a generic message resembling *"I heard that, user."* We do
this by examining all of the messages sent inside the chat and looking
for the ones which contain the nickname string.
First, we register an event handler for the :term:`groupchat_message`
event inside the bot's ``__init__`` function.
.. note::
We do not register a handler for the :term:`message` event in this
bot, but if we did, the group chat message would have been sent to
both handlers.
.. code-block:: python
def __init__(self, jid, password, room, nick):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.room = room
self.nick = nick
self.add_event_handler("session_start", self.start)
self.add_event_handler("groupchat_message", self.muc_message)
Then, we can send our generic message whenever the bot's nickname gets
mentioned.
.. warning::
Always check that a message is not from yourself,
otherwise you will create an infinite loop responding
to your own messages.
.. code-block:: python
def muc_message(self, msg):
if msg['mucnick'] != self.nick and self.nick in msg['body']:
self.send_message(mto=msg['from'].bare,
mbody="I heard that, %s." % msg['mucnick'],
mtype='groupchat')
Greeting Members
~~~~~~~~~~~~~~~~
Now we want to greet member whenever they join the group chat. To
do this we will use the dynamic ``muc::room@server::got_online`` [1]_
event so it's a good idea to register an event handler for it.
.. note::
The groupchat_presence event is triggered whenever a
presence stanza is received from any chat room, including
any presences you send yourself. To limit event handling
to a single room, use the events ``muc::room@server::presence``,
``muc::room@server::got_online``, or ``muc::room@server::got_offline``.
.. code-block:: python
def __init__(self, jid, password, room, nick):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.room = room
self.nick = nick
self.add_event_handler("session_start", self.start)
self.add_event_handler("groupchat_message", self.muc_message)
self.add_event_handler("muc::%s::got_online" % self.room,
self.muc_online)
Now all that's left to do is to greet them:
.. code-block:: python
def muc_online(self, presence):
if presence['muc']['nick'] != self.nick:
self.send_message(mto=presence['from'].bare,
mbody="Hello, %s %s" % (presence['muc']['role'],
presence['muc']['nick']),
mtype='groupchat')
.. [1] this is similar to the :term:`got_online` event and is sent by
the xep_0045 plugin whenever a member joins the referenced
MUC chat room.
Final Product
-------------
.. compound::
The final step is to create a small runner script for initialising our ``MUCBot`` class and adding some
basic configuration options. By following the basic boilerplate pattern in :ref:`echobot`, we arrive
at the code below. To experiment with this example, you can use:
.. code-block:: sh
python muc.py -d -j jid@example.com -r room@muc.example.net -n lurkbot
which will prompt for the password, log in, and join the group chat. To test, open
your regular IM client and join the same group chat that you sent the bot to. You
will see ``lurkbot`` as one of the members in the group chat, and that it greeted
you upon entry. Send a message with the string "lurkbot" inside the body text, and you
will also see that it responds with our pre-programmed customized message.
.. include:: ../../examples/muc.py
:literal:

View File

@@ -0,0 +1,2 @@
Manage Presence Subscriptions
=============================

View File

@@ -0,0 +1,40 @@
.. _proxy:
=========================
Enable HTTP Proxy Support
=========================
.. note::
If you have any issues working through this quickstart guide
join the chat room at `slixmpp@muc.poez.io
<xmpp:slixmpp@muc.poez.io?join>`_.
In some instances, you may wish to route XMPP traffic through
an HTTP proxy, probably to get around restrictive firewalls.
Slixmpp provides support for basic HTTP proxying with DIGEST
authentication.
Enabling proxy support is done in two steps. The first is to instruct Slixmpp
to use a proxy, and the second is to configure the proxy details:
.. code-block:: python
xmpp = ClientXMPP(...)
xmpp.use_proxy = True
xmpp.proxy_config = {
'host': 'proxy.example.com',
'port': 5555,
'username': 'example_user',
'password': '******'
}
The ``'username'`` and ``'password'`` fields are optional if the proxy does not
require authentication.
The Final Product
-----------------
.. include:: ../../examples/proxy_echo_client.py
:literal:

View File

@@ -0,0 +1,2 @@
Send a Message Every 5 Minutes
==============================

View File

@@ -0,0 +1,92 @@
Sign in, Send a Message, and Disconnect
=======================================
.. note::
If you have any issues working through this quickstart guide
join the chat room at `slixmpp@muc.poez.io
<xmpp:slixmpp@muc.poez.io?join>`_.
A common use case for Slixmpp is to send one-off messages from
time to time. For example, one use case could be sending out a notice when
a shell script finishes a task.
We will create our one-shot bot based on the pattern explained in :ref:`echobot`. To
start, we create a client class based on :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and
register a handler for the :term:`session_start` event. We will also accept parameters
for the JID that will receive our message, and the string content of the message.
.. code-block:: python
import slixmpp
class SendMsgBot(slixmpp.ClientXMPP):
def __init__(self, jid, password, recipient, msg):
super().__init__(jid, password)
self.recipient = recipient
self.msg = msg
self.add_event_handler('session_start', self.start)
def start(self, event):
self.send_presence()
self.get_roster()
Note that as in :ref:`echobot`, we need to include send an initial presence and request
the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`.
.. code-block:: python
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient, mbody=self.msg)
Finally, we need to disconnect the client using :meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>`.
Now, sent stanzas are placed in a queue to pass them to the send thread. If we were to call
:meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible
for the client to disconnect before the send queue is processed and the message is actually
sent on the wire. To ensure that our message is processed, we use
:meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`.
.. code-block:: python
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient, mbody=self.msg)
self.disconnect(wait=True)
.. warning::
If you happen to be adding stanzas to the send queue faster than the send thread
can process them, then :meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`
will block and not disconnect.
Final Product
-------------
.. compound::
The final step is to create a small runner script for initialising our ``SendMsgBot`` class and adding some
basic configuration options. By following the basic boilerplate pattern in :ref:`echobot`, we arrive
at the code below. To experiment with this example, you can use:
.. code-block:: sh
python send_client.py -d -j oneshot@example.com -t someone@example.net -m "This is a message"
which will prompt for the password and then log in, send your message, and then disconnect. To test, open
your regular IM client with the account you wish to send messages to. When you run the ``send_client.py``
example and instruct it to send your IM client account a message, you should receive the message you
gave. If the two JIDs you use also have a mutual presence subscription (they're on each other's buddy lists)
then you will also see the ``SendMsgBot`` client come online and then go offline.
.. include:: ../../examples/send_client.py
:literal:

34
docs/glossary.rst Normal file
View File

@@ -0,0 +1,34 @@
.. _glossary:
Glossary
========
.. glossary::
:sorted:
stream handler
A callback function that accepts stanza objects pulled directly
from the XML stream. A stream handler is encapsulated in a
object that includes a :class:`Matcher <.MatcherBase>` object, and
which provides additional semantics. For example, the
:class:`.Waiter` handler wrapper blocks thread execution until a
matching stanza is received.
event handler
A callback function that responds to events raised by
:meth:`.XMLStream.event`.
stanza object
Informally may refer both to classes which extend :class:`.ElementBase`
or :class:`.StanzaBase`, and to objects of such classes.
A stanza object is a wrapper for an XML object which exposes :class:`dict`
like interfaces which may be assigned to, read from, or deleted.
stanza plugin
A :term:`stanza object` which has been registered as a potential child
of another stanza object. The plugin stanza may accessed through the
parent stanza using the plugin's ``plugin_attrib`` as an interface.
substanza
See :term:`stanza plugin`

200
docs/guide_xep_0030.rst Normal file
View File

@@ -0,0 +1,200 @@
XEP-0030: Working with Service Discovery
========================================
XMPP networks can be composed of many individual clients, components,
and servers. Determining the JIDs for these entities and the various
features they may support is the role of `XEP-0030, Service
Discovery <http://xmpp.org/extensions/xep-0030.html>`_, or "disco" for short.
Every XMPP entity may possess what are called nodes. A node is just a name for
some aspect of an XMPP entity. For example, if an XMPP entity provides `Ad-Hoc
Commands <http://xmpp.org/extensions/xep-0050.html>`_, then it will have a node
named ``http://jabber.org/protocol/commands`` which will contain information
about the commands provided. Other agents using these ad-hoc commands will
interact with the information provided by this node. Note that the node name is
just an identifier; there is no inherent meaning.
Working with service discovery is about creating and querying these nodes.
According to XEP-0030, a node may contain three types of information:
identities, features, and items. (Further, extensible, information types are
defined in `XEP-0128 <http://xmpp.org/extensions/xep-0128.html>`_, but they are
not yet implemented by Slixmpp.) Slixmpp provides methods to configure each
of these node attributes.
Configuring Service Discovery
-----------------------------
The design focus for the XEP-0030 plug-in is handling info and items requests
in a dynamic fashion, allowing for complex policy decisions of who may receive
information and how much, or use alternate backend storage mechanisms for all
of the disco data. To do this, each action that the XEP-0030 plug-in performs
is handed off to what is called a "node handler," which is just a callback
function. These handlers are arranged in a hierarchy that allows for a single
handler to manage an entire domain of JIDs (say for a component), while allowing
other handler functions to override that global behaviour for certain JIDs, or
even further limited to only certain JID and node combinations.
The Dynamic Handler Hierarchy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``global``: (JID is None, node is None)
Handlers assigned at this level for an action (such as ``add_feature``) provide a global default
behaviour when the action is performed.
* ``jid``: (JID assigned, node is None)
At this level, handlers provide a default behaviour for actions affecting any node owned by the
JID in question. This level is most useful for component connections; there is effectively no
difference between this and the global level when using a client connection.
* ``node``: (JID assigned, node assigned)
A handler for this level is responsible for carrying out an action for only one node, and is the
most specific handler type available. These types of handlers will be most useful for "special"
nodes that require special processing different than others provided by the JID, such as using
access control lists, or consolidating data from other nodes.
Default Static Handlers
~~~~~~~~~~~~~~~~~~~~~~~
The XEP-0030 plug-in provides a default set of handlers that work using in-memory
disco stanzas. Each handler simply performs the appropriate lookup or storage
operation using these stanzas without doing any complex operations such as
checking an ACL, etc.
You may find it necessary at some point to revert a particular node or JID to
using the default, static handlers. To do so, use the method ``restore_defaults()``.
You may also elect to only convert a given set of actions instead.
Creating a Node Handler
~~~~~~~~~~~~~~~~~~~~~~~
Every node handler receives three arguments: the JID, the node, and a data
parameter that will contain the relevant information for carrying out the
handler's action, typically a dictionary.
The JID will always have a value, defaulting to ``xmpp.boundjid.full`` for
components or ``xmpp.boundjid.bare`` for clients. The node value may be None or
a string.
Only handlers for the actions ``get_info`` and ``get_items`` need to have return
values. For these actions, DiscoInfo or DiscoItems stanzas are exepected as
output. It is also acceptable for handlers for these actions to generate an
XMPPError exception when necessary.
Example Node Handler:
+++++++++++++++++++++
Here is one of the built-in default handlers as an example:
.. code-block:: python
def add_identity(self, jid, node, data):
"""
Add a new identity to the JID/node combination.
The data parameter may provide:
category -- The general category to which the agent belongs.
itype -- A more specific designation with the category.
name -- Optional human readable name for this identity.
lang -- Optional standard xml:lang value.
"""
self.add_node(jid, node)
self.nodes[(jid, node)]['info'].add_identity(
data.get('category', ''),
data.get('itype', ''),
data.get('name', None),
data.get('lang', None))
Adding Identities, Features, and Items
--------------------------------------
In order to maintain some backwards compatibility, the methods ``add_identity``,
``add_feature``, and ``add_item`` do not follow the method signature pattern of
the other API methods (i.e. jid, node, then other options), but rather retain
the parameter orders from previous plug-in versions.
Adding an Identity
~~~~~~~~~~~~~~~~~~
Adding an identity may be done using either the older positional notation, or
with keyword parameters. The example below uses the keyword arguments, but in
the same order as expected using positional arguments.
.. code-block:: python
xmpp['xep_0030'].add_identity(category='client',
itype='bot',
name='Slixmpp',
node='foo',
jid=xmpp.boundjid.full,
lang='no')
The JID and node values determine which handler will be used to perform the
``add_identity`` action.
The ``lang`` parameter allows for adding localized versions of identities using
the ``xml:lang`` attribute.
Adding a Feature
~~~~~~~~~~~~~~~~
The position ordering for ``add_feature()`` is to include the feature, then
specify the node and then the JID. The JID and node values determine which
handler will be used to perform the ``add_feature`` action.
.. code-block:: python
xmpp['xep_0030'].add_feature(feature='jabber:x:data',
node='foo',
jid=xmpp.boundjid.full)
Adding an Item
~~~~~~~~~~~~~~
The parameters to ``add_item()`` are potentially confusing due to the fact that
adding an item requires two JID and node combinations: the JID and node of the
item itself, and the JID and node that will own the item.
.. code-block:: python
xmpp['xep_0030'].add_item(jid='myitemjid@example.com',
name='An Item!',
node='owner_node',
subnode='item_node',
ijid=xmpp.boundjid.full)
.. note::
In this case, the owning JID and node are provided with the
parameters ``ijid`` and ``node``.
Performing Disco Queries
------------------------
The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs
and their nodes for disco information. Since these methods are wrappers for
sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()``
method. The ``get_items()`` method may also accept the boolean parameter
``iterator``, which when set to ``True`` will return an iterator object using
the `XEP-0059 <http://xmpp.org/extensions/xep-0059.html>`_ plug-in.
.. code-block:: python
info = yield from self['xep_0030'].get_info(jid='foo@example.com',
node='bar',
ifrom='baz@mycomponent.example.com',
timeout=30)
items = self['xep_0030'].get_info(jid='foo@example.com',
node='bar',
iterator=True)
For more examples on how to use basic disco queries, check the ``disco_browser.py``
example in the ``examples`` directory.
Local Queries
~~~~~~~~~~~~~
In some cases, it may be necessary to query the contents of a node owned by the
client itself, or one of a component's many JIDs. The same method is used as for
normal queries, with two differences. First, the parameter ``local=True`` must
be used. Second, the return value will be a DiscoInfo or DiscoItems stanza, not
a full Iq stanza.
.. code-block:: python
info = self['xep_0030'].get_info(node='foo', local=True)
items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com',
node='bar',
local=True)

View File

@@ -0,0 +1,4 @@
.. _using-handlers-matchers:
Using Stream Handlers and Matchers
==================================

30
docs/howto/stanzas.rst Normal file
View File

@@ -0,0 +1,30 @@
.. _work-with-stanzas:
How to Work with Stanza Objects
===============================
.. _create-stanza-interfaces:
Defining Stanza Interfaces
--------------------------
.. _create-stanza-plugins:
Creating Stanza Plugins
-----------------------
.. _create-extension-plugins:
Creating a Stanza Extension
---------------------------
.. _override-parent-interfaces:
Overriding a Parent Stanza
--------------------------

236
docs/index.rst Normal file
View File

@@ -0,0 +1,236 @@
Slixmpp
#########
.. sidebar:: Get the Code
The latest source code for Slixmpp may be found on the `Git repo
<http://git.poez.io/slixmpp>`_. ::
git clone git://git.poez.io/slixmpp
An XMPP chat room is available for discussing and getting help with slixmpp.
**Chat**
`slixmpp@muc.poez.io <xmpp:slixmpp@muc.poez.io?join>`_
**Reporting bugs**
You can report bugs at http://dev.louiz.org/projects/slixmpp/issues.
.. note::
slixmpp is a friendly fork of `SleekXMPP <https://github.com/fritzy/SleekXMPP>`_
which goal is to use asyncio instead of threads to handle networking. See
:ref:`differences`.
Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 3.4+,
Slixmpp's design goals and philosphy are:
**Low number of dependencies**
Installing and using Slixmpp 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 Slixmpp 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, Slixmpp 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.
Here's your first Slixmpp Bot:
--------------------------------
.. code-block:: python
import asyncio
import logging
from slixmpp import ClientXMPP
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')
def session_start(self, event):
self.send_presence()
self.get_roster()
# Most get_*/set_* methods from plugins use Iq stanzas, which
# are sent asynchronously. You can almost always provide a
# callback that will be executed when the reply is received.
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('somejid@example.com', 'use_getpass')
xmpp.connect()
xmpp.process()
To read if you come from SleekXMPP
----------------------------------
.. toctree::
:maxdepth: 1
differences
using_asyncio
Getting Started (with Examples)
-------------------------------
.. toctree::
:maxdepth: 1
getting_started/echobot
getting_started/sendlogout
getting_started/component
getting_started/presence
getting_started/muc
getting_started/proxy
getting_started/scheduler
getting_started/iq
Tutorials, FAQs, and How To Guides
----------------------------------
.. toctree::
:maxdepth: 1
xeps
xmpp_tdg
howto/stanzas
create_plugin
features
sasl
handlersmatchers
Plugin Guides
~~~~~~~~~~~~~
.. toctree::
:maxdepth: 1
guide_xep_0030
Slixmpp Architecture and Design
---------------------------------
.. toctree::
:maxdepth: 3
architecture
plugin_arch
API Reference
-------------
.. toctree::
:maxdepth: 2
event_index
api/clientxmpp
api/componentxmpp
api/basexmpp
api/exceptions
api/xmlstream/jid
api/xmlstream/stanzabase
api/xmlstream/handler
api/xmlstream/matcher
api/xmlstream/xmlstream
api/xmlstream/tostring
Core Stanzas
~~~~~~~~~~~~
.. toctree::
:maxdepth: 2
api/stanza/rootstanza
api/stanza/message
api/stanza/presence
api/stanza/iq
Plugins
~~~~~~~
.. toctree::
:maxdepth: 2
Additional Info
---------------
.. toctree::
:hidden:
glossary
license
* :ref:`license`
* :ref:`glossary`
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
SleekXMPP Credits
-----------------
.. note::
Those people made SleekXMPP, so you should not bother them if
you have an issue with slixmpp. But its still fair to credit
them for their work.
**Main Author:** `Nathan Fritz <http://andyet.net/team/fritzy>`_
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
`@fritzy <http://twitter.com/fritzy>`_
Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP
<http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of the XMPP
Council.
**Co-Author:** `Lance Stout <http://andyet.net/team/lance>`_
`lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,
`@lancestout <http://twitter.com/lancestout>`_
Both Fritzy and Lance work for `&yet <http://andyet.net>`_, which specializes in
realtime web and XMPP applications.
- `contact@andyet.net <mailto:contact@andyet.net>`_
- `XMPP Consulting <http://xmppconsulting.com>`_
**Contributors:**
- Brian Beggs (`macdiesel <http://github.com/macdiesel>`_)
- Dann Martens (`dannmartens <http://github.com/dannmartens>`_)
- Florent Le Coz (`louiz <http://github.com/louiz>`_)
- Kevin Smith (`Kev <http://github.com/Kev>`_, http://kismith.co.uk)
- Remko Tronçon (`remko <http://github.com/remko>`_, http://el-tramo.be)
- Te-jé Rogers (`te-je <http://github.com/te-je>`_)
- Thom Nichols (`tomstrummer <http://github.com/tomstrummer>`_)

5
docs/license.rst Normal file
View File

@@ -0,0 +1,5 @@
.. _license:
License (MIT)
=============
.. include:: ../LICENSE

170
docs/make.bat Normal file
View File

@@ -0,0 +1,170 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Slixmpp.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Slixmpp.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

2
docs/plugin_arch.rst Normal file
View File

@@ -0,0 +1,2 @@
Plugin Architecture
===================

BIN
docs/python-objects.inv Normal file

Binary file not shown.

2
docs/sasl.rst Normal file
View File

@@ -0,0 +1,2 @@
How SASL Authentication Works
=============================

148
docs/using_asyncio.rst Normal file
View File

@@ -0,0 +1,148 @@
.. _using_asyncio:
=============
Using asyncio
=============
Block on IQ sending
~~~~~~~~~~~~~~~~~~~
:meth:`.Iq.send` now returns a :class:`~.Future` so you can easily block with:
.. code-block:: python
result = yield from iq.send()
.. warning::
If the reply is an IQ with an ``error`` type, this will raise an
:class:`.IqError`, and if it timeouts, it will raise an
:class:`.IqTimeout`. Don't forget to catch it.
You can still use callbacks instead.
XEP plugin integration
~~~~~~~~~~~~~~~~~~~~~~
The same changes from the SleekXMPP API apply, so you can do:
.. code-block:: python
iq_info = yield from self.xmpp['xep_0030'].get_info(jid)
But the following will only return a Future:
.. code-block:: python
iq_info = self.xmpp['xep_0030'].get_info(jid)
Callbacks, Event Handlers, and Stream Handlers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IQ callbacks and :term:`Event Handlers <event handler>` can be coroutine
functions; in this case, they will be scheduled in the event loop using
:meth:`.asyncio.async` and not ran immediately.
A :class:`.CoroutineCallback` class has been added as well for
:term:`Stream Handlers <stream handler>`, which will use
:meth:`.asyncio.async` to schedule the callback.
Running the event loop
~~~~~~~~~~~~~~~~~~~~~~
:meth:`.XMLStream.process` is only a thin wrapper on top of
``loop.run_forever()`` (if ``timeout`` is provided then it will
only run for this amount of time, and if ``forever`` is False it will
run until disconnection).
Therefore you can handle the event loop in any way you like
instead of using ``process()``.
Examples
~~~~~~~~
Blocking until the session is established
-----------------------------------------
This code blocks until the XMPP session is fully established, which
can be useful to make sure external events arent triggering XMPP
callbacks while everything is not ready.
.. code-block:: python
import asyncio, slixmpp
client = slixmpp.ClientXMPP('jid@example', 'password')
client.connected_event = asyncio.Event()
callback = lambda _: client.connected_event.set()
client.add_event_handler('session_start', callback)
client.connect()
loop.run_until_complete(event.wait())
# do some other stuff before running the event loop, e.g.
# loop.run_until_complete(httpserver.init())
client.process()
Use with other asyncio-based libraries
--------------------------------------
This code interfaces with aiohttp to retrieve two pages asynchronously
when the session is established, and then send the HTML content inside
a simple <message>.
.. code-block:: python
import asyncio, aiohttp, slixmpp
@asyncio.coroutine
def get_pythonorg(event):
req = yield from aiohttp.request('get', 'http://www.python.org')
text = yield from req.text
client.send_message(mto='jid2@example', mbody=text)
@asyncio.coroutine
def get_asyncioorg(event):
req = yield from aiohttp.request('get', 'http://www.asyncio.org')
text = yield from req.text
client.send_message(mto='jid3@example', mbody=text)
client = slixmpp.ClientXMPP('jid@example', 'password')
client.add_event_handler('session_start', get_pythonorg)
client.add_event_handler('session_start', get_asyncioorg)
client.connect()
client.process()
Blocking Iq
-----------
This client checks (via XEP-0092) the software used by every entity it
receives a message from. After this, it sends a message to a specific
JID indicating its findings.
.. code-block:: python
import asyncio, slixmpp
class ExampleClient(slixmpp.ClientXMPP):
def __init__(self, *args, **kwargs):
slixmpp.ClientXMPP.__init__(self, *args, **kwargs)
self.register_plugin('xep_0092')
self.add_event_handler('message', self.on_message)
@asyncio.coroutine
def on_message(self, event):
# You should probably handle IqError and IqTimeout exceptions here
# but this is an example.
version = yield from self['xep_0092'].get_version(message['from'])
text = "%s sent me a message, he runs %s" % (message['from'],
version['software_version']['name'])
self.send_message(mto='master@example.tld', mbody=text)
client = ExampleClient('jid@example', 'password')
client.connect()
client.process()

50
docs/xeps.rst Normal file
View File

@@ -0,0 +1,50 @@
Supported XEPS
==============
======= ============================= ================
XEP Description Notes
======= ============================= ================
`0004`_ Data forms
`0009`_ Jabber RPC
`0012`_ Last Activity
`0030`_ Service Discovery
`0033`_ Extended Stanza Addressing
`0045`_ Multi-User Chat (MUC) Client-side only
`0050`_ Ad-hoc Commands
`0059`_ Result Set Management
`0060`_ Publish/Subscribe (PubSub) Client-side only
`0066`_ Out-of-band Data
`0078`_ Non-SASL Authentication
`0082`_ XMPP Date and Time Profiles
`0085`_ Chat-State Notifications
`0086`_ Error Condition Mappings
`0092`_ Software Version
`0128`_ Service Discovery Extensions
`0202`_ Entity Time
`0203`_ Delayed Delivery
`0224`_ Attention
`0249`_ Direct MUC Invitations
======= ============================= ================
.. _0004: http://xmpp.org/extensions/xep-0004.html
.. _0009: http://xmpp.org/extensions/xep-0009.html
.. _0012: http://xmpp.org/extensions/xep-0012.html
.. _0030: http://xmpp.org/extensions/xep-0030.html
.. _0033: http://xmpp.org/extensions/xep-0033.html
.. _0045: http://xmpp.org/extensions/xep-0045.html
.. _0050: http://xmpp.org/extensions/xep-0050.html
.. _0059: http://xmpp.org/extensions/xep-0059.html
.. _0060: http://xmpp.org/extensions/xep-0060.html
.. _0066: http://xmpp.org/extensions/xep-0066.html
.. _0078: http://xmpp.org/extensions/xep-0078.html
.. _0082: http://xmpp.org/extensions/xep-0082.html
.. _0085: http://xmpp.org/extensions/xep-0085.html
.. _0086: http://xmpp.org/extensions/xep-0086.html
.. _0092: http://xmpp.org/extensions/xep-0092.html
.. _0128: http://xmpp.org/extensions/xep-0128.html
.. _0199: http://xmpp.org/extensions/xep-0199.html
.. _0202: http://xmpp.org/extensions/xep-0202.html
.. _0203: http://xmpp.org/extensions/xep-0203.html
.. _0224: http://xmpp.org/extensions/xep-0224.html
.. _0249: http://xmpp.org/extensions/xep-0249.html

249
docs/xmpp_tdg.rst Normal file
View File

@@ -0,0 +1,249 @@
Following *XMPP: The Definitive Guide*
======================================
Slixmpp was featured in the first edition of the O'Reilly book
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271/>`_
by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code
for the book's examples can be found at http://github.com/remko/xmpp-tdg. An
updated version of the source code, maintained to stay current with the latest
Slixmpp release, is available at http://github.com/legastero/xmpp-tdg.
However, since publication, Slixmpp has advanced from version 0.2.1 to version
1.0 and there have been several major API changes. The most notable is the
introduction of :term:`stanza objects <stanza object>` which have simplified and
standardized interactions with the XMPP XML stream.
What follows is a walk-through of *The Definitive Guide* highlighting the
changes needed to make the code examples work with version 1.0 of Slixmpp.
These changes have been kept to a minimum to preserve the correlation with
the book's explanations, so be aware that some code may not use current best
practices.
Example 2-2. (Page 26)
----------------------
**Implementation of a basic bot that echoes all incoming messages back to its sender.**
The echo bot example requires a change to the ``handleIncomingMessage`` method
to reflect the use of the ``Message`` :term:`stanza object`. The
``"jid"`` field of the message object should now be ``"from"`` to match the
``from`` attribute of the actual XML message stanza. Likewise, ``"message"``
changes to ``"body"`` to match the ``body`` element of the message stanza.
Updated Code
~~~~~~~~~~~~
.. code-block:: python
def handleIncomingMessage(self, message):
self.xmpp.send_message(message["from"], message["body"])
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ |
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_
Example 14-1. (Page 215)
------------------------
**CheshiR IM bot implementation.**
The main event handling method in the Bot class is meant to process both message
events and presence update events. With the new changes in Slixmpp 1.0,
extracting a CheshiR status "message" from both types of stanzas
requires accessing different attributes. In the case of a message stanza, the
``"body"`` attribute would contain the CheshiR message. For a presence event,
the information is stored in the ``"status"`` attribute. To handle both cases,
we can test the type of the given event object and look up the proper attribute
based on the type.
Like in the EchoBot example, the expression ``event["jid"]`` needs to change
to ``event["from"]`` in order to get a JID object for the stanza's sender.
Because other functions in CheshiR assume that the JID is a string, the ``jid``
attribute is used to access the string version of the JID. A check is also added
in case ``user`` is ``None``, but the check could (and probably should) be
placed in ``addMessageFromUser``.
Another change is needed in ``handleMessageAddedToBackend`` where
an HTML-IM response is created. The HTML content should be enclosed in a single
element, such as a ``<p>`` tag.
Updated Code
~~~~~~~~~~~~
.. code-block:: python
def handleIncomingXMPPEvent(self, event):
msgLocations = {slixmpp.stanza.presence.Presence: "status",
slixmpp.stanza.message.Message: "body"}
message = event[msgLocations[type(event)]]
user = self.backend.getUserFromJID(event["from"].jid)
if user is not None:
self.backend.addMessageFromUser(message, user)
def handleMessageAddedToBackend(self, message) :
body = message.user + ": " + message.text
htmlBody = "<p><a href='%(uri)s'>%(user)s</a>: %(message)s</p>" % {
"uri": self.url + "/" + message.user,
"user" : message.user, "message" : message.text }
for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
self.xmpp.send_message(subscriberJID, body, mhtml=htmlBody)
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ |
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_
Example 14-3. (Page 217)
------------------------
**Configurable CheshiR IM bot implementation.**
.. note::
Since the CheshiR examples build on each other, see previous sections for
corrections to code that is not marked as new in the book example.
The main difference for the configurable IM bot is the handling for the
data form in ``handleConfigurationCommand``. The test for equality
with the string ``"1"`` is no longer required; Slixmpp converts
boolean data form fields to the values ``True`` and ``False``
automatically.
For the method ``handleIncomingXMPPPresence``, the attribute
``"jid"`` is again converted to ``"from"`` to get a JID
object for the presence stanza's sender, and the ``jid`` attribute is
used to access the string version of that JID object. A check is also added in
case ``user`` is ``None``, but the check could (and probably
should) be placed in ``getShouldMonitorPresenceFromUser``.
Updated Code
~~~~~~~~~~~~
.. code-block:: python
def handleConfigurationCommand(self, form, sessionId):
values = form.getValues()
monitorPresence =values["monitorPresence"]
jid = self.xmpp.plugin["xep_0050"].sessions[sessionId]["jid"]
user = self.backend.getUserFromJID(jid)
self.backend.setShouldMonitorPresenceFromUser(user, monitorPresence)
def handleIncomingXMPPPresence(self, event):
user = self.backend.getUserFromJID(event["from"].jid)
if user is not None:
if self.backend.getShouldMonitorPresenceFromUser(user):
self.handleIncomingXMPPEvent(event)
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/ConfigurableBot.py>`_ |
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/ConfigurableBot.py>`_
Example 14-4. (Page 220)
------------------------
**CheshiR IM server component implementation.**
.. note::
Since the CheshiR examples build on each other, see previous sections for
corrections to code that is not marked as new in the book example.
Like several previous examples, a needed change is to replace
``subscription["from"]`` with ``subscription["from"].jid`` because the
``BaseXMPP`` method ``make_presence`` requires the JID to be a string.
A correction needs to be made in ``handleXMPPPresenceProbe`` because a line was
left out of the original implementation; the variable ``user`` is undefined. The
JID of the user can be extracted from the presence stanza's ``from`` attribute.
Since this implementation of CheshiR uses an XMPP component, it must
include a ``from`` attribute in all messages that it sends. Adding the
``from`` attribute is done by including ``mfrom=self.xmpp.jid`` in calls to
``self.xmpp.send_message``.
Updated Code
~~~~~~~~~~~~
.. code-block:: python
def handleXMPPPresenceProbe(self, event) :
self.xmpp.send_presence(pto = event["from"])
def handleXMPPPresenceSubscription(self, subscription) :
if subscription["type"] == "subscribe" :
userJID = subscription["from"].jid
self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribed")
self.xmpp.send_presence(pto = userJID)
self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribe")
def handleMessageAddedToBackend(self, message) :
body = message.user + ": " + message.text
for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
self.xmpp.send_message(subscriberJID, body, mfrom=self.xmpp.jid)
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ |
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_
Example 14-6. (Page 223)
------------------------
**CheshiR IM server component with in-band registration support.**
.. note::
Since the CheshiR examples build on each other, see previous sections for
corrections to code that is not marked as new in the book example.
After applying the changes from Example 14-4 above, the registrable component
implementation should work correctly.
.. tip::
To see how to implement in-band registration as a Slixmpp plugin,
see the tutorial :ref:`tutorial-create-plugin`.
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_ |
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_
Example 14-7. (Page 225)
------------------------
**Extended CheshiR IM server component implementation.**
.. note::
Since the CheshiR examples build on each other, see previous
sections for corrections to code that is not marked as new in the book
example.
While the final code example can look daunting with all of the changes
made, it requires very few modifications to work with the latest version of
Slixmpp. Most differences are the result of CheshiR's backend functions
expecting JIDs to be strings so that they can be stripped to bare JIDs. To
resolve these, use the ``jid`` attribute of the JID objects. Also,
references to ``"message"`` and ``"jid"`` attributes need to
be changed to either ``"body"`` or ``"status"``, and either
``"from"`` or ``"to"`` depending on if the object is a message
or presence stanza and which of the JIDs from the stanza is needed.
Updated Code
~~~~~~~~~~~~
.. code-block:: python
def handleIncomingXMPPMessage(self, event) :
message = self.addRecipientToMessage(event["body"], event["to"].jid)
user = self.backend.getUserFromJID(event["from"].jid)
self.backend.addMessageFromUser(message, user)
def handleIncomingXMPPPresence(self, event) :
if event["to"].jid == self.componentDomain :
user = self.backend.getUserFromJID(event["from"].jid)
self.backend.addMessageFromUser(event["status"], user)
...
def handleXMPPPresenceSubscription(self, subscription) :
if subscription["type"] == "subscribe" :
userJID = subscription["from"].jid
user = self.backend.getUserFromJID(userJID)
contactJID = subscription["to"]
self.xmpp.send_presence_subscription(
pfrom=contactJID, pto=userJID, ptype="subscribed", pnick=user)
self.sendPresenceOfContactToUser(contactJID=contactJID, userJID=userJID)
if contactJID == self.componentDomain :
self.sendAllContactSubscriptionRequestsToUser(userJID)
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ |
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_

182
examples/IoT_TestDevice.py Executable file
View File

@@ -0,0 +1,182 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Implementation of xeps for Internet of Things
http://wiki.xmpp.org/web/Tech_pages/IoT_systems
Copyright (C) 2013 Sustainable Innovation, Joachim.lindborg@sust.se
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from os.path import basename, join as pjoin
from argparse import ArgumentParser
from urllib import urlopen
from getpass import getpass
import slixmpp
from slixmpp.plugins.xep_0323.device import Device
#from slixmpp.exceptions import IqError, IqTimeout
class IoT_TestDevice(slixmpp.ClientXMPP):
"""
A simple IoT device that can act as server or client
"""
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.add_event_handler("session_start", self.session_start)
self.add_event_handler("message", self.message)
self.device=None
self.releaseMe=False
self.beServer=True
self.clientJID=None
def datacallback(self,from_jid,result,nodeId=None,timestamp=None,fields=None,error_msg=None):
"""
This method will be called when you ask another IoT device for data with the xep_0323
se script below for the registration of the callback
"""
logging.debug("we got data %s from %s",str(result),from_jid)
def beClientOrServer(self,server=True,clientJID=None ):
if server:
self.beServer=True
self.clientJID=None
else:
self.beServer=False
self.clientJID=clientJID
def testForRelease(self):
# todo thread safe
return self.releaseMe
def doReleaseMe(self):
# todo thread safe
self.releaseMe=True
def addDevice(self, device):
self.device=device
def session_start(self, event):
self.send_presence()
self.get_roster()
# tell your preffered friend that you are alive
self.send_message(mto='jocke@jabber.sust.se', mbody=self.boundjid.bare +' is now online use xep_323 stanza to talk to me')
if not(self.beServer):
session=self['xep_0323'].request_data(self.boundjid.full,self.clientJID,self.datacallback)
def message(self, msg):
if msg['type'] in ('chat', 'normal'):
logging.debug("got normal chat message" + str(msg))
ip=urlopen('http://icanhazip.com').read()
msg.reply("Hi I am " + self.boundjid.full + " and I am on IP " + ip).send()
else:
logging.debug("got unknown message type %s", str(msg['type']))
class TheDevice(Device):
"""
This is the actual device object that you will use to get information from your real hardware
You will be called in the refresh method when someone is requesting information from you
"""
def __init__(self,nodeId):
Device.__init__(self,nodeId)
self.counter=0
def refresh(self,fields):
"""
the implementation of the refresh method
"""
self._set_momentary_timestamp(self._get_timestamp())
self.counter+=self.counter
self._add_field_momentary_data(self, "Temperature", self.counter)
if __name__ == '__main__':
# Setup the command line arguments.
#
# This script can act both as
# "server" an IoT device that can provide sensorinformation
# python IoT_TestDevice.py -j "serverjid@yourdomain.com" -p "password" -n "TestIoT" --debug
#
# "client" an IoT device or other party that would like to get data from another device
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
parser.add_argument("-t", "--pingto", help="set jid to ping",
action="store", type="string", dest="pingjid",
default=None)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
# IoT test
parser.add_argument("-c", "--sensorjid", dest="sensorjid",
help="Another device to call for data on", default=None)
parser.add_argument("-n", "--nodeid", dest="nodeid",
help="I am a device get ready to be called", default=None)
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
xmpp = IoT_TestDevice(args.jid,args.password)
xmpp.register_plugin('xep_0030')
#xmpp['xep_0030'].add_feature(feature='urn:xmpp:iot:sensordata',
# node=None,
# jid=None)
xmpp.register_plugin('xep_0323')
xmpp.register_plugin('xep_0325')
if args.nodeid:
# xmpp['xep_0030'].add_feature(feature='urn:xmpp:sn',
# node=args.nodeid,
# jid=xmpp.boundjid.full)
myDevice = TheDevice(args.nodeid);
# myDevice._add_field(name="Relay", typename="numeric", unit="Bool");
myDevice._add_field(name="Temperature", typename="numeric", unit="C")
myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
xmpp['xep_0323'].register_node(nodeId=args.nodeid, device=myDevice, commTimeout=10);
xmpp.beClientOrServer(server=True)
while not(xmpp.testForRelease()):
xmpp.connect()
xmpp.process(block=True)
logging.debug("lost connection")
if args.sensorjid:
logging.debug("will try to call another device for data")
xmpp.beClientOrServer(server=False,clientJID=args.sensorjid)
xmpp.connect()
xmpp.process(block=True)
logging.debug("ready ending")
else:
print("noopp didn't happen")

View File

@@ -1,45 +1,35 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import logging
import time
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
import slixmpp
class CommandBot(sleekxmpp.ClientXMPP):
class CommandBot(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that provides a basic
A simple Slixmpp bot that provides a basic
adhoc command.
"""
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can intialize
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
@@ -48,7 +38,7 @@ class CommandBot(sleekxmpp.ClientXMPP):
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an intial
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
@@ -70,7 +60,7 @@ class CommandBot(sleekxmpp.ClientXMPP):
def _handle_command(self, iq, session):
"""
Respond to the intial request for a command.
Respond to the initial request for a command.
Arguments:
iq -- The iq stanza containing the command request.
@@ -78,7 +68,8 @@ class CommandBot(sleekxmpp.ClientXMPP):
session. Additional, custom data may be saved
here to persist across handler callbacks.
"""
form = self['xep_0004'].makeForm('form', 'Greeting')
form = self['xep_0004'].make_form('form', 'Greeting')
form['instructions'] = 'Send a custom greeting to a JID'
form.addField(var='greeting',
ftype='text-single',
label='Your greeting')
@@ -123,8 +114,10 @@ class CommandBot(sleekxmpp.ClientXMPP):
form = payload
greeting = form['values']['greeting']
self.send_message(mto=session['from'],
mbody="%s, World!" % greeting)
mbody="%s, World!" % greeting,
mtype='chat')
# Having no return statement is the same as unsetting the 'payload'
# and 'next' session values and returning the session.
@@ -139,61 +132,42 @@ class CommandBot(sleekxmpp.ClientXMPP):
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser()
# Output verbosity options.
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)
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
opts, args = optp.parse_args()
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the CommandBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = CommandBot(opts.jid, opts.password)
xmpp = CommandBot(args.jid, args.password)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0050') # Adhoc Commands
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency':15})
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the pydns library installed, you will need
# to manually specify the name of the server if it does not match
# the one in the JID. For example, to use Google Talk you would
# need to use:
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
xmpp.process(threaded=False)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,40 +1,30 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import logging
import time
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
import slixmpp
class CommandUserBot(sleekxmpp.ClientXMPP):
class CommandUserBot(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that uses the adhoc command
A simple Slixmpp bot that uses the adhoc command
provided by the adhoc_provider.py example.
"""
def __init__(self, jid, password, other, greeting):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
self.command_provider = other
self.greeting = greeting
@@ -42,7 +32,7 @@ class CommandUserBot(sleekxmpp.ClientXMPP):
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can intialize
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
self.add_event_handler("message", self.message)
@@ -52,7 +42,7 @@ class CommandUserBot(sleekxmpp.ClientXMPP):
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an intial
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
@@ -104,7 +94,7 @@ class CommandUserBot(sleekxmpp.ClientXMPP):
# label="Your greeting" />
# </x>
form = self['xep_0004'].makeForm(ftype='submit')
form = self['xep_0004'].make_form(ftype='submit')
form.addField(var='greeting',
value=session['greeting'])
@@ -136,73 +126,54 @@ class CommandUserBot(sleekxmpp.ClientXMPP):
# The session will automatically be cleared if no error
# handler is provided.
self['xep_0050'].terminate_command(session)
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser()
# Output verbosity options.
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)
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
optp.add_option("-o", "--other", dest="other",
help="JID providing commands")
optp.add_option("-g", "--greeting", dest="greeting",
help="Greeting")
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-o", "--other", dest="other",
help="JID providing commands")
parser.add_argument("-g", "--greeting", dest="greeting",
help="Greeting")
opts, args = optp.parse_args()
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if opts.other is None:
opts.other = raw_input("JID Providing Commands: ")
if opts.greeting is None:
opts.other = raw_input("Greeting: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.other is None:
args.other = input("JID Providing Commands: ")
if args.greeting is None:
args.greeting = input("Greeting: ")
# Setup the CommandBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = CommandUserBot(opts.jid, opts.password, opts.other, opts.greeting)
xmpp = CommandUserBot(args.jid, args.password, args.other, args.greeting)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0050') # Adhoc Commands
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the pydns library installed, you will need
# to manually specify the name of the server if it does not match
# the one in the JID. For example, to use Google Talk you would
# need to use:
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
xmpp.process(threaded=False)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

147
examples/admin_commands.py Executable file
View File

@@ -0,0 +1,147 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
class AdminCommands(slixmpp.ClientXMPP):
"""
A simple Slixmpp bot that uses admin commands to
add a new user to a server.
"""
def __init__(self, jid, password, command):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.command = command
self.add_event_handler("session_start", self.start)
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self.send_presence()
self.get_roster()
def command_success(iq, session):
print('Command completed')
if iq['command']['form']:
for var, field in iq['command']['form']['fields'].items():
print('%s: %s' % (var, field['value']))
if iq['command']['notes']:
print('Command Notes:')
for note in iq['command']['notes']:
print('%s: %s' % note)
self.disconnect()
def command_error(iq, session):
print('Error completing command')
print('%s: %s' % (iq['error']['condition'],
iq['error']['text']))
self['xep_0050'].terminate_command(session)
self.disconnect()
def process_form(iq, session):
form = iq['command']['form']
answers = {}
for var, field in form['fields'].items():
if var != 'FORM_TYPE':
if field['type'] == 'boolean':
answers[var] = input('%s (y/n): ' % field['label'])
if answers[var].lower() in ('1', 'true', 'y', 'yes'):
answers[var] = '1'
else:
answers[var] = '0'
else:
answers[var] = input('%s: ' % field['label'])
else:
answers['FORM_TYPE'] = field['value']
form['type'] = 'submit'
form['values'] = answers
session['next'] = command_success
session['payload'] = form
self['xep_0050'].complete_command(session)
session = {'next': process_form,
'error': command_error}
command = self.command.replace('-', '_')
handler = getattr(self['xep_0133'], command, None)
if handler:
handler(session={
'next': process_form,
'error': command_error
})
else:
print('Invalid command name: %s' % self.command)
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-c", "--command", dest="command",
help="admin command to use")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.command is None:
args.command = input("Admin command: ")
# Setup the CommandBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = AdminCommands(args.jid, args.password, args.command)
xmpp.register_plugin('xep_0133') # Service Administration
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process()

View File

@@ -1,10 +0,0 @@
<config xmlns="sleekxmpp:config">
<jid>component.localhost</jid>
<secret>ssshh</secret>
<server>localhost</server>
<port>8888</port>
<query xmlns="jabber:iq:roster">
<item jid="user@example.com" subscription="both" />
</query>
</config>

View File

@@ -1,190 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import sys
import logging
import time
from optparse import OptionParser
import sleekxmpp
from sleekxmpp.componentxmpp import ComponentXMPP
from sleekxmpp.stanza.roster import Roster
from sleekxmpp.xmlstream import ElementBase
from sleekxmpp.xmlstream.stanzabase import ET, registerStanzaPlugin
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
class Config(ElementBase):
"""
In order to make loading and manipulating an XML config
file easier, we will create a custom stanza object for
our config XML file contents. See the documentation
on stanza objects for more information on how to create
and use stanza objects and stanza plugins.
We will reuse the IQ roster query stanza to store roster
information since it already exists.
Example config XML:
<config xmlns="sleekxmpp:config">
<jid>component.localhost</jid>
<secret>ssshh</secret>
<server>localhost</server>
<port>8888</port>
<query xmlns="jabber:iq:roster">
<item jid="user@example.com" subscription="both" />
</query>
</config>
"""
name = "config"
namespace = "sleekxmpp:config"
interfaces = set(('jid', 'secret', 'server', 'port'))
sub_interfaces = interfaces
registerStanzaPlugin(Config, Roster)
class ConfigComponent(ComponentXMPP):
"""
A simple SleekXMPP component that uses an external XML
file to store its configuration data. To make testing
that the component works, it will also echo messages sent
to it.
"""
def __init__(self, config):
"""
Create a ConfigComponent.
Arguments:
config -- The XML contents of the config file.
config_file -- The XML config file object itself.
"""
ComponentXMPP.__init__(self, config['jid'],
config['secret'],
config['server'],
config['port'])
# Store the roster information.
self.roster = config['roster']['items']
# The session_start event will be triggered when
# the component establishes its connection with the
# server and the XML streams are ready for use. We
# want to listen for this event so that we we can
# broadcast any needed initial presence stanzas.
self.add_event_handler("session_start", self.start)
# The message event is triggered whenever a message
# stanza is received. Be aware that that includes
# MUC messages and error messages.
self.add_event_handler("message", self.message)
def start(self, event):
"""
Process the session_start event.
The typical action for the session_start event in a component
is to broadcast presence stanzas to all subscribers to the
component. Note that the component does not have a roster
provided by the XMPP server. In this case, we have possibly
saved a roster in the component's configuration file.
Since the component may use any number of JIDs, you should
also include the JID that is sending the presence.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
for jid in self.roster:
if self.roster[jid]['subscription'] != 'none':
self.sendPresence(pfrom=self.jid, pto=jid)
def message(self, msg):
"""
Process incoming message stanzas. Be aware that this also
includes MUC messages and error messages. It is usually
a good idea to check the messages's type before processing
or sending replies.
Since a component may send messages from any number of JIDs,
it is best to always include a from JID.
Arguments:
msg -- The received message stanza. See the documentation
for stanza objects and the Message stanza to see
how it may be used.
"""
# The reply method will use the messages 'to' JID as the
# outgoing reply's 'from' JID.
msg.reply("Thanks for sending\n%(body)s" % msg).send()
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
# Output verbosity options.
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)
# Component name and secret options.
optp.add_option("-c", "--config", help="path to config file",
dest="config", default="config.xml")
opts, args = optp.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
format='%(levelname)-8s %(message)s')
# Load configuration data.
config_file = open(opts.config, 'r+')
config_data = "\n".join([line for line in config_file])
config = Config(xml=ET.fromstring(config_data))
config_file.close()
# Setup the ConfigComponent and register plugins. Note that while plugins
# may have interdependencies, the order in which you register them does
# not matter.
xmpp = ConfigComponent(config)
xmpp.registerPlugin('xep_0030') # Service Discovery
xmpp.registerPlugin('xep_0004') # Data Forms
xmpp.registerPlugin('xep_0060') # PubSub
xmpp.registerPlugin('xep_0199') # XMPP Ping
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
xmpp.process(threaded=False)
print("Done")
else:
print("Unable to connect.")

100
examples/confirm_answer.py Executable file
View File

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

125
examples/confirm_ask.py Executable file
View File

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

View File

@@ -0,0 +1,137 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp import ClientXMPP, Iq
from slixmpp.exceptions import IqError, IqTimeout, XMPPError
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from stanza import Action
class ActionBot(slixmpp.ClientXMPP):
"""
A simple Slixmpp bot that receives a custom stanza
from another client.
"""
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
self.register_handler(
Callback('Some custom iq',
StanzaPath('iq@type=set/action'),
self._handle_action))
self.add_event_handler('custom_action',
self._handle_action_event)
register_stanza_plugin(Iq, Action)
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self.send_presence()
self.get_roster()
def _handle_action(self, iq):
"""
Raise an event for the stanza so that it can be processed in its
own thread without blocking the main stanza processing loop.
"""
self.event('custom_action', iq)
def _handle_action_event(self, iq):
"""
Respond to the custom action event.
"""
method = iq['action']['method']
param = iq['action']['param']
if method == 'is_prime' and param == '2':
print("got message: %s" % iq)
iq.reply()
iq['action']['status'] = 'done'
iq.send()
elif method == 'bye':
print("got message: %s" % iq)
self.disconnect()
else:
print("got message: %s" % iq)
iq.reply()
iq['action']['status'] = 'error'
iq.send()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the CommandBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = ActionBot(args.jid, args.password)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0050') # Adhoc Commands
xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency':15})
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process()

View File

@@ -0,0 +1,142 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp import Iq
from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream import register_stanza_plugin
from stanza import Action
class ActionUserBot(slixmpp.ClientXMPP):
"""
A simple Slixmpp bot that sends a custom action stanza
to another client.
"""
def __init__(self, jid, password, other):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.action_provider = other
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
self.add_event_handler("message", self.message)
register_stanza_plugin(Iq, Action)
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self.send_presence()
self.get_roster()
self.send_custom_iq()
def send_custom_iq(self):
"""Create and send two custom actions.
If the first action was successful, then send
a shutdown command and then disconnect.
"""
iq = self.Iq()
iq['to'] = self.action_provider
iq['type'] = 'set'
iq['action']['method'] = 'is_prime'
iq['action']['param'] = '2'
try:
resp = iq.send()
if resp['action']['status'] == 'done':
#sending bye
iq2 = self.Iq()
iq2['to'] = self.action_provider
iq2['type'] = 'set'
iq2['action']['method'] = 'bye'
iq2.send(block=False)
self.disconnect()
except XMPPError:
print('There was an error sending the custom action.')
def message(self, msg):
"""
Process incoming message stanzas.
Arguments:
msg -- The received message stanza.
"""
logging.info(msg['body'])
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-o", "--other", dest="other",
help="JID providing custom stanza")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.other is None:
args.other = input("JID Providing custom stanza: ")
# Setup the CommandBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = ActionUserBot(args.jid, args.password, args.other)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0050') # Adhoc Commands
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process()

View File

@@ -0,0 +1,56 @@
from slixmpp.xmlstream import ElementBase
class Action(ElementBase):
"""
A stanza class for XML content of the form:
<action xmlns="slixmpp:custom:actions">
<method>X</method>
<param>X</param>
<status>X</status>
</action>
"""
#: The `name` field refers to the basic XML tag name of the
#: stanza. Here, the tag name will be 'action'.
name = 'action'
#: The namespace of the main XML tag.
namespace = 'slixmpp:custom:actions'
#: The `plugin_attrib` value is the name that can be used
#: with a parent stanza to access this stanza. For example
#: from an Iq stanza object, accessing:
#:
#: iq['action']
#:
#: would reference an Action object, and will even create
#: an Action object and append it to the Iq stanza if
#: one doesn't already exist.
plugin_attrib = 'action'
#: Stanza objects expose dictionary-like interfaces for
#: accessing and manipulating substanzas and other values.
#: The set of interfaces defined here are the names of
#: these dictionary-like interfaces provided by this stanza
#: type. For example, an Action stanza object can use:
#:
#: action['method'] = 'foo'
#: print(action['param'])
#: del action['status']
#:
#: to set, get, or remove its values.
interfaces = set(('method', 'param', 'status'))
#: By default, values in the `interfaces` set are mapped to
#: attribute values. This can be changed such that an interface
#: maps to a subelement's text value by adding interfaces to
#: the sub_interfaces set. For example, here all interfaces
#: are marked as sub_interfaces, and so the XML produced will
#: look like:
#:
#: <action xmlns="slixmpp:custom:actions">
#: <method>foo</method>
#: </action>
sub_interfaces = interfaces

View File

@@ -1,33 +1,24 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import time
import logging
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
import slixmpp
from slixmpp.exceptions import IqError, IqTimeout
from slixmpp.xmlstream.asyncio import asyncio
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
class Disco(sleekxmpp.ClientXMPP):
class Disco(slixmpp.ClientXMPP):
"""
A demonstration for using basic service discovery.
@@ -40,7 +31,7 @@ class Disco(sleekxmpp.ClientXMPP):
"""
def __init__(self, jid, password, target_jid, target_node='', get=''):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
# Using service discovery requires the XEP-0030 plugin.
self.register_plugin('xep_0030')
@@ -59,16 +50,17 @@ class Disco(sleekxmpp.ClientXMPP):
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can intialize
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an intial
requesting the roster and broadcasting an initial
presence stanza.
In this case, we send disco#info and disco#items
@@ -82,117 +74,88 @@ class Disco(sleekxmpp.ClientXMPP):
self.get_roster()
self.send_presence()
if self.get in self.info_types:
# By using block=True, the result stanza will be
# returned. Execution will block until the reply is
# received. Non-blocking options would be to listen
# for the disco_info event, or passing a handler
# function using the callback parameter.
info = self['xep_0030'].get_info(jid=self.target_jid,
node=self.target_node,
block=True)
if self.get in self.items_types:
# The same applies from above. Listen for the
# disco_items event or pass a callback function
# if you need to process a non-blocking request.
items = self['xep_0030'].get_items(jid=self.target_jid,
node=self.target_node,
block=True)
try:
if self.get in self.info_types:
# function using the callback parameter.
info = yield from self['xep_0030'].get_info(jid=self.target_jid,
node=self.target_node)
if self.get in self.items_types:
# The same applies from above. Listen for the
# disco_items event or pass a callback function
# if you need to process a non-blocking request.
items = yield from self['xep_0030'].get_items(jid=self.target_jid,
node=self.target_node)
if self.get not in self.info_types and self.get not in self.items_types:
logging.error("Invalid disco request type.")
return
except IqError as e:
logging.error("Entity returned an error: %s" % e.iq['error']['condition'])
except IqTimeout:
logging.error("No response received.")
else:
logging.error("Invalid disco request type.")
self.disconnect()
return
header = 'XMPP Service Discovery: %s' % self.target_jid
print(header)
print('-' * len(header))
if self.target_node != '':
print('Node: %s' % self.target_node)
header = 'XMPP Service Discovery: %s' % self.target_jid
print(header)
print('-' * len(header))
if self.target_node != '':
print('Node: %s' % self.target_node)
print('-' * len(header))
if self.get in self.identity_types:
print('Identities:')
for identity in info['disco_info']['identities']:
print(' - %s' % str(identity))
if self.get in self.identity_types:
print('Identities:')
for identity in info['disco_info']['identities']:
print(' - %s' % str(identity))
if self.get in self.feature_types:
print('Features:')
for feature in info['disco_info']['features']:
print(' - %s' % feature)
if self.get in self.feature_types:
print('Features:')
for feature in info['disco_info']['features']:
print(' - %s' % feature)
if self.get in self.items_types:
print('Items:')
for item in items['disco_items']['items']:
print(' - %s' % str(item))
self.disconnect()
if self.get in self.items_types:
print('Items:')
for item in items['disco_items']['items']:
print(' - %s' % str(item))
finally:
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
optp.version = '%%prog 0.1'
optp.usage = "Usage: %%prog [options] %s <jid> [<node>]" % \
'all|info|items|identities|features'
parser = ArgumentParser(description=Disco.__doc__)
optp.add_option('-q','--quiet', help='set logging to ERROR',
action='store_const',
dest='loglevel',
const=logging.ERROR,
default=logging.ERROR)
optp.add_option('-d','--debug', help='set logging to DEBUG',
action='store_const',
dest='loglevel',
const=logging.DEBUG,
default=logging.ERROR)
optp.add_option('-v','--verbose', help='set logging to COMM',
action='store_const',
dest='loglevel',
const=5,
default=logging.ERROR)
parser.add_argument("-q","--quiet", help="set logging to ERROR",
action="store_const",
dest="loglevel",
const=logging.ERROR,
default=logging.ERROR)
parser.add_argument("-d","--debug", help="set logging to DEBUG",
action="store_const",
dest="loglevel",
const=logging.DEBUG,
default=logging.ERROR)
# JID and password options.
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
opts,args = optp.parse_args()
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("query", choices=["all", "info", "items", "identities", "features"])
parser.add_argument("target_jid")
parser.add_argument("node", nargs='?')
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if len(args) < 2:
optp.print_help()
exit()
if len(args) == 2:
args = (args[0], args[1], '')
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the Disco browser.
xmpp = Disco(opts.jid, opts.password, args[1], args[2], args[0])
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
xmpp = Disco(args.jid, args.password, args.target_jid, args.node, args.query)
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the pydns library installed, you will need
# to manually specify the name of the server if it does not match
# the one in the JID. For example, to use Google Talk you would
# need to use:
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
xmpp.process(threaded=False)
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process(forever=False)

165
examples/download_avatars.py Executable file
View File

@@ -0,0 +1,165 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2012 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp.exceptions import XMPPError
from slixmpp import asyncio
FILE_TYPES = {
'image/png': 'png',
'image/gif': 'gif',
'image/jpeg': 'jpg'
}
class AvatarDownloader(slixmpp.ClientXMPP):
"""
A basic script for downloading the avatars for a user's contacts.
"""
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.add_event_handler("session_start", self.start)
self.add_event_handler("changed_status", self.wait_for_presences)
self.add_event_handler('vcard_avatar_update', self.on_vcard_avatar)
self.add_event_handler('avatar_metadata_publish', self.on_avatar)
self.received = set()
self.presences_received = asyncio.Event()
self.roster_received = asyncio.Event()
def roster_received_cb(self, event):
self.roster_received.set()
self.presences_received.clear()
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self.send_presence()
self.get_roster(callback=self.roster_received_cb)
print('Waiting for presence updates...\n')
yield from self.roster_received.wait()
print('Roster received')
yield from self.presences_received.wait()
self.disconnect()
@asyncio.coroutine
def on_vcard_avatar(self, pres):
print("Received vCard avatar update from %s" % pres['from'].bare)
try:
result = yield from self['xep_0054'].get_vcard(pres['from'].bare, cached=True,
timeout=5)
except XMPPError:
print("Error retrieving avatar for %s" % pres['from'])
return
avatar = result['vcard_temp']['PHOTO']
filetype = FILE_TYPES.get(avatar['TYPE'], 'png')
filename = 'vcard_avatar_%s_%s.%s' % (
pres['from'].bare,
pres['vcard_temp_update']['photo'],
filetype)
with open(filename, 'wb+') as img:
img.write(avatar['BINVAL'])
@asyncio.coroutine
def on_avatar(self, msg):
print("Received avatar update from %s" % msg['from'])
metadata = msg['pubsub_event']['items']['item']['avatar_metadata']
for info in metadata['items']:
if not info['url']:
try:
result = yield from self['xep_0084'].retrieve_avatar(msg['from'].bare, info['id'],
timeout=5)
except XMPPError:
print("Error retrieving avatar for %s" % msg['from'])
return
avatar = result['pubsub']['items']['item']['avatar_data']
filetype = FILE_TYPES.get(metadata['type'], 'png')
filename = 'avatar_%s_%s.%s' % (msg['from'].bare, info['id'], filetype)
with open(filename, 'wb+') as img:
img.write(avatar['value'])
else:
# We could retrieve the avatar via HTTP, etc here instead.
pass
def wait_for_presences(self, pres):
"""
Wait to receive updates from all roster contacts.
"""
self.received.add(pres['from'].bare)
print((len(self.received), len(self.client_roster.keys())))
if len(self.received) >= len(self.client_roster.keys()):
self.presences_received.set()
else:
self.presences_received.clear()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
parser.add_argument("-q","--quiet", help="set logging to ERROR",
action="store_const",
dest="loglevel",
const=logging.ERROR,
default=logging.ERROR)
parser.add_argument("-d","--debug", help="set logging to DEBUG",
action="store_const",
dest="loglevel",
const=logging.DEBUG,
default=logging.ERROR)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
xmpp = AvatarDownloader(args.jid, args.password)
xmpp.register_plugin('xep_0054')
xmpp.register_plugin('xep_0153')
xmpp.register_plugin('xep_0084')
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process()

View File

@@ -1,45 +1,35 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import logging
import time
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
import slixmpp
class EchoBot(sleekxmpp.ClientXMPP):
class EchoBot(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that will echo messages it
A simple Slixmpp bot that will echo messages it
receives, along with a short thank you message.
"""
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can intialize
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
@@ -53,7 +43,7 @@ class EchoBot(sleekxmpp.ClientXMPP):
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an intial
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
@@ -76,67 +66,48 @@ class EchoBot(sleekxmpp.ClientXMPP):
for stanza objects and the Message stanza to see
how it may be used.
"""
msg.reply("Thanks for sending\n%(body)s" % msg).send()
if msg['type'] in ('chat', 'normal'):
msg.reply("Thanks for sending\n%(body)s" % msg).send()
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser(description=EchoBot.__doc__)
# Output verbosity options.
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)
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
opts, args = optp.parse_args()
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the EchoBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = EchoBot(opts.jid, opts.password)
xmpp = EchoBot(args.jid, args.password)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
xmpp.register_plugin('xep_0199') # XMPP Ping
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the pydns library installed, you will need
# to manually specify the name of the server if it does not match
# the one in the JID. For example, to use Google Talk you would
# need to use:
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
xmpp.process(threaded=False)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

105
examples/echo_component.py Executable file
View File

@@ -0,0 +1,105 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp.componentxmpp import ComponentXMPP
class EchoComponent(ComponentXMPP):
"""
A simple Slixmpp component that echoes messages.
"""
def __init__(self, jid, secret, server, port):
ComponentXMPP.__init__(self, jid, secret, server, port)
# You don't need a session_start handler, but that is
# where you would broadcast initial presence.
# The message event is triggered whenever a message
# stanza is received. Be aware that that includes
# MUC messages and error messages.
self.add_event_handler("message", self.message)
def message(self, msg):
"""
Process incoming message stanzas. Be aware that this also
includes MUC messages and error messages. It is usually
a good idea to check the messages's type before processing
or sending replies.
Since a component may send messages from any number of JIDs,
it is best to always include a from JID.
Arguments:
msg -- The received message stanza. See the documentation
for stanza objects and the Message stanza to see
how it may be used.
"""
# The reply method will use the messages 'to' JID as the
# outgoing reply's 'from' JID.
msg.reply("Thanks for sending\n%(body)s" % msg).send()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser(description=EchoComponent.__doc__)
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-s", "--server", dest="server",
help="server to connect to")
parser.add_argument("-P", "--port", dest="port",
help="port to connect to")
args = parser.parse_args()
if args.jid is None:
args.jid = input("Component JID: ")
if args.password is None:
args.password = getpass("Password: ")
if args.server is None:
args.server = input("Server: ")
if args.port is None:
args.port = int(input("Port: "))
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
# Setup the EchoComponent and register plugins. Note that while plugins
# may have interdependencies, the order in which you register them does
# not matter.
xmpp = EchoComponent(args.jid, args.password, args.server, args.port)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
xmpp.register_plugin('xep_0199') # XMPP Ping
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process()

133
examples/gtalk_custom_domain.py Executable file
View File

@@ -0,0 +1,133 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
import ssl
from slixmpp.xmlstream import cert
class GTalkBot(slixmpp.ClientXMPP):
"""
A demonstration of using Slixmpp with accounts from a Google Apps
account with a custom domain, because it requires custom certificate
validation.
"""
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
# The message event is triggered whenever a message
# stanza is received. Be aware that that includes
# MUC messages and error messages.
self.add_event_handler("message", self.message)
# Using a Google Apps custom domain, the certificate
# does not contain the custom domain, just the GTalk
# server name. So we will need to process invalid
# certifcates ourselves and check that it really
# is from Google.
self.add_event_handler("ssl_invalid_cert", self.invalid_cert)
def invalid_cert(self, pem_cert):
der_cert = ssl.PEM_cert_to_DER_cert(pem_cert)
try:
cert.verify('talk.google.com', der_cert)
logging.debug("CERT: Found GTalk certificate")
except cert.CertificateError as err:
log.error(err.message)
self.disconnect(send_close=False)
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self.send_presence()
self.get_roster()
def message(self, msg):
"""
Process incoming message stanzas. Be aware that this also
includes MUC messages and error messages. It is usually
a good idea to check the messages's type before processing
or sending replies.
Arguments:
msg -- The received message stanza. See the documentation
for stanza objects and the Message stanza to see
how it may be used.
"""
if msg['type'] in ('chat', 'normal'):
msg.reply("Thanks for sending\n%(body)s" % msg).send()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the GTalkBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = GTalkBot(args.jid, args.password)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
xmpp.register_plugin('xep_0199') # XMPP Ping
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process()

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Implementation of HTTP over XMPP transport
http://xmpp.org/extensions/xep-0332.html
Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
This file is part of slixmpp.
See the file LICENSE for copying permission.
"""
from slixmpp import ClientXMPP
from optparse import OptionParser
import logging
import getpass
class HTTPOverXMPPClient(ClientXMPP):
def __init__(self, jid, password):
ClientXMPP.__init__(self, jid, password)
self.register_plugin('xep_0332') # HTTP over XMPP Transport
self.add_event_handler(
'session_start', self.session_start, threaded=True
)
self.add_event_handler('http_request', self.http_request_received)
self.add_event_handler('http_response', self.http_response_received)
def http_request_received(self, iq):
pass
def http_response_received(self, iq):
print('HTTP Response Received : %s' % iq)
print('From : %s' % iq['from'])
print('To : %s' % iq['to'])
print('Type : %s' % iq['type'])
print('Headers : %s' % iq['resp']['headers'])
print('Code : %s' % iq['resp']['code'])
print('Message : %s' % iq['resp']['message'])
print('Data : %s' % iq['resp']['data'])
def session_start(self, event):
# TODO: Fill in the blanks
self['xep_0332'].send_request(
to='?', method='?', resource='?', headers={}
)
self.disconnect()
if __name__ == '__main__':
#
# NOTE: To run this example, fill up the blanks in session_start() and
# use the following command.
#
# ./http_over_xmpp.py -J <jid> -P <pwd> -i <ip> -p <port> [-v]
#
parser = OptionParser()
# Output verbosity options.
parser.add_option(
'-v', '--verbose', help='set logging to DEBUG', action='store_const',
dest='loglevel', const=logging.DEBUG, default=logging.ERROR
)
# JID and password options.
parser.add_option('-J', '--jid', dest='jid', help='JID')
parser.add_option('-P', '--password', dest='password', help='Password')
# XMPP server ip and port options.
parser.add_option(
'-i', '--ipaddr', dest='ipaddr',
help='IP Address of the XMPP server', default=None
)
parser.add_option(
'-p', '--port', dest='port',
help='Port of the XMPP server', default=None
)
opts, args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
format='%(levelname)-8s %(message)s')
if opts.jid is None:
opts.jid = input('Username: ')
if opts.password is None:
opts.password = getpass.getpass('Password: ')
xmpp = HTTPOverXMPPClient(opts.jid, opts.password)
xmpp.connect()
xmpp.process()

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
class IBBReceiver(slixmpp.ClientXMPP):
"""
A basic example of creating and using an in-band bytestream.
"""
def __init__(self, jid, password, filename):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.file = open(filename, 'wb')
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
self.add_event_handler("ibb_stream_start", self.stream_opened)
self.add_event_handler("ibb_stream_data", self.stream_data)
self.add_event_handler("ibb_stream_end", self.stream_closed)
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self.send_presence()
self.get_roster()
def stream_opened(self, stream):
print('Stream opened: %s from %s' % (stream.sid, stream.peer_jid))
def stream_data(self, stream):
self.file.write(stream.read())
def stream_closed(self, stream):
print('Stream closed: %s from %s' % (stream.sid, stream.peer_jid))
self.file.close()
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-o", "--out", dest="filename",
help="file to save to")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.filename is None:
args.filename = input("File path: ")
# Setup the IBBReceiver and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = IBBReceiver(args.jid, args.password, args.filename)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0047', {
'auto_accept': True
}) # In-band Bytestreams
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process(forever=False)

View File

@@ -0,0 +1,125 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import asyncio
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp.exceptions import IqError, IqTimeout
class IBBSender(slixmpp.ClientXMPP):
"""
A basic example of creating and using an in-band bytestream.
"""
def __init__(self, jid, password, receiver, filename, use_messages=False):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.receiver = receiver
self.file = open(filename, 'rb')
self.use_messages = use_messages
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
event -- An empty dictionary. The session_start
event does not provide any additional
data.
"""
self.send_presence()
self.get_roster()
try:
# Open the IBB stream in which to write to.
stream = yield from self['xep_0047'].open_stream(self.receiver, use_messages=self.use_messages)
# If you want to send in-memory bytes, use stream.sendall() instead.
yield from stream.sendfile(self.file, timeout=10)
# And finally close the stream.
yield from stream.close(timeout=10)
except (IqError, IqTimeout):
print('File transfer errored')
else:
print('File transfer finished')
finally:
self.file.close()
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-r", "--receiver", dest="receiver",
help="JID of the receiver")
parser.add_argument("-f", "--file", dest="filename",
help="file to send")
parser.add_argument("-m", "--use-messages", action="store_true",
help="use messages instead of iqs for file transfer")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.receiver is None:
args.receiver = input("Receiver: ")
if args.filename is None:
args.filename = input("File path: ")
# Setup the IBBSender and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = IBBSender(args.jid, args.password, args.receiver, args.filename, args.use_messages)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0047') # In-band Bytestreams
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process(forever=False)

107
examples/migrate_roster.py Executable file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
# Setup the command line arguments.
parser = ArgumentParser()
# Output verbosity options.
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
parser.add_argument("--oldjid", dest="old_jid",
help="JID of the old account")
parser.add_argument("--oldpassword", dest="old_password",
help="password of the old account")
parser.add_argument("--newjid", dest="new_jid",
help="JID of the old account")
parser.add_argument("--newpassword", dest="new_password",
help="password of the old account")
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.old_jid is None:
args.old_jid = input("Old JID: ")
if args.old_password is None:
args.old_password = getpass("Old Password: ")
if args.new_jid is None:
args.new_jid = input("New JID: ")
if args.new_password is None:
args.new_password = getpass("New Password: ")
old_xmpp = slixmpp.ClientXMPP(args.old_jid, args.old_password)
# If you are connecting to Facebook and wish to use the
# X-FACEBOOK-PLATFORM authentication mechanism, you will need
# your API key and an access token. Then you'll set:
# xmpp.credentials['api_key'] = 'THE_API_KEY'
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
# If you are connecting to MSN, then you will need an
# access token, and it does not matter what JID you
# specify other than that the domain is 'messenger.live.com',
# so '_@messenger.live.com' will work. You can specify
# the access token as so:
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
roster = []
def on_session(event):
roster.append(old_xmpp.get_roster())
old_xmpp.disconnect()
old_xmpp.add_event_handler('session_start', on_session)
if old_xmpp.connect():
old_xmpp.process(block=True)
if not roster:
print('No roster to migrate')
sys.exit()
new_xmpp = slixmpp.ClientXMPP(args.new_jid, args.new_password)
def on_session2(event):
new_xmpp.get_roster()
new_xmpp.send_presence()
logging.info(roster[0])
data = roster[0]['roster']['items']
logging.info(data)
for jid, item in data.items():
if item['subscription'] != 'none':
new_xmpp.send_presence(ptype='subscribe', pto=jid)
new_xmpp.update_roster(jid,
name = item['name'],
groups = item['groups'])
new_xmpp.disconnect()
new_xmpp.add_event_handler('session_start', on_session2)
new_xmpp.connect()
new_xmpp.process()

View File

@@ -1,40 +1,31 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import logging
import time
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
import slixmpp
class MUCBot(sleekxmpp.ClientXMPP):
class MUCBot(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that will greets those
A simple Slixmpp bot that will greets those
who enter the room, and acknowledge any messages
that mentions the bot's nickname.
"""
def __init__(self, jid, password, room, nick):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
self.room = room
self.nick = nick
@@ -42,7 +33,7 @@ class MUCBot(sleekxmpp.ClientXMPP):
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can intialize
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
@@ -59,14 +50,14 @@ class MUCBot(sleekxmpp.ClientXMPP):
# muc::room@server::got_online, or muc::room@server::got_offline.
self.add_event_handler("muc::%s::got_online" % self.room,
self.muc_online)
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an intial
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
@@ -74,17 +65,17 @@ class MUCBot(sleekxmpp.ClientXMPP):
event does not provide any additional
data.
"""
self.getRoster()
self.sendPresence()
self.plugin['xep_0045'].joinMUC(self.room,
self.nick,
# If a room password is needed, use:
# password=the_room_password,
wait=True)
self.get_roster()
self.send_presence()
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):
"""
Process incoming message stanzas from any chat room. Be aware
Process incoming message stanzas from any chat room. Be aware
that if you also have any handlers for the 'message' event,
message stanzas may be processed by both handlers, so check
the 'type' attribute when using a 'message' event handler.
@@ -96,7 +87,7 @@ class MUCBot(sleekxmpp.ClientXMPP):
otherwise you will create an infinite loop responding
to your own messages.
This handler will reply to messages that mention
This handler will reply to messages that mention
the bot's nickname.
Arguments:
@@ -112,12 +103,12 @@ class MUCBot(sleekxmpp.ClientXMPP):
def muc_online(self, presence):
"""
Process a presence stanza from a chat room. In this case,
presences from users that have just come online are
presences from users that have just come online are
handled by sending a welcome message that includes
the user's nickname and role in the room.
Arguments:
presence -- The received presence stanza. See the
presence -- The received presence stanza. See the
documentation for the Presence stanza
to see how else it may be used.
"""
@@ -130,57 +121,49 @@ class MUCBot(sleekxmpp.ClientXMPP):
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser()
# Output verbosity options.
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)
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
optp.add_option("-r", "--room", dest="room",
help="MUC room to join")
optp.add_option("-n", "--nick", dest="nick",
help="MUC nickname")
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-r", "--room", dest="room",
help="MUC room to join")
parser.add_argument("-n", "--nick", dest="nick",
help="MUC nickname")
opts, args = optp.parse_args()
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if None in [opts.jid, opts.password, opts.room, opts.nick]:
optp.print_help()
sys.exit(1)
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.room is None:
args.room = input("MUC room: ")
if args.nick is None:
args.nick = input("MUC nickname: ")
# Setup the MUCBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = MUCBot(opts.jid, opts.password, opts.room, opts.nick)
xmpp = MUCBot(args.jid, args.password, args.room, args.nick)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0045') # Multi-User Chat
xmpp.register_plugin('xep_0199') # XMPP Ping
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the pydns library installed, you will need
# to manually specify the name of the server if it does not match
# the one in the JID. For example, to use Google Talk you would
# need to use:
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
xmpp.process(threaded=False)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,57 +1,50 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import logging
import time
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
from slixmpp.exceptions import IqError, IqTimeout
from slixmpp import asyncio
import sleekxmpp
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
import slixmpp
class PingTest(sleekxmpp.ClientXMPP):
class PingTest(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that will send a ping request
A simple Slixmpp bot that will send a ping request
to a given JID.
"""
def __init__(self, jid, password, pingjid):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
if pingjid is None:
pingjid = self.jid
pingjid = self.boundjid.bare
self.pingjid = pingjid
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can intialize
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an intial
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
@@ -61,80 +54,61 @@ class PingTest(sleekxmpp.ClientXMPP):
"""
self.send_presence()
self.get_roster()
result = self['xep_0199'].send_ping(self.pingjid,
timeout=10,
errorfalse=True)
logging.info("Pinging...")
if result is False:
logging.info("Couldn't ping.")
self.disconnect()
sys.exit(1)
else:
logging.info("Success! RTT: %s" % str(result))
try:
rtt = yield from self['xep_0199'].ping(self.pingjid,
timeout=10)
logging.info("Success! RTT: %s", rtt)
except IqError as e:
logging.info("Error pinging %s: %s",
self.pingjid,
e.iq['error']['condition'])
except IqTimeout:
logging.info("No response from %s", self.pingjid)
finally:
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser()
# Output verbosity options.
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('-t', '--pingto', help='set jid to ping',
action='store', type='string', dest='pingjid',
default=None)
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
parser.add_argument("-t", "--pingto", help="set jid to ping",
dest="pingjid", default=None)
# JID and password options.
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
opts, args = optp.parse_args()
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the PingTest and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = PingTest(opts.jid, opts.password, opts.pingjid)
xmpp = PingTest(args.jid, args.password, args.pingjid)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
xmpp.register_plugin('xep_0199') # XMPP Ping
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the pydns library installed, you will need
# to manually specify the name of the server if it does not match
# the one in the JID. For example, to use Google Talk you would
# need to use:
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
xmpp.process(threaded=False)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,45 +1,35 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import sys
import logging
import time
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
reload(sys)
sys.setdefaultencoding('utf8')
import slixmpp
class EchoBot(sleekxmpp.ClientXMPP):
class EchoBot(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that will echo messages it
A simple Slixmpp bot that will echo messages it
receives, along with a short thank you message.
"""
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use. We want to
# listen for this event so that we we can intialize
# listen for this event so that we we can initialize
# our roster.
self.add_event_handler("session_start", self.start)
@@ -53,7 +43,7 @@ class EchoBot(sleekxmpp.ClientXMPP):
Process the session_start event.
Typical actions for the session_start event are
requesting the roster and broadcasting an intial
requesting the roster and broadcasting an initial
presence stanza.
Arguments:
@@ -81,87 +71,65 @@ class EchoBot(sleekxmpp.ClientXMPP):
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser()
# Output verbosity options.
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)
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
# JID and password options.
optp.add_option("-j", "--jid", dest="jid",
help="JID to use")
optp.add_option("-p", "--password", dest="password",
help="password to use")
optp.add_option("--phost", dest="proxy_host",
help="Proxy hostname")
optp.add_option("--pport", dest="proxy_port",
help="Proxy port")
optp.add_option("--puser", dest="proxy_user",
help="Proxy username")
optp.add_option("--ppass", dest="proxy_pass",
help="Proxy password")
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("--phost", dest="proxy_host",
help="Proxy hostname")
parser.add_argument("--pport", dest="proxy_port",
help="Proxy port")
parser.add_argument("--puser", dest="proxy_user",
help="Proxy username")
parser.add_argument("--ppass", dest="proxy_pass",
help="Proxy password")
opts, args = optp.parse_args()
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if opts.proxy_host is None:
opts.proxy_host = raw_input("Proxy host: ")
if opts.proxy_port is None:
opts.proxy_port = raw_input("Proxy port: ")
if opts.proxy_user is None:
opts.proxy_user = raw_input("Proxy username: ")
if opts.proxy_pass is None and opts.proxy_user:
opts.proxy_pass = getpass.getpass("Proxy password: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.proxy_host is None:
args.proxy_host = input("Proxy host: ")
if args.proxy_port is None:
args.proxy_port = input("Proxy port: ")
if args.proxy_user is None:
args.proxy_user = input("Proxy username: ")
if args.proxy_pass is None and args.proxy_user:
args.proxy_pass = getpass("Proxy password: ")
# Setup the EchoBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = EchoBot(opts.jid, opts.password)
xmpp = EchoBot(args.jid, args.password)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
xmpp.register_plugin('xep_0199') # XMPP Ping
# If you are working with an OpenFire server, you may need
# to adjust the SSL version used:
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
xmpp.use_proxy = True
xmpp.proxy_config = {
'host': opts.proxy_host,
'port': int(opts.proxy_port),
'username': opts.proxy_user,
'password': opts.proxy_pass}
'host': args.proxy_host,
'port': int(args.proxy_port),
'username': args.proxy_user,
'password': args.proxy_pass}
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the pydns library installed, you will need
# to manually specify the name of the server if it does not match
# the one in the JID. For example, to use Google Talk you would
# need to use:
#
# if xmpp.connect(('talk.google.com', 5222)):
# ...
xmpp.process(threaded=False)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

166
examples/pubsub_client.py Executable file
View File

@@ -0,0 +1,166 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
from getpass import getpass
from argparse import ArgumentParser
import asyncio
import slixmpp
from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream import ET, tostring
class PubsubClient(slixmpp.ClientXMPP):
def __init__(self, jid, password, server,
node=None, action='nodes', data=''):
super().__init__(jid, password)
self.register_plugin('xep_0030')
self.register_plugin('xep_0059')
self.register_plugin('xep_0060')
self.actions = ['nodes', 'create', 'delete',
'publish', 'get', 'retract',
'purge', 'subscribe', 'unsubscribe']
self.action = action
self.node = node
self.data = data
self.pubsub_server = server
self.add_event_handler('session_start', self.start)
@asyncio.coroutine
def start(self, event):
self.get_roster()
self.send_presence()
try:
yield from getattr(self, self.action)()
except:
logging.error('Could not execute: %s', self.action)
self.disconnect()
def nodes(self):
try:
result = yield from self['xep_0060'].get_nodes(self.pubsub_server, self.node)
for item in result['disco_items']['items']:
logging.info(' - %s', str(item))
except XMPPError as error:
logging.error('Could not retrieve node list: %s', error.format())
def create(self):
try:
yield from self['xep_0060'].create_node(self.pubsub_server, self.node)
logging.info('Created node %s', self.node)
except XMPPError as error:
logging.error('Could not create node %s: %s', self.node, error.format())
def delete(self):
try:
yield from self['xep_0060'].delete_node(self.pubsub_server, self.node)
logging.info('Deleted node %s', self.node)
except XMPPError as error:
logging.error('Could not delete node %s: %s', self.node, error.format())
def publish(self):
payload = ET.fromstring("<test xmlns='test'>%s</test>" % self.data)
try:
result = yield from self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload)
logging.info('Published at item id: %s', result['pubsub']['publish']['item']['id'])
except XMPPError as error:
logging.error('Could not publish to %s: %s', self.node, error.format())
def get(self):
try:
result = yield from self['xep_0060'].get_item(self.pubsub_server, self.node, self.data)
for item in result['pubsub']['items']['substanzas']:
logging.info('Retrieved item %s: %s', item['id'], tostring(item['payload']))
except XMPPError as error:
logging.error('Could not retrieve item %s from node %s: %s', self.data, self.node, error.format())
def retract(self):
try:
yield from self['xep_0060'].retract(self.pubsub_server, self.node, self.data)
logging.info('Retracted item %s from node %s', self.data, self.node)
except XMPPError as error:
logging.error('Could not retract item %s from node %s: %s', self.data, self.node, error.format())
def purge(self):
try:
yield from self['xep_0060'].purge(self.pubsub_server, self.node)
logging.info('Purged all items from node %s', self.node)
except XMPPError as error:
logging.error('Could not purge items from node %s: %s', self.node, error.format())
def subscribe(self):
try:
iq = yield from self['xep_0060'].subscribe(self.pubsub_server, self.node)
subscription = iq['pubsub']['subscription']
logging.info('Subscribed %s to node %s', subscription['jid'], subscription['node'])
except XMPPError as error:
logging.error('Could not subscribe %s to node %s: %s', self.boundjid.bare, self.node, error.format())
def unsubscribe(self):
try:
yield from self['xep_0060'].unsubscribe(self.pubsub_server, self.node)
logging.info('Unsubscribed %s from node %s', self.boundjid.bare, self.node)
except XMPPError as error:
logging.error('Could not unsubscribe %s from node %s: %s', self.boundjid.bare, self.node, error.format())
if __name__ == '__main__':
# Setup the command line arguments.
parser = ArgumentParser()
parser.version = '%%prog 0.1'
parser.usage = "Usage: %%prog [options] <jid> " + \
'nodes|create|delete|purge|subscribe|unsubscribe|publish|retract|get' + \
' [<node> <data>]'
parser.add_argument("-q","--quiet", help="set logging to ERROR",
action="store_const",
dest="loglevel",
const=logging.ERROR,
default=logging.INFO)
parser.add_argument("-d","--debug", help="set logging to DEBUG",
action="store_const",
dest="loglevel",
const=logging.DEBUG,
default=logging.INFO)
# JID and password options.
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("server")
parser.add_argument("action", choices=["nodes", "create", "delete", "purge", "subscribe", "unsubscribe", "publish", "retract", "get"])
parser.add_argument("node", nargs='?')
parser.add_argument("data", nargs='?')
args = parser.parse_args()
# Setup logging.
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the Pubsub client
xmpp = PubsubClient(args.jid, args.password,
server=args.server,
node=args.node,
action=args.action,
data=args.data)
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process(forever=False)

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