Compare commits

...

366 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
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
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
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
ekini
ea3d39b50e added xep-0138 support (compression) 2012-07-23 15:39:07 +07:00
571 changed files with 12350 additions and 14296 deletions

3
.gitignore vendored
View File

@@ -6,9 +6,10 @@ docs/_build/
*.swp
.tox/
.coverage
sleekxmpp.egg-info/
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]

View File

@@ -1,6 +1,7 @@
include README.rst
include LICENSE
include testall.py
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

View File

@@ -1,77 +1,21 @@
SleekXMPP
Slixmpp
#########
SleekXMPP is an MIT licensed XMPP library for Python 2.6/3.1+,
and is featured in examples in
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived
here from reading the Definitive Guide, please see the notes on updating
the examples to the latest version of SleekXMPP.
Slixmpp is an MIT licensed XMPP library for Python 3.4+. It is a fork of
SleekXMPP.
SleekXMPP's design goals and philosphy are:
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.
**Low number of dependencies**
Installing and using SleekXMPP should be as simple as possible, without
having to deal with long dependency chains.
Building
--------
As part of reducing the number of dependencies, some third party
modules are included with SleekXMPP in the ``thirdparty`` directory.
Imports from this module first try to import an existing installed
version before loading the packaged version, when possible.
**Every XEP as a plugin**
Following Python's "batteries included" approach, the goal is to
provide support for all currently active XEPs (final and draft). Since
adding XEP support is done through easy to create plugins, the hope is
to also provide a solid base for implementing and creating experimental
XEPs.
**Rewarding to work with**
As much as possible, SleekXMPP should allow things to "just work" using
sensible defaults and appropriate abstractions. XML can be ugly to work
with, but it doesn't have to be that way.
Get the Code
------------
Get the latest stable version from PyPI::
pip install sleekxmpp
The latest source code for SleekXMPP may be found on `Github
<http://github.com/fritzy/SleekXMPP>`_. Releases can be found in the
``master`` branch, while the latest development version is in the
``develop`` branch.
**Latest Release**
- `1.2.5 <http://github.com/fritzy/SleekXMPP/zipball/1.2.5>`_
**Develop Releases**
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
Installing DNSPython
---------------------
If you are using Python3 and wish to use dnspython, you will have to checkout and
install the ``python3`` branch::
git clone http://github.com/rthalley/dnspython
cd dnspython
git checkout python3
python3 setup.py install
Discussion
----------
A mailing list and XMPP chat room are available for discussing and getting
help with SleekXMPP.
**Mailing List**
`SleekXMPP Discussion on Google Groups <http://groups.google.com/group/sleekxmpp-discussion>`_
**Chat**
`sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_
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
-------------------------
@@ -83,22 +27,22 @@ be in ``docs/_build/html``::
make html
open _build/html/index.html
To run the test suite for SleekXMPP::
To run the test suite for Slixmpp::
python testall.py
python run_tests.py
The SleekXMPP Boilerplate
The Slixmpp Boilerplate
-------------------------
Projects using SleekXMPP tend to follow a basic pattern for setting up client/component
connections and configuration. Here is the gist of the boilerplate needed for a SleekXMPP
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
SleekXMPP projects::
Slixmpp projects::
import logging
from sleekxmpp import ClientXMPP
from sleekxmpp.exceptions import IqError, IqTimeout
from slixmpp import ClientXMPP
from slixmpp.exceptions import IqError, IqTimeout
class EchoBot(ClientXMPP):
@@ -144,7 +88,7 @@ SleekXMPP projects::
if __name__ == '__main__':
# Ideally use optparse or argparse to get JID,
# Ideally use optparse or argparse to get JID,
# password, and log level.
logging.basicConfig(level=logging.DEBUG,
@@ -152,21 +96,37 @@ SleekXMPP projects::
xmpp = EchoBot('somejid@example.com', 'use_getpass')
xmpp.connect()
xmpp.process(block=True)
xmpp.process(forever=True)
Credits
-------
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@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
<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@gmail.com <xmpp:lancestout@gmail.com?message>`_,
`@lancestout <http://twitter.com/lancestout>`_
**Contributors:**

View File

@@ -72,17 +72,17 @@ qthelp:
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SleekXMPP.qhcp"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Slixmpp.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SleekXMPP.qhc"
@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/SleekXMPP"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SleekXMPP"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Slixmpp"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Slixmpp"
@echo "# devhelp"
epub:

View File

@@ -8,11 +8,11 @@
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: Arial, sans-serif;
font-size: 100%;
@@ -34,18 +34,18 @@ div.bodywrapper {
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%;
@@ -53,12 +53,12 @@ div.footer {
text-align: center;
font-size: 75%;
}
div.footer a {
color: #444;
text-decoration: underline;
}
div.related {
background-color: #6BA81E;
line-height: 32px;
@@ -66,11 +66,11 @@ div.related {
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;
@@ -79,7 +79,7 @@ div.sphinxsidebar {
div.sphinxsidebarwrapper{
padding: 20px 0;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4 {
font-family: Arial, sans-serif;
@@ -95,30 +95,30 @@ div.sphinxsidebar h4 {
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;
@@ -128,19 +128,19 @@ div.sphinxsidebar input {
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,
@@ -155,30 +155,30 @@ div.body h6 {
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;
}
@@ -191,29 +191,29 @@ 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;
@@ -225,7 +225,7 @@ pre {
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
-moz-box-shadow: 1px 1px 1px #d8d8d8;
}
tt {
background-color: #ecf0f3;
color: #222;

View File

@@ -134,7 +134,7 @@ div.footer a {
/* -- body styles ----------------------------------------------------------- */
p {
p {
margin: 0.8em 0 0.5em 0;
}

View File

@@ -2,7 +2,7 @@
BaseXMPP
========
.. module:: sleekxmpp.basexmpp
.. module:: slixmpp.basexmpp
.. autoclass:: BaseXMPP
:members:

View File

@@ -2,7 +2,7 @@
ClientXMPP
==========
.. module:: sleekxmpp.clientxmpp
.. module:: slixmpp.clientxmpp
.. autoclass:: ClientXMPP
:members:

View File

@@ -2,7 +2,7 @@
ComponentXMPP
=============
.. module:: sleekxmpp.componentxmpp
.. module:: slixmpp.componentxmpp
.. autoclass:: ComponentXMPP
:members:

View File

@@ -1,9 +1,9 @@
Exceptions
==========
.. module:: sleekxmpp.exceptions
.. module:: slixmpp.exceptions
.. autoexception:: XMPPError
: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

@@ -1,12 +0,0 @@
.. module:: sleekxmpp.xmlstream.filesocket
.. _filesocket:
Python 2.6 File Socket Shims
============================
.. autoclass:: FileSocket
:members:
.. autoclass:: Socket26
:members:

View File

@@ -3,22 +3,26 @@ Stanza Handlers
The Basic Handler
-----------------
.. module:: sleekxmpp.xmlstream.handler.base
.. module:: slixmpp.xmlstream.handler.base
.. autoclass:: BaseHandler
:members:
Callback
--------
.. module:: sleekxmpp.xmlstream.handler.callback
.. module:: slixmpp.xmlstream.handler
.. autoclass:: Callback
:members:
CoroutineCallback
-----------------
.. autoclass:: CoroutineCallback
:members:
Waiter
------
.. module:: sleekxmpp.xmlstream.handler.waiter
.. autoclass:: Waiter
:members:

View File

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

View File

@@ -3,7 +3,7 @@ Stanza Matchers
The Basic Matcher
-----------------
.. module:: sleekxmpp.xmlstream.matcher.base
.. module:: slixmpp.xmlstream.matcher.base
.. autoclass:: MatcherBase
:members:
@@ -11,7 +11,7 @@ The Basic Matcher
ID Matching
-----------
.. module:: sleekxmpp.xmlstream.matcher.id
.. module:: slixmpp.xmlstream.matcher.id
.. autoclass:: MatcherId
:members:
@@ -19,7 +19,7 @@ ID Matching
Stanza Path Matching
--------------------
.. module:: sleekxmpp.xmlstream.matcher.stanzapath
.. module:: slixmpp.xmlstream.matcher.stanzapath
.. autoclass:: StanzaPath
:members:
@@ -27,7 +27,7 @@ Stanza Path Matching
XPath
-----
.. module:: sleekxmpp.xmlstream.matcher.xpath
.. module:: slixmpp.xmlstream.matcher.xpath
.. autoclass:: MatchXPath
:members:
@@ -35,7 +35,7 @@ XPath
XMLMask
-------
.. module:: sleekxmpp.xmlstream.matcher.xmlmask
.. module:: slixmpp.xmlstream.matcher.xmlmask
.. autoclass:: MatchXMLMask
:members:

View File

@@ -1,11 +0,0 @@
=========
Scheduler
=========
.. module:: sleekxmpp.xmlstream.scheduler
.. autoclass:: Task
:members:
.. autoclass:: Scheduler
:members:

View File

@@ -4,9 +4,9 @@
Stanza Objects
==============
.. module:: sleekxmpp.xmlstream.stanzabase
.. module:: slixmpp.xmlstream.stanzabase
The :mod:`~sleekmxpp.xmlstream.stanzabase` module provides a wrapper for the
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
@@ -52,17 +52,17 @@ elements of the original XML chunk.
.. seealso::
:ref:`create-stanza-interfaces`.
Because the :mod:`~sleekxmpp.xmlstream.stanzabase` module was developed
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 SleekXMPP we refer to a
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`, are accessible through a special
``'substanzas'`` interface. This option is useful for stanzas which
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
@@ -72,7 +72,7 @@ plugin stanza object. Here is an example:
<iq type="result">
<query xmlns="http://jabber.org/protocol/disco#info">
<identity category="client" type="bot" name="SleekXMPP Bot" />
<identity category="client" type="bot" name="Slixmpp Bot" />
</query>
</iq>
@@ -84,13 +84,13 @@ we can access the plugin as so::
>>> iq['disco_info']
'<query xmlns="http://jabber.org/protocol/disco#info">
<identity category="client" type="bot" name="SleekXMPP Bot" />
<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', 'SleekXMPP Bot')]
[('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
@@ -101,7 +101,7 @@ of an interface defined by the parent.
- :ref:`create-stanza-plugins`
- :ref:`create-extension-plugins`
- :ref:`override-parent-interfaces`
Registering Stanza Plugins
--------------------------

View File

@@ -1,18 +1,18 @@
.. module:: sleekxmpp.xmlstream.tostring
.. module:: slixmpp.xmlstream.tostring
.. _tostring:
XML Serialization
=================
Since the XML layer of SleekXMPP is based on :mod:`~xml.etree.ElementTree`,
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 sleekxmpp.xmlstream.tostring import tostring
>>> from slixmpp.xmlstream.tostring import tostring
>>> from xml.etree import cElementTree as ET
>>> xml = ET.fromstring('<foo xmlns="bar"><baz /></foo>')
>>> ET.tostring(xml)
@@ -25,10 +25,10 @@ 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:`~sleekxmpp.stanza.message.Message` instance and dump
you create a :class:`~slixmpp.stanza.message.Message` instance and dump
it to the terminal, the ``jabber:client`` namespace will appear.
.. autofunction:: tostring
.. autofunction:: slixmpp.xmlstream.tostring
Escaping Special Characters
---------------------------
@@ -43,4 +43,5 @@ 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
..
autofunction:: xml_escape

View File

@@ -2,9 +2,7 @@
XML Stream
==========
.. module:: sleekxmpp.xmlstream.xmlstream
.. autoexception:: RestartStream
.. module:: slixmpp.xmlstream.xmlstream
.. autoclass:: XMLStream
:members:

View File

@@ -1,9 +1,9 @@
.. index:: XMLStream, BaseXMPP, ClientXMPP, ComponentXMPP
SleekXMPP Architecture
Slixmpp Architecture
======================
The core of SleekXMPP is contained in four classes: ``XMLStream``,
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.
@@ -17,28 +17,27 @@ of the tedium of creating/manipulating XML.
The Foundation: XMLStream
-------------------------
:class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic
: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 Main Threads
~~~~~~~~~~~~~~~~
:class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` instances run using at
least three background threads: the send thread, the read thread, and the
scheduler thread. The send thread is in charge of monitoring the send queue
and writing text to the outgoing XML stream. The read thread pulls text off
of the incoming XML stream and stores the results in an event queue. The
scheduler thread is used to emit events after a given period of time.
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.
Additionally, the main event processing loop may be executed in its
own thread if SleekXMPP is being used in the background for another
application.
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`.
Short-lived threads may also be spawned as requested for threaded
:term:`event handlers <event handler>`.
: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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -53,7 +52,7 @@ when this bit of XML is received (with an assumed namespace of
</message>
1. **Convert XML strings into objects.**
#. **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
@@ -61,95 +60,69 @@ when this bit of XML is received (with an assumed namespace of
new object is determined using a map of namespaced element names to
classes.
Our incoming XML is thus turned into a :class:`~sleekxmpp.stanza.Message`
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:`~sleekxmpp.stanza.Message`.
:class:`~slixmpp.stanza.Message`.
2. **Match stanza objects to callbacks.**
#. **Match stanza objects to callbacks.**
These objects are then compared against the stored patterns associated
with the registered callback handlers. For each match, a copy of the
:term:`stanza object` is paired with a reference to the handler and
placed into the event queue.
with the registered callback handlers.
Our :class:`~sleekxmpp.stanza.Message` object is thus paired with the message stanza handler
:meth:`BaseXMPP._handle_message` to create the tuple::
Each handler matching our :term:`stanza object` is then added to a list.
('stanza', stanza_obj, handler)
#. **Processing callbacks**
3. **Process the event queue.**
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.
The event queue is the heart of SleekXMPP. Nearly every action that
takes place is first inserted into this queue, whether that be received
stanzas, custom events, or scheduled events.
When the stanza is pulled out of the event queue with an associated
callback, the callback function is executed with the stanza as its only
parameter.
.. warning::
The callback, aka :term:`stream handler`, is executed in the main event
processing thread. If the handler blocks, event processing will also
block.
4. **Raise Custom Events**
#. **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:`~sleekxmpp.stanza.Iq` stanza), then custom events must be used.
: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. Importantly, these events may be handled in their
own thread.
be raised at any time.
When the event is raised, a copy of the stanza is created for each
handler registered for the event. In contrast to :term:`stream handlers
<stream handler>`, these functions are referred to as :term:`event
handlers <event handler>`. Each stanza/handler pair is then put into the
event queue.
.. note::
It is possible to skip the event queue and process an event immediately
by using ``direct=True`` when raising the event.
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::
raises a ``'message'`` event
self.event('message', msg)
.. code-block:: python
The event call then places the message object back into the event queue
paired with an :term:`event handler`::
self.event('message', msg)
('event', 'message', msg_copy1, custom_event_handler_1)
('event', 'message', msg_copy2, custom_evetn_handler_2)
#. **Process Custom Events**
5. **Process Custom Events**
The stanza and :term:`event handler` are then pulled from the event
queue, and the handler is executed, passing the stanza as its only
argument. If the handler was registered as threaded, then a new thread
will be spawned for it.
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')``.
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::
msg.reply()
msg['body'] = "Hey! This is awesome!"
msg.send()
reply = msg.reply()
reply['body'] = "Hey! This is awesome!"
reply.send()
.. index:: BaseXMPP, XMLStream
Raising XMPP Awareness: BaseXMPP
--------------------------------
While :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` attempts to shy away
from anything too XMPP specific, :class:`~sleekxmpp.basexmpp.BaseXMPP`'s
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
@@ -157,14 +130,14 @@ default handlers for incoming messages and keeping track of presence
notifications.
The plugin system for adding new XEP support is also maintained by
:class:`~sleekxmpp.basexmpp.BaseXMPP`.
:class:`~slixmpp.basexmpp.BaseXMPP`.
.. index:: ClientXMPP, BaseXMPP
ClientXMPP
----------
:class:`~sleekxmpp.clientxmpp.ClientXMPP` extends
:class:`~sleekxmpp.clientxmpp.BaseXMPP` with additional logic for connecting
: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.
@@ -172,6 +145,6 @@ features such as STARTTLS and SASL.
ComponentXMPP
-------------
:class:`~sleekxmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of
:class:`~sleekxmpp.basexmpp.BaseXMPP` that implements the component handshake
:class:`~slixmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of
:class:`~slixmpp.basexmpp.BaseXMPP` that implements the component handshake
protocol.

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# SleekXMPP documentation build configuration file, created by
# 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.
@@ -40,7 +40,7 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'SleekXMPP'
project = u'Slixmpp'
copyright = u'2011, Nathan Fritz, Lance Stout'
# The version info for the project you're documenting, acts as replacement for
@@ -48,9 +48,9 @@ copyright = u'2011, Nathan Fritz, Lance Stout'
# built documents.
#
# The short X.Y version.
version = '1.0'
version = '1.1'
# The full version, including alpha/beta/rc tags.
release = '1.0'
release = '1.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -105,7 +105,7 @@ html_theme = 'haiku'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = 'SleekXMPP'
html_title = 'slixmpp'
# A shorter title for the navigation bar. Default is the same as html_title.
html_short_title = '%s Documentation' % release
@@ -168,7 +168,7 @@ html_additional_pages = {
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'SleekXMPPdoc'
htmlhelp_basename = 'Slixmppdoc'
# -- Options for LaTeX output --------------------------------------------------
@@ -182,7 +182,7 @@ htmlhelp_basename = 'SleekXMPPdoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'SleekXMPP.tex', u'SleekXMPP Documentation',
('index', 'Slixmpp.tex', u'Slixmpp Documentation',
u'Nathan Fritz, Lance Stout', 'manual'),
]
@@ -215,8 +215,8 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'sleekxmpp', u'SleekXMPP Documentation',
('index', 'slixmpp', u'Slixmpp Documentation',
[u'Nathan Fritz, Lance Stout'], 1)
]
intersphinx_mapping = {'python': ('http://docs.python.org/3.2', 'python-objects.inv')}
intersphinx_mapping = {'python': ('http://docs.python.org/3.4', 'python-objects.inv')}

View File

@@ -1,10 +1,10 @@
.. _create-plugin:
Creating a SleekXMPP Plugin
Creating a Slixmpp Plugin
===========================
One of the goals of SleekXMPP is to provide support for every draft or final
XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, SleekXMPP has a
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
@@ -14,11 +14,11 @@ 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 SleekXMPP
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 SleekXMPP
different, more robust, official plugin for XEP-0077 may be added to Slixmpp
in the future.
.. note::
@@ -29,10 +29,10 @@ in the future.
First Steps
-----------
Every plugin inherits from the class :mod:`base_plugin <sleekxmpp.plugins.base.base_plugin>`,
Every plugin inherits from the class :mod:`BasePlugin <slixmpp.plugins.base.BasePlugin`,
and must include a ``plugin_init`` method. While the
plugins distributed with SleekXMPP must be placed in the plugins directory
``sleekxmpp/plugins`` to be loaded, custom plugins may be loaded from any
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
@@ -40,9 +40,9 @@ module. To do so, use the following form when registering the plugin:
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
``SleekXMPP/sleekxmpp/plugins``. We want to do some basic house-keeping and
``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.
@@ -50,15 +50,15 @@ attribute.
.. code-block:: python
"""
Creating a SleekXMPP Plugin
Creating a Slixmpp Plugin
This is a minimal implementation of XEP-0077 to serve
as a tutorial for creating SleekXMPP plugins.
as a tutorial for creating Slixmpp plugins.
"""
from sleekxmpp.plugins.base import base_plugin
from slixmpp.plugins.base import BasePlugin
class xep_0077(base_plugin):
class xep_0077(BasePlugin):
"""
XEP-0077 In-Band Registration
"""
@@ -68,7 +68,7 @@ attribute.
self.xep = "0077"
Now that we have a basic plugin, we need to edit
``sleekxmpp/plugins/__init__.py`` to include our new plugin by adding
``slixmpp/plugins/__init__.py`` to include our new plugin by adding
``'xep_0077'`` to the ``__all__`` declaration.
Interacting with Other Plugins
@@ -81,20 +81,20 @@ 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 ``base_plugin.post_init(self)``
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
SleekXMPP object begins processing, ``post_init`` will be called on any plugins
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'``. SleekXMPP
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):
base_plugin.post_init(self)
BasePlugin.post_init(self)
self.xmpp['xep_0030'].add_feature("jabber:iq:register")
Creating Custom Stanza Objects
@@ -141,7 +141,7 @@ behaviour:
**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 SleekXMPP.
case in a future version of Slixmpp.
* ``sub_interfaces``
A subset of ``interfaces``, but these keys map to the text of any
@@ -156,8 +156,8 @@ behaviour:
.. code-block:: python
from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
from sleekxmpp import Iq
from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
from slixmpp import Iq
class Registration(ElementBase):
namespace = 'jabber:iq:register'
@@ -209,7 +209,7 @@ 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
``sleekxmpp.xmlstream.stanzabase``) which takes the class of a parent stanza
``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.
@@ -347,7 +347,7 @@ method ``setForm`` which will take the names of the fields we wish to include.
# Add a blank field
reg.addField(field)
iq.reply().setPayload(reg.xml)
iq.reply().set_payload(reg.xml)
iq.send()
Note how we are able to access our ``Registration`` stanza object with
@@ -421,7 +421,7 @@ to the IQ reply.
...
def _sendError(self, iq, code, error_type, name, text=''):
iq.reply().setPayload(iq['register'].xml)
iq.reply().set_payload(iq['register'].xml)
iq.error()
iq['error']['code'] = code
iq['error']['type'] = error_type
@@ -464,7 +464,7 @@ component examples below for how to respond to this event.
if self.backend.register(iq['from'].bare, iq['register']):
# Successful registration
self.xmpp.event('registered_user', iq)
iq.reply().setPayload(iq['register'].xml)
iq.reply().set_payload(iq['register'].xml)
iq.send()
else:
# Conflicting registration
@@ -484,15 +484,15 @@ and that we specified the form fields we wish to use with
.. code-block:: python
import sleekxmpp.componentxmpp
import slixmpp.componentxmpp
class Example(sleekxmpp.componentxmpp.ComponentXMPP):
class Example(slixmpp.componentxmpp.ComponentXMPP):
def __init__(self, jid, password):
sleekxmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888)
slixmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888)
self.registerPlugin('xep_0030')
self.registerPlugin('xep_0077')
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)
@@ -500,11 +500,11 @@ and that we specified the form fields we wish to use with
def reg(self, iq):
msg = "Welcome! %s" % iq['register']['username']
self.sendMessage(iq['from'], msg, mfrom=self.fulljid)
self.send_message(iq['from'], msg, mfrom=self.fulljid)
def unreg(self, iq):
msg = "Bye! %s" % iq['register']['username']
self.sendMessage(iq['from'], msg, mfrom=self.fulljid)
self.send_message(iq['from'], msg, mfrom=self.fulljid)
**Congratulations!** We now have a basic, functioning implementation of
XEP-0077.
@@ -517,17 +517,17 @@ with some additional registration fields implemented.
.. code-block:: python
"""
Creating a SleekXMPP Plugin
Creating a Slixmpp Plugin
This is a minimal implementation of XEP-0077 to serve
as a tutorial for creating SleekXMPP plugins.
as a tutorial for creating Slixmpp plugins.
"""
from sleekxmpp.plugins.base import base_plugin
from sleekxmpp.xmlstream.handler.callback import Callback
from sleekxmpp.xmlstream.matcher.xpath import MatchXPath
from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
from sleekxmpp import Iq
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
@@ -535,9 +535,9 @@ with some additional registration fields implemented.
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',
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
@@ -589,7 +589,7 @@ with some additional registration fields implemented.
def unregister(self, jid):
del self.users[jid]
class xep_0077(base_plugin):
class xep_0077(BasePlugin):
"""
XEP-0077 In-Band Registration
"""
@@ -608,7 +608,7 @@ with some additional registration fields implemented.
register_stanza_plugin(Iq, Registration)
def post_init(self):
base_plugin.post_init(self)
BasePlugin.post_init(self)
self.xmpp['xep_0030'].add_feature("jabber:iq:register")
def __handleRegistration(self, iq):
@@ -634,8 +634,9 @@ with some additional registration fields implemented.
if self.backend.register(iq['from'].bare, iq['register']):
# Successful registration
self.xmpp.event('registered_user', iq)
iq.reply().setPayload(iq['register'].xml)
iq.send()
reply = iq.reply()
reply.set_payload(iq['register'].xml)
reply.send()
else:
# Conflicting registration
self._sendError(iq, '409', 'cancel', 'conflict',
@@ -666,14 +667,16 @@ with some additional registration fields implemented.
# Add a blank field
reg.addField(field)
iq.reply().setPayload(reg.xml)
iq.send()
reply = iq.reply()
reply.set_payload(reg.xml)
reply.send()
def _sendError(self, iq, code, error_type, name, text=''):
iq.reply().setPayload(iq['register'].xml)
iq.error()
iq['error']['code'] = code
iq['error']['type'] = error_type
iq['error']['condition'] = name
iq['error']['text'] = text
iq.send()
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.

View File

@@ -6,33 +6,33 @@ Event Index
connected
- **Data:** ``{}``
- **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream`
- **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:`~sleekxmpp.xmlstream.XMLstream`
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
Signal that a connection can not be established after number of attempts.
changed_status
- **Data:** :py:class:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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 SleekXMPP will
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.
@@ -58,20 +58,20 @@ Event Index
- **Source:**
disco_info
- **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoInfo`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030`
- **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:`~sleekxmpp.plugins.xep_0030.stanza.DiscoItems`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030`
- **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:`~sleekxmpp.xmlstream.XMLstream`
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
Signal that the connection with the XMPP server has been lost.
@@ -81,33 +81,33 @@ Event Index
failed_auth
- **Data:** ``{}``
- **Source:** :py:class:`~sleekxmpp.ClientXMPP`, :py:class:`~sleekxmpp.plugins.xep_0078.xep_0078`
- **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:`~sleekxmpp.plugins.gmail_notify.gmail_notify`
- **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:`~sleekxmpp.Iq`
- **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem`
- **Data:** :py:class:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.roster.item.RosterItem`
Signal that an unavailable presence stanza has been received from a JID.
@@ -116,25 +116,25 @@ Event Index
- **Source:**
groupchat_direct_invite
- **Data:** :py:class:`~sleekxmpp.Message`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0249.direct`
- **Data:** :py:class:`~slixmpp.Message`
- **Source:** :py:class:`~slixmpp.plugins.xep_0249.direct`
groupchat_message
- **Data:** :py:class:`~sleekxmpp.Message`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
- **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:`~sleekxmpp.Message`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
- **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
@@ -146,21 +146,28 @@ Event Index
- **Source:**
message
- **Data:** :py:class:`~sleekxmpp.Message`
- **Source:** :py:class:`BaseXMPP <sleekxmpp.BaseXMPP>`
- **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:`~sleekxmpp.plugins.xep_0004.Form`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
- **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:`~sleekxmpp.plugins.xep_0004.Form`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
- **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.
@@ -181,95 +188,95 @@ Event Index
- **Source:**
presence_available
- **Data:** :py:class:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.plugins.xep_0004.Form`
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.Presence`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **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:`~sleekxmpp.stanza.Roster`
- **Source:** :py:class:`~sleekxmpp.ClientXMPP`
- **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:`~sleekxmpp.roster.multi.Roster`
- **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:`~sleekxmpp.xmlstream.XMLstream`
- **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
future implementation of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
will distinguish the two events.
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 <sleekxmpp.ClientXMPP>`,
:py:class:`ComponentXMPP <sleekxmpp.ComponentXMPP>`
:py:class:`XEP-0078 <sleekxmpp.plugins.xep_0078>`
- **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:`~sleekxmpp.xmlstream.XMLstream`
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
stream_error
- **Data:** :py:class:`~sleekxmpp.stanza.StreamError`
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
- **Data:** :py:class:`~slixmpp.stanza.StreamError`
- **Source:** :py:class:`~slixmpp.BaseXMPP`

View File

@@ -5,24 +5,16 @@ Create and Run a Server Component
=================================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
or join the chat room at `sleek@conference.jabber.org
<xmpp:sleek@conference.jabber.org?join>`_.
join the chat room at `slixmpp@muc.poez.io
<xmpp:slixmpp@muc.poez.io?join>`_.
If you have not yet installed SleekXMPP, do so now by either checking out a version
from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
or ``easy_install``.
If you have not yet installed Slixmpp, do so now by either checking out a version
with `Git <http://git.poez.io/slixmpp>`_.
.. code-block:: sh
pip install sleekxmpp # Or: easy_install sleekxmpp
Many XMPP applications eventually graduate to requiring to run as a server
component in order to meet scalability requirements. To demonstrate how to
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.
@@ -30,7 +22,7 @@ The first difference is that we will add an additional import statement:
.. code-block:: python
from sleekxmpp.componentxmpp import ComponentXMPP
from slixmpp.componentxmpp import ComponentXMPP
Likewise, we will change the bot's class definition to match:
@@ -48,7 +40,7 @@ a MUC component, the following could be used:
.. code-block:: python
muc = ComponentXMPP('muc.sleekxmpp.com', '******', 'sleekxmpp.com', 5555)
muc = ComponentXMPP('muc.slixmpp.com', '******', 'slixmpp.com', 5555)
.. note::
@@ -62,10 +54,10 @@ 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:`~sleekxmpp.basexmpp.BaseXMPP.send_message()` and
:meth:`~sleekxmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters
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:`~sleekxmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used.
:class:`~slixmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used.
Final Product

View File

@@ -1,25 +1,17 @@
.. _echobot:
===============================
SleekXMPP Quickstart - Echo Bot
Slixmpp Quickstart - Echo Bot
===============================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
or join the chat room at `sleek@conference.jabber.org
<xmpp:sleek@conference.jabber.org?join>`_.
If you have not yet installed SleekXMPP, do so now by either checking out a version
from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
or ``easy_install``.
.. code-block:: sh
pip install sleekxmpp # Or: easy_install sleekxmpp
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
@@ -44,11 +36,12 @@ To get started, here is a brief outline of the structure that the final project
# -*- coding: utf-8 -*-
import sys
import asyncio
import logging
import getpass
from optparse import OptionParser
import sleekxmpp
import slixmpp
'''Here we will create out echo bot class'''
@@ -59,24 +52,6 @@ To get started, here is a brief outline of the structure that the final project
'''Finally, we connect the bot and start listening for messages'''
Default Encoding
----------------
XMPP requires support for UTF-8 and so SleekXMPP must use UTF-8 as well. In
Python3 this is simple because Unicode is the default string type. For Python2.6+
the situation is not as easy because standard strings are simply byte arrays and
use ASCII. We can get Python to use UTF-8 as the default encoding by including:
.. code-block:: python
if sys.version_info < (3, 0):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
.. warning::
Until we are able to ensure that SleekXMPP will always use Unicode in Python2.6+, this
may cause issues embedding SleekXMPP into other applications which assume ASCII encoding.
Creating the EchoBot Class
--------------------------
@@ -85,30 +60,30 @@ clients. Since our echo bot will only be responding to a few people, and won't n
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.
SleekXMPP comes with a :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` class
which we can extend to add our message echoing feature. :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>`
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(sleekxmpp.ClientXMPP):
class EchoBot(slixmpp.ClientXMPP):
def __init__(self, jid, password):
super(EchoBot, self).__init__(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
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(EchoBot, self).__init__(jid, password)
super().__init__(jid, password)
self.add_event_handler('session_start', self.start)
@@ -132,8 +107,8 @@ Our event handler, like every event handler, accepts a single parameter which ty
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 <sleekxmpp.basexmpp.BaseXMPP.send_presence>`.
Calling :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest
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
@@ -141,17 +116,17 @@ stanza allowed in XMPP:
<presence />
The second requirement is fulfilled using :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>`, which
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 <sleekxmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return
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
<sleekxmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and
<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
<sleekxmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <sleekxmpp.exceptions.IQError>` exception can
<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.
@@ -178,7 +153,7 @@ whenever a messsage is received.
.. code-block:: python
def __init__(self, jid, password):
super(EchoBot, self).__init__(jid, password)
super().__init__(jid, password)
self.add_event_handler('session_start', self.start)
self.add_event_handler('message', self.message)
@@ -198,10 +173,10 @@ or ``chat``. (Other potential types are ``error``, ``headline``, and ``groupchat
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.
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 <sleekxmpp.basexmpp.BaseXMPP.send_message>`,
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:
@@ -229,20 +204,20 @@ Whichever method you choose to use, the results in action will look like this:
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. SleekXMPP thus leaves out the ``from`` attribute when replying
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 SleekXMPP itself, we do want our echo bot program to be able
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.
a password directly through the command line can be a security risk.
.. code-block:: python
@@ -303,21 +278,21 @@ the ``EchoBot.__init__`` method instead.
.. note::
If you are using the OpenFire server, you will need to include an additional
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 SleekXMPP support.
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
``dnspython`` installed, then the :meth:`sleekxmpp.clientxmpp.ClientXMPP` method
``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 ``dnspython``, then SleekXMPP will attempt to
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:`sleekxmpp.clientxmpp.ClientXMPP`.
to :meth:`slixmpp.clientxmpp.ClientXMPP`.
.. code-block:: python
@@ -330,35 +305,19 @@ to :meth:`sleekxmpp.clientxmpp.ClientXMPP`.
else:
print('Unable to connect')
.. note::
For Google Talk users withouth ``dnspython`` installed, the above code
should look like:
.. code-block:: python
if __name__ == '__main__':
# .. option parsing & echo bot configuration
if xmpp.connect(('talk.google.com', 5222)):
xmpp.process(block=True)
else:
print('Unable to connect')
To begin responding to messages, you'll see we called :meth:`sleekxmpp.basexmpp.BaseXMPP.process`
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:`sleekxmpp.plugins.base.base_plugin.post_init` method on all registered plugins. By
passing ``block=True`` to :meth:`sleekxmpp.basexmpp.BaseXMPP.process` we are running the
main processing loop in the main thread of execution. The :meth:`sleekxmpp.basexmpp.BaseXMPP.process`
call will not return until after SleekXMPP disconnects. If you need to run the client in the background
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::
.. note::
Before 1.0, controlling the blocking behaviour of :meth:`sleekxmpp.basexmpp.BaseXMPP.process` was
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 SleekXMPP used threads at all, instead of how
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.
@@ -370,7 +329,7 @@ The Final Product
-----------------
Here then is what the final result should look like after working through the guide above. The code
can also be found in the SleekXMPP `examples directory <http://github.com/fritzy/SleekXMPP/tree/master/examples>`_.
can also be found in the Slixmpp `examples directory <http://git.poez.io/slixmpp/tree/examples>`_.
.. compound::

View File

@@ -1,17 +1,17 @@
Send/Receive IQ Stanzas
=======================
Unlike :class:`~sleekxmpp.stanza.message.Message` and
:class:`~sleekxmpp.stanza.presence.Presence` stanzas which only use
text data for basic usage, :class:`~sleekxmpp.stanza.iq.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
SleekXMPP plugin to provide the necessary convenience methods to
Slixmpp plugin to provide the necessary convenience methods to
make working with them easier.
Basic Use
---------
XMPP's use of :class:`~sleekxmpp.stanza.iq.Iq` stanzas is built around
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
@@ -26,18 +26,18 @@ need to be able to send:
Creating Iq Stanzas
~~~~~~~~~~~~~~~~~~~
SleekXMPP provides built-in support for creating basic :class:`~sleekxmpp.stanza.iq.Iq`
Slixmpp provides built-in support for creating basic :class:`~slixmpp.stanza.iq.Iq`
stanzas this way. The relevant methods are:
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq`
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_get`
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_set`
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_result`
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_error`
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_query`
* :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:`~sleekxmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based
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:
@@ -50,14 +50,14 @@ namespace. For example, to produce the query above, you would use:
Sending Iq Stanzas
~~~~~~~~~~~~~~~~~~
Once an :class:`~sleekxmpp.stanza.iq.Iq` stanza is created, sending it
over the wire is done using its :meth:`~sleekxmpp.stanza.iq.Iq.send()`
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:`~sleekxmpp.stanza.iq.Iq.send()`
* ``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
@@ -74,7 +74,7 @@ These options are:
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``
@@ -85,16 +85,16 @@ These options are:
.. code-block:: python
cb_name = iq.send(callback=self.a_callback)
cb_name = iq.send(callback=self.a_callback)
# ... later if we need to cancel
self.remove_handler(cb_name)
Properly working with :class:`~sleekxmpp.stanza.iq.Iq` stanzas requires
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:`~sleekxmpp.stanza.iq.Iq.send()`: :exc:`~sleekxmpp.exceptions.IqError`
and :exc:`~sleekxmpp.exceptions.IqTimeout`. These exceptions only
: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
@@ -110,7 +110,7 @@ apply to the default, blocking calls.
pass
If you do not care to distinguish between errors and timeouts, then you
can combine both cases with a generic :exc:`~sleekxmpp.exceptions.XMPPError`
can combine both cases with a generic :exc:`~slixmpp.exceptions.XMPPError`
exception:
.. code-block:: python
@@ -124,24 +124,24 @@ exception:
Advanced Use
------------
Going beyond the basics provided by SleekXMPP requires building at least a
rudimentary SleekXMPP plugin to create a :term:`stanza object` for
interfacting with the :class:`~sleekxmpp.stanza.iq.Iq` payload.
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:`~sleekxmpp.stanza.iq.Iq` requests is
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:`~sleekxmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value
and has a :attr:`~slixmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value
of ``custom_xep``.
There are two types of incoming :class:`~sleekxmpp.stanza.iq.Iq` requests:
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:
@@ -167,7 +167,7 @@ filter by type as needed, as so:
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:`~sleekxmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher.
:class:`~slixmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher.
.. code-block:: python

View File

@@ -7,21 +7,13 @@ Mulit-User Chat (MUC) Bot
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
or join the chat room at `sleek@conference.jabber.org
<xmpp:sleek@conference.jabber.org?join>`_.
join the chat room at `slixmpp@muc.poez.io
<xmpp:slixmpp@muc.poez.io?join>`_.
If you have not yet installed SleekXMPP, do so now by either checking out a version
from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
or ``easy_install``.
If you have not yet installed Slixmpp, do so now by either checking out a version
from `Git <http://git.poez.io/slixmpp>`_.
.. code-block:: sh
pip install sleekxmpp # Or: easy_install sleekxmpp
Now that you've got the basic gist of using SleekXMPP by following the
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
@@ -36,7 +28,7 @@ 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 <sleekxmpp.clientxmpp.ClientXMPP>` and which accepts
: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.
@@ -44,12 +36,12 @@ bot will use inside the chat room. We also register an
.. code-block:: python
import sleekxmpp
import slixmpp
class MUCBot(sleekxmpp.ClientXMPP):
class MUCBot(slixmpp.ClientXMPP):
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
@@ -71,17 +63,17 @@ has been established:
def start(self, event):
self.get_roster()
self.send_presence()
self.plugin['xep_0045'].joinMUC(self.room,
self.nick,
wait=True)
self.plugin['xep_0045'].join_muc(self.room,
self.nick,
wait=True)
Note that as in :ref:`echobot`, we need to include send an initial presence and request
the roster. Next, we want to join the group chat, so we call the
``joinMUC`` method of the MUC plugin.
``join_muc`` method of the MUC plugin.
.. note::
The :attr:`plugin <sleekxmpp.basexmpp.BaseXMPP.plugin>` attribute is
The :attr:`plugin <slixmpp.basexmpp.BaseXMPP.plugin>` attribute is
dictionary that maps to instances of plugins that we have previously
registered, by their names.
@@ -115,7 +107,7 @@ event inside the bot's ``__init__`` function.
.. code-block:: python
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
@@ -159,7 +151,7 @@ event so it's a good idea to register an event handler for it.
.. code-block:: python
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

View File

@@ -5,19 +5,17 @@ Enable HTTP Proxy Support
=========================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
or join the chat room at `sleek@conference.jabber.org
<xmpp:sleek@conference.jabber.org?join>`_.
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.
SleekXMPP provides support for basic HTTP proxying with DIGEST
Slixmpp provides support for basic HTTP proxying with DIGEST
authentication.
Enabling proxy support is done in two steps. The first is to instruct SleekXMPP
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

View File

@@ -2,31 +2,29 @@ Sign in, Send a Message, and Disconnect
=======================================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
or join the chat room at `sleek@conference.jabber.org
<xmpp:sleek@conference.jabber.org?join>`_.
A common use case for SleekXMPP is to send one-off messages from
time to time. For example, one use case could be sending out a notice when
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 <sleekxmpp.clientxmpp.ClientXMPP>` and
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 sleekxmpp
import slixmpp
class SendMsgBot(sleekxmpp.ClientXMPP):
class SendMsgBot(slixmpp.ClientXMPP):
def __init__(self, jid, password, recipient, msg):
super(SendMsgBot, self).__init__(jid, password)
super().__init__(jid, password)
self.recipient = recipient
self.msg = msg
@@ -38,7 +36,7 @@ for the JID that will receive our message, and the string content of the message
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 <sleekxmpp.basexmpp.BaseXMPP.send_message>`.
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
@@ -48,12 +46,12 @@ the roster. Next, we want to send our message, and to do that we will use :meth:
self.send_message(mto=self.recipient, mbody=self.msg)
Finally, we need to disconnect the client using :meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>`.
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 <sleekxmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible
: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) <sleekxmpp.xmlstream.XMLStream.disconnect>`.
sent on the wire. To ensure that our message is processed, we use
:meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`.
.. code-block:: python
@@ -68,7 +66,7 @@ sent on the wire. To ensure that our message is processed, we use
.. 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) <sleekxmpp.xmlstream.XMLStream.disconnect>`
can process them, then :meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`
will block and not disconnect.
Final Product

View File

@@ -9,21 +9,20 @@ Glossary
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 :term:`Matcher` object, and which provides
additional semantics. For example, the ``Waiter`` handler wrapper
blocks thread execution until a matching stanza is received.
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
``XMLStream.event``. An event handler may be marked as
threaded, allowing it to execute outside of the main processing
loop.
:meth:`.XMLStream.event`.
stanza object
Informally may refer both to classes which extend ``ElementBase``
or ``StanzaBase``, and to objects of such classes.
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 ``dict``
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

View File

@@ -18,7 +18,7 @@ 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 SleekXMPP.) SleekXMPP provides methods to configure each
not yet implemented by Slixmpp.) Slixmpp provides methods to configure each
of these node attributes.
Configuring Service Discovery
@@ -61,7 +61,7 @@ operation using these stanzas without doing any complex operations such as
checking an ACL, etc.
You may find it necessary at some point to revert a particular node or JID to
using the default, static handlers. To do so, use the method ``make_static()``.
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
@@ -119,7 +119,7 @@ the same order as expected using positional arguments.
xmpp['xep_0030'].add_identity(category='client',
itype='bot',
name='Sleek',
name='Slixmpp',
node='foo',
jid=xmpp.boundjid.full,
lang='no')
@@ -159,10 +159,10 @@ item itself, and the JID and node that will own the item.
.. note::
In this case, the owning JID and node are provided with the
parameters ``ijid`` and ``node``.
parameters ``ijid`` and ``node``.
Peforming Disco Queries
-----------------------
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()``
@@ -172,11 +172,10 @@ the `XEP-0059 <http://xmpp.org/extensions/xep-0059.html>`_ plug-in.
.. code-block:: python
info = self['xep_0030'].get_info(jid='foo@example.com',
node='bar',
ifrom='baz@mycomponent.example.com',
block=True,
timeout=30)
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',
@@ -197,5 +196,5 @@ a full Iq stanza.
info = self['xep_0030'].get_info(node='foo', local=True)
items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com',
node='bar',
node='bar',
local=True)

View File

@@ -1,49 +1,36 @@
SleekXMPP
Slixmpp
#########
.. sidebar:: Get the Code
.. code-block:: sh
The latest source code for Slixmpp may be found on the `Git repo
<http://git.poez.io/slixmpp>`_. ::
pip install sleekxmpp
git clone git://git.poez.io/slixmpp
The latest source code for SleekXMPP may be found on `Github
<http://github.com/fritzy/SleekXMPP>`_. Releases can be found in the
``master`` branch, while the latest development version is in the
``develop`` branch.
**Latest Stable Release**
- `1.0 <http://github.com/fritzy/SleekXMPP/zipball/1.0>`_
**Develop Releases**
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
A mailing list and XMPP chat room are available for discussing and getting
help with SleekXMPP.
**Mailing List**
`SleekXMPP Discussion on Google Groups <http://groups.google.com/group/sleekxmpp-discussion>`_
An XMPP chat room is available for discussing and getting help with slixmpp.
**Chat**
`sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_
`slixmpp@muc.poez.io <xmpp:slixmpp@muc.poez.io?join>`_
**Reporting bugs**
You can report bugs at http://dev.louiz.org/projects/slixmpp/issues.
SleekXMPP is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+,
and is featured in examples in
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived
here from reading the Definitive Guide, please see the notes on updating
the examples to the latest version of SleekXMPP.
.. 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`.
SleekXMPP's design goals and philosphy are:
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 SleekXMPP should be as simple as possible, without
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 SleekXMPP in the ``thirdparty`` directory.
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.
@@ -55,19 +42,20 @@ SleekXMPP's design goals and philosphy are:
XEPs.
**Rewarding to work with**
As much as possible, SleekXMPP should allow things to "just work" using
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 SleekXMPP Bot:
Here's your first Slixmpp Bot:
--------------------------------
.. code-block:: python
import asyncio
import logging
from sleekxmpp import ClientXMPP
from sleekxmpp.exceptions import IqError, IqTimeout
from slixmpp import ClientXMPP
class EchoBot(ClientXMPP):
@@ -85,27 +73,13 @@ Here's your first SleekXMPP Bot:
# 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()
# 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'):
@@ -113,7 +87,7 @@ Here's your first SleekXMPP Bot:
if __name__ == '__main__':
# Ideally use optparse or argparse to get JID,
# Ideally use optparse or argparse to get JID,
# password, and log level.
logging.basicConfig(level=logging.DEBUG,
@@ -121,15 +95,24 @@ Here's your first SleekXMPP Bot:
xmpp = EchoBot('somejid@example.com', 'use_getpass')
xmpp.connect()
xmpp.process(block=True)
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
@@ -144,8 +127,7 @@ Tutorials, FAQs, and How To Guides
----------------------------------
.. toctree::
:maxdepth: 1
faq
xeps
xmpp_tdg
howto/stanzas
@@ -156,12 +138,12 @@ Tutorials, FAQs, and How To Guides
Plugin Guides
~~~~~~~~~~~~~
.. toctree::
.. toctree::
:maxdepth: 1
guide_xep_0030
SleekXMPP Architecture and Design
Slixmpp Architecture and Design
---------------------------------
.. toctree::
:maxdepth: 3
@@ -173,7 +155,7 @@ API Reference
-------------
.. toctree::
:maxdepth: 2
event_index
api/clientxmpp
api/componentxmpp
@@ -184,9 +166,7 @@ API Reference
api/xmlstream/handler
api/xmlstream/matcher
api/xmlstream/xmlstream
api/xmlstream/scheduler
api/xmlstream/tostring
api/xmlstream/filesocket
Core Stanzas
~~~~~~~~~~~~
@@ -197,8 +177,6 @@ Core Stanzas
api/stanza/message
api/stanza/presence
api/stanza/iq
api/stanza/error
api/stanza/stream_error
Plugins
~~~~~~~
@@ -220,8 +198,14 @@ Additional Info
* :ref:`modindex`
* :ref:`search`
Credits
-------
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>`_,

View File

@@ -1,4 +1,4 @@
.. _license:
.. _license:
License (MIT)
=============

View File

@@ -95,9 +95,9 @@ if "%1" == "qthelp" (
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SleekXMPP.qhcp
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Slixmpp.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SleekXMPP.ghc
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Slixmpp.ghc
goto end
)

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()

View File

@@ -4,9 +4,9 @@ Supported XEPS
======= ============================= ================
XEP Description Notes
======= ============================= ================
`0004`_ Data forms
`0009`_ Jabber RPC
`0012`_ Last Activity
`0004`_ Data forms
`0009`_ Jabber RPC
`0012`_ Last Activity
`0030`_ Service Discovery
`0033`_ Extended Stanza Addressing
`0045`_ Multi-User Chat (MUC) Client-side only

View File

@@ -1,20 +1,20 @@
Following *XMPP: The Definitive Guide*
======================================
SleekXMPP was featured in the first edition of the O'Reilly book
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
SleekXMPP release, is available at http://github.com/legastero/xmpp-tdg.
Slixmpp release, is available at http://github.com/legastero/xmpp-tdg.
However, since publication, SleekXMPP has advanced from version 0.2.1 to version
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 SleekXMPP.
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.
@@ -36,7 +36,7 @@ Updated Code
.. code-block:: python
def handleIncomingMessage(self, message):
self.xmpp.sendMessage(message["from"], message["body"])
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>`_
@@ -47,7 +47,7 @@ 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 SleekXMPP 1.0,
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,
@@ -72,21 +72,21 @@ Updated Code
.. code-block:: python
def handleIncomingXMPPEvent(self, event):
msgLocations = {sleekxmpp.stanza.presence.Presence: "status",
sleekxmpp.stanza.message.Message: "body"}
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.sendMessage(subscriberJID, body, mhtml=htmlBody)
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>`_
@@ -102,7 +102,7 @@ Example 14-3. (Page 217)
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; SleekXMPP converts
with the string ``"1"`` is no longer required; Slixmpp converts
boolean data form fields to the values ``True`` and ``False``
automatically.
@@ -145,7 +145,7 @@ Example 14-4. (Page 220)
Like several previous examples, a needed change is to replace
``subscription["from"]`` with ``subscription["from"].jid`` because the
``BaseXMPP`` method ``makePresence`` requires the JID to be a string.
``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
@@ -154,7 +154,7 @@ 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.sendMessage``.
``self.xmpp.send_message``.
Updated Code
~~~~~~~~~~~~
@@ -162,19 +162,19 @@ Updated Code
.. code-block:: python
def handleXMPPPresenceProbe(self, event) :
self.xmpp.sendPresence(pto = event["from"])
self.xmpp.send_presence(pto = event["from"])
def handleXMPPPresenceSubscription(self, subscription) :
if subscription["type"] == "subscribe" :
userJID = subscription["from"].jid
self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribed")
self.xmpp.sendPresence(pto = userJID)
self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribe")
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.sendMessage(subscriberJID, body, mfrom=self.xmpp.jid)
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>`_
@@ -192,7 +192,7 @@ 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 SleekXMPP plugin,
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>`_ |
@@ -203,13 +203,13 @@ Example 14-7. (Page 225)
**Extended CheshiR IM server component implementation.**
.. note::
Since the CheshiR examples build on each other, see previous
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
SleekXMPP. Most differences are the result of CheshiR's backend functions
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
@@ -239,11 +239,11 @@ Updated Code
userJID = subscription["from"].jid
user = self.backend.getUserFromJID(userJID)
contactJID = subscription["to"]
self.xmpp.sendPresenceSubscription(
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>`_
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_

View File

@@ -1,53 +1,35 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
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 SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import os
import sys
# This can be used when you are in a test environment and need to make paths right
sys.path=['/Users/jocke/Dropbox/06_dev/SleekXMPP']+sys.path
import logging
import unittest
import distutils.core
import datetime
from glob import glob
from os.path import splitext, basename, join as pjoin
from optparse import OptionParser
from os.path import basename, join as pjoin
from argparse import ArgumentParser
from urllib import urlopen
from getpass import getpass
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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
from slixmpp.plugins.xep_0323.device import Device
from sleekxmpp.plugins.xep_0323.device import Device
#from slixmpp.exceptions import IqError, IqTimeout
#from sleekxmpp.exceptions import IqError, IqTimeout
class IoT_TestDevice(sleekxmpp.ClientXMPP):
class IoT_TestDevice(slixmpp.ClientXMPP):
"""
A simple IoT device that can act as server or client
"""
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__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
@@ -125,47 +107,44 @@ if __name__ == '__main__':
#
# "client" an IoT device or other party that would like to get data from another device
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",
action="store", type="string", 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")
# IoT test
optp.add_option("-c", "--sensorjid", dest="sensorjid",
help="Another device to call for data on", default=None)
optp.add_option("-n", "--nodeid", dest="nodeid",
help="I am a device get ready to be called", default=None)
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)
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: ")
xmpp = IoT_TestDevice(opts.jid,opts.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,
@@ -173,31 +152,31 @@ if __name__ == '__main__':
xmpp.register_plugin('xep_0323')
xmpp.register_plugin('xep_0325')
if opts.nodeid:
if args.nodeid:
# xmpp['xep_0030'].add_feature(feature='urn:xmpp:sn',
# node=opts.nodeid,
# node=args.nodeid,
# jid=xmpp.boundjid.full)
myDevice = TheDevice(opts.nodeid);
myDevice = TheDevice(args.nodeid);
# myDevice._add_field(name="Relay", typename="numeric", unit="Bool");
myDevice._add_field(name="Temperature", typename="numeric", unit="C");
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"});
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
xmpp['xep_0323'].register_node(nodeId=opts.nodeid, device=myDevice, commTimeout=10);
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 opts.sensorjid:
if args.sensorjid:
logging.debug("will try to call another device for data")
xmpp.beClientOrServer(server=False,clientJID=opts.sensorjid)
xmpp.beClientOrServer(server=False,clientJID=args.sensorjid)
xmpp.connect()
xmpp.process(block=True)
logging.debug("ready ending")
else:
print "noopp didn't happen"
print("noopp didn't happen")

View File

@@ -1,41 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
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
@@ -79,7 +68,7 @@ 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',
@@ -143,62 +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
xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency':15})
# 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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,41 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
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
@@ -105,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'])
@@ -142,69 +131,49 @@ class CommandUserBot(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("-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.greeting = 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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,41 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
class AdminCommands(sleekxmpp.ClientXMPP):
class AdminCommands(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that uses admin commands to
A simple Slixmpp bot that uses admin commands to
add a new user to a server.
"""
def __init__(self, jid, password, command):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
self.command = command
@@ -81,13 +70,13 @@ class AdminCommands(sleekxmpp.ClientXMPP):
for var, field in form['fields'].items():
if var != 'FORM_TYPE':
if field['type'] == 'boolean':
answers[var] = raw_input('%s (y/n): ' % field['label'])
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] = raw_input('%s: ' % field['label'])
answers[var] = input('%s: ' % field['label'])
else:
answers['FORM_TYPE'] = field['value']
form['type'] = 'submit'
@@ -116,63 +105,43 @@ class AdminCommands(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("-c", "--command", dest="command",
help="admin command to use")
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")
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.command is None:
opts.command = raw_input("Admin command: ")
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(opts.jid, opts.password, opts.command)
xmpp = AdminCommands(args.jid, args.password, args.command)
xmpp.register_plugin('xep_0133') # Service Administration
# 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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

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

@@ -1,48 +1,37 @@
#!/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 getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
import slixmpp
from sleekxmpp import ClientXMPP, Iq
from sleekxmpp.exceptions import IqError, IqTimeout, XMPPError
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath
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
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class ActionBot(sleekxmpp.ClientXMPP):
class ActionBot(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that receives a custom stanza
A simple Slixmpp bot that receives a custom stanza
from another client.
"""
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
@@ -57,8 +46,7 @@ class ActionBot(sleekxmpp.ClientXMPP):
self._handle_action))
self.add_event_handler('custom_action',
self._handle_action_event,
threaded=True)
self._handle_action_event)
register_stanza_plugin(Iq, Action)
@@ -88,10 +76,6 @@ class ActionBot(sleekxmpp.ClientXMPP):
def _handle_action_event(self, iq):
"""
Respond to the custom action event.
Since one of the actions is to disconnect, this
event handler needs to be run in threaded mode, by
using `threaded=True` in the `add_event_handler` call.
"""
method = iq['action']['method']
param = iq['action']['param']
@@ -112,62 +96,42 @@ class ActionBot(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 = ActionBot(opts.jid, opts.password)
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})
# 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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,46 +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 getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp import Iq
from sleekxmpp.exceptions import XMPPError
from sleekxmpp.xmlstream import register_stanza_plugin
import slixmpp
from slixmpp import Iq
from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream import register_stanza_plugin
from stanza import Action
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class ActionUserBot(sleekxmpp.ClientXMPP):
class ActionUserBot(slixmpp.ClientXMPP):
"""
A simple SleekXMPP bot that sends a custom action stanza
A simple Slixmpp bot that sends a custom action stanza
to another client.
"""
def __init__(self, jid, password, other):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
self.action_provider = other
@@ -49,7 +38,7 @@ class ActionUserBot(sleekxmpp.ClientXMPP):
# 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, threaded=True)
self.add_event_handler("session_start", self.start)
self.add_event_handler("message", self.message)
register_stanza_plugin(Iq, Action)
@@ -93,10 +82,8 @@ class ActionUserBot(sleekxmpp.ClientXMPP):
iq2['type'] = 'set'
iq2['action']['method'] = 'bye'
iq2.send(block=False)
# The wait=True delays the disconnect until the queue
# of stanzas to be sent becomes empty.
self.disconnect(wait=True)
self.disconnect()
except XMPPError:
print('There was an error sending the custom action.')
@@ -111,65 +98,45 @@ class ActionUserBot(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("-o", "--other", dest="other",
help="JID providing custom stanza")
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")
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 custom stanza: ")
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(opts.jid, opts.password, opts.other)
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
# 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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,30 +1,30 @@
from sleekxmpp.xmlstream import ElementBase
from slixmpp.xmlstream import ElementBase
class Action(ElementBase):
"""
A stanza class for XML content of the form:
<action xmlns="sleekxmpp:custom:actions">
<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 = 'sleekxmpp:custom:actions'
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.
@@ -49,8 +49,8 @@ class Action(ElementBase):
#: the sub_interfaces set. For example, here all interfaces
#: are marked as sub_interfaces, and so the XML produced will
#: look like:
#:
#: <action xmlns="sleekxmpp:custom:actions">
#:
#: <action xmlns="slixmpp:custom:actions">
#: <method>foo</method>
#: </action>
sub_interfaces = interfaces

View File

@@ -1,35 +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 logging
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.exceptions import IqError, IqTimeout
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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class Disco(sleekxmpp.ClientXMPP):
class Disco(slixmpp.ClientXMPP):
"""
A demonstration for using basic service discovery.
@@ -42,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')
@@ -63,8 +52,9 @@ class Disco(sleekxmpp.ClientXMPP):
# 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, threaded=True)
self.add_event_handler("session_start", self.start)
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
@@ -86,22 +76,16 @@ class Disco(sleekxmpp.ClientXMPP):
try:
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)
elif self.get in self.items_types:
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 = self['xep_0030'].get_items(jid=self.target_jid,
node=self.target_node,
block=True)
else:
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:
@@ -136,69 +120,42 @@ class Disco(sleekxmpp.ClientXMPP):
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 dnspython 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(block=True)
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process(forever=False)

View File

@@ -1,33 +1,21 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2012 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 getpass
import threading
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.exceptions import XMPPError
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
from slixmpp.exceptions import XMPPError
from slixmpp import asyncio
FILE_TYPES = {
@@ -37,23 +25,29 @@ FILE_TYPES = {
}
class AvatarDownloader(sleekxmpp.ClientXMPP):
class AvatarDownloader(slixmpp.ClientXMPP):
"""
A basic script for downloading the avatars for a user's contacts.
"""
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
self.add_event_handler("session_start", self.start, threaded=True)
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 = threading.Event()
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.
@@ -68,16 +62,20 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
data.
"""
self.send_presence()
self.get_roster()
self.get_roster(callback=self.roster_received_cb)
print('Waiting for presence updates...\n')
self.presences_received.wait(15)
self.disconnect(wait=True)
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 = self['xep_0054'].get_vcard(pres['from'], cached=True)
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
@@ -88,16 +86,18 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
pres['from'].bare,
pres['vcard_temp_update']['photo'],
filetype)
with open(filename, 'w+') as img:
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 = self['xep_0084'].retrieve_avatar(msg['from'], info['id'])
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
@@ -106,7 +106,7 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
filetype = FILE_TYPES.get(metadata['type'], 'png')
filename = 'avatar_%s_%s.%s' % (msg['from'].bare, info['id'], filetype)
with open(filename, 'w+') as img:
with open(filename, 'wb+') as img:
img.write(avatar['value'])
else:
# We could retrieve the avatar via HTTP, etc here instead.
@@ -117,6 +117,7 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
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:
@@ -125,60 +126,40 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
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 = 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.
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")
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: ")
xmpp = AvatarDownloader(opts.jid, opts.password)
xmpp = AvatarDownloader(args.jid, args.password)
xmpp.register_plugin('xep_0054')
xmpp.register_plugin('xep_0153')
xmpp.register_plugin('xep_0084')
# 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 dnspython 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(block=True)
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,41 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
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
@@ -83,75 +72,42 @@ class EchoBot(sleekxmpp.ClientXMPP):
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 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"
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,37 +1,26 @@
#!/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 getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.componentxmpp import ComponentXMPP
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
from slixmpp.componentxmpp import ComponentXMPP
class EchoComponent(ComponentXMPP):
"""
A simple SleekXMPP component that echoes messages.
A simple Slixmpp component that echoes messages.
"""
def __init__(self, jid, secret, server, port):
@@ -67,56 +56,50 @@ class EchoComponent(ComponentXMPP):
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser(description=EchoComponent.__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")
optp.add_option("-s", "--server", dest="server",
help="server to connect to")
optp.add_option("-P", "--port", dest="port",
help="port to connect to")
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")
opts, args = optp.parse_args()
args = parser.parse_args()
if opts.jid is None:
opts.jid = raw_input("Component JID: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if opts.server is None:
opts.server = raw_input("Server: ")
if opts.port is None:
opts.port = int(raw_input("Port: "))
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=opts.loglevel,
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(opts.jid, opts.password, opts.server, opts.port)
xmpp.registerPlugin('xep_0030') # Service Discovery
xmpp.registerPlugin('xep_0004') # Data Forms
xmpp.registerPlugin('xep_0060') # PubSub
xmpp.registerPlugin('xep_0199') # XMPP Ping
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.
if xmpp.connect():
xmpp.process(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,46 +1,34 @@
#!/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 getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
import slixmpp
import ssl
from sleekxmpp.xmlstream import cert
from slixmpp.xmlstream import cert
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class GTalkBot(sleekxmpp.ClientXMPP):
class GTalkBot(slixmpp.ClientXMPP):
"""
A demonstration of using SleekXMPP with accounts from a Google Apps
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):
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
@@ -104,62 +92,42 @@ class GTalkBot(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 GTalkBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = GTalkBot(opts.jid, opts.password)
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
# 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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
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

@@ -1,45 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
class IBBReceiver(sleekxmpp.ClientXMPP):
class IBBReceiver(slixmpp.ClientXMPP):
"""
A basic example of creating and using an in-band bytestream.
"""
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
def __init__(self, jid, password, filename):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.register_plugin('xep_0030') # Service Discovery
self.register_plugin('xep_0047', {
'auto_accept': True
}) # In-band Bytestreams
self.file = open(filename, 'wb')
# The session_start event will be triggered when
# the bot establishes its connection with the server
@@ -48,8 +34,9 @@ class IBBReceiver(sleekxmpp.ClientXMPP):
# our roster.
self.add_event_handler("session_start", self.start)
self.add_event_handler("ibb_stream_start", self.stream_opened, threaded=True)
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):
"""
@@ -67,81 +54,59 @@ class IBBReceiver(sleekxmpp.ClientXMPP):
self.send_presence()
self.get_roster()
def accept_stream(self, iq):
"""
Check that it is ok to accept a stream request.
Controlling stream acceptance can be done via either:
- setting 'auto_accept' to False in the plugin
configuration. The default is True.
- setting 'accept_stream' to a function which accepts
an Iq stanza as its argument, like this one.
The accept_stream function will be used if it exists, and the
auto_accept value will be used otherwise.
"""
return True
def stream_opened(self, stream):
print('Stream opened: %s from %s' % (stream.sid, stream.peer_jid))
# You could run a loop reading from the stream using stream.recv(),
# or use the ibb_stream_data event.
def stream_data(self, stream):
self.file.write(stream.read())
def stream_data(self, event):
print(event['data'])
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.
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")
parser.add_argument("-o", "--out", dest="filename",
help="file to save to")
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: ")
if args.filename is None:
args.filename = input("File path: ")
xmpp = IBBReceiver(opts.jid, opts.password)
# 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"
# 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.
if xmpp.connect():
# If you do not have the dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process(forever=False)

View File

@@ -1,43 +1,36 @@
#!/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 asyncio
import logging
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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
from slixmpp.exceptions import IqError, IqTimeout
class IBBSender(sleekxmpp.ClientXMPP):
class IBBSender(slixmpp.ClientXMPP):
"""
A basic example of creating and using an in-band bytestream.
"""
def __init__(self, jid, password, receiver, filename):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
def __init__(self, jid, password, receiver, filename, use_messages=False):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.receiver = receiver
self.filename = filename
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
@@ -46,6 +39,7 @@ class IBBSender(sleekxmpp.ClientXMPP):
# our roster.
self.add_event_handler("session_start", self.start)
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
@@ -62,84 +56,70 @@ class IBBSender(sleekxmpp.ClientXMPP):
self.send_presence()
self.get_roster()
# For the purpose of demonstration, we'll set a very small block
# size. The default block size is 4096. We'll also use a window
# allowing sending multiple blocks at a time; in this case, three
# block transfers may be in progress at any time.
stream = self['xep_0047'].open_stream(self.receiver)
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)
with open(self.filename) as f:
data = f.read()
stream.sendall(data)
# 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.
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", "--receiver", dest="receiver",
help="JID to use")
optp.add_option("-f", "--file", dest="filename",
help="JID to use")
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")
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.receiver is None:
opts.receiver = raw_input("Receiver: ")
if opts.filename is None:
opts.filename = raw_input("File path: ")
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 EchoBot and register plugins. Note that while plugins may
# 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(opts.jid, opts.password, opts.receiver, opts.filename)
xmpp = IBBSender(args.jid, args.password, args.receiver, args.filename, args.use_messages)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0047') # In-band Bytestreams
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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process(forever=False)

View File

@@ -1,68 +1,55 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import logging
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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
# 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("--oldjid", dest="old_jid",
help="JID of the old account")
optp.add_option("--oldpassword", dest="old_password",
help="password of the old account")
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")
optp.add_option("--newjid", dest="new_jid",
help="JID of the old account")
optp.add_option("--newpassword", dest="new_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")
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.old_jid is None:
opts.old_jid = raw_input("Old JID: ")
if opts.old_password is None:
opts.old_password = getpass.getpass("Old Password: ")
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 opts.new_jid is None:
opts.new_jid = raw_input("New JID: ")
if opts.new_password is None:
opts.new_password = getpass.getpass("New 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 = sleekxmpp.ClientXMPP(opts.old_jid, opts.old_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
@@ -98,7 +85,7 @@ if not roster:
print('No roster to migrate')
sys.exit()
new_xmpp = sleekxmpp.ClientXMPP(opts.new_jid, opts.new_password)
new_xmpp = slixmpp.ClientXMPP(args.new_jid, args.new_password)
def on_session2(event):
new_xmpp.get_roster()
new_xmpp.send_presence()
@@ -113,8 +100,8 @@ def on_session2(event):
new_xmpp.update_roster(jid,
name = item['name'],
groups = item['groups'])
new_xmpp.disconnect()
new_xmpp.disconnect()
new_xmpp.add_event_handler('session_start', on_session2)
if new_xmpp.connect():
new_xmpp.process(block=True)
new_xmpp.connect()
new_xmpp.process()

View File

@@ -1,42 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
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
@@ -78,11 +67,11 @@ class MUCBot(sleekxmpp.ClientXMPP):
"""
self.get_roster()
self.send_presence()
self.plugin['xep_0045'].joinMUC(self.room,
self.nick,
# If a room password is needed, use:
# password=the_room_password,
wait=True)
self.plugin['xep_0045'].join_muc(self.room,
self.nick,
# If a room password is needed, use:
# password=the_room_password,
wait=True)
def muc_message(self, msg):
"""
@@ -132,62 +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 opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if opts.room is None:
opts.room = raw_input("MUC room: ")
if opts.nick is None:
opts.nick = raw_input("MUC nickname: ")
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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,41 +1,32 @@
#!/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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
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.boundjid.bare
self.pingjid = pingjid
@@ -45,8 +36,9 @@ class PingTest(sleekxmpp.ClientXMPP):
# 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, threaded=True)
self.add_event_handler("session_start", self.start)
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
@@ -64,8 +56,8 @@ class PingTest(sleekxmpp.ClientXMPP):
self.get_roster()
try:
rtt = self['xep_0199'].ping(self.pingjid,
timeout=10)
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",
@@ -79,65 +71,44 @@ class PingTest(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)
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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,41 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
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
@@ -82,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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,31 +1,21 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import logging
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.xmlstream import ET, tostring
import asyncio
import slixmpp
from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream import ET, tostring
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class PubsubClient(sleekxmpp.ClientXMPP):
class PubsubClient(slixmpp.ClientXMPP):
def __init__(self, jid, password, server,
node=None, action='list', data=''):
super(PubsubClient, self).__init__(jid, password)
node=None, action='nodes', data=''):
super().__init__(jid, password)
self.register_plugin('xep_0030')
self.register_plugin('xep_0059')
@@ -40,162 +30,137 @@ class PubsubClient(sleekxmpp.ClientXMPP):
self.data = data
self.pubsub_server = server
self.add_event_handler('session_start', self.start, threaded=True)
self.add_event_handler('session_start', self.start)
@asyncio.coroutine
def start(self, event):
self.get_roster()
self.send_presence()
try:
getattr(self, self.action)()
yield from getattr(self, self.action)()
except:
logging.error('Could not execute: %s' % self.action)
logging.error('Could not execute: %s', self.action)
self.disconnect()
def nodes(self):
try:
result = self['xep_0060'].get_nodes(self.pubsub_server, self.node)
result = yield from self['xep_0060'].get_nodes(self.pubsub_server, self.node)
for item in result['disco_items']['items']:
print(' - %s' % str(item))
except:
logging.error('Could not retrieve node list.')
logging.info(' - %s', str(item))
except XMPPError as error:
logging.error('Could not retrieve node list: %s', error.format())
def create(self):
try:
self['xep_0060'].create_node(self.pubsub_server, self.node)
except:
logging.error('Could not create node: %s' % self.node)
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:
self['xep_0060'].delete_node(self.pubsub_server, self.node)
print('Deleted node: %s' % self.node)
except:
logging.error('Could not delete node: %s' % self.node)
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 = self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload)
id = result['pubsub']['publish']['item']['id']
print('Published at item id: %s' % id)
except:
logging.error('Could not publish to: %s' % self.node)
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 = self['xep_0060'].get_item(self.pubsub_server, self.node, self.data)
result = yield from self['xep_0060'].get_item(self.pubsub_server, self.node, self.data)
for item in result['pubsub']['items']['substanzas']:
print('Retrieved item %s: %s' % (item['id'], tostring(item['payload'])))
except:
logging.error('Could not retrieve item %s from node %s' % (self.data, self.node))
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:
result = self['xep_0060'].retract(self.pubsub_server, self.node, self.data)
print('Retracted item %s from node %s' % (self.data, self.node))
except:
logging.error('Could not retract item %s from node %s' % (self.data, self.node))
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:
result = self['xep_0060'].purge(self.pubsub_server, self.node)
print('Purged all items from node %s' % self.node)
except:
logging.error('Could not purge items from node %s' % self.node)
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:
result = self['xep_0060'].subscribe(self.pubsub_server, self.node)
print('Subscribed %s to node %s' % (self.boundjid.bare, self.node))
except:
logging.error('Could not subscribe %s to node %s' % (self.boundjid.bare, self.node))
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:
result = self['xep_0060'].unsubscribe(self.pubsub_server, self.node)
print('Unsubscribed %s from node %s' % (self.boundjid.bare, self.node))
except:
logging.error('Could not unsubscribe %s from node %s' % (self.boundjid.bare, self.node))
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.
optp = OptionParser()
optp.version = '%%prog 0.1'
optp.usage = "Usage: %%prog [options] <jid> " + \
parser = ArgumentParser()
parser.version = '%%prog 0.1'
parser.usage = "Usage: %%prog [options] <jid> " + \
'nodes|create|delete|purge|subscribe|unsubscribe|publish|retract|get' + \
' [<node> <data>]'
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.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")
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("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=opts.loglevel,
logging.basicConfig(level=args.loglevel,
format='%(levelname)-8s %(message)s')
if len(args) < 2:
optp.print_help()
exit()
if opts.jid is None:
opts.jid = raw_input("Username: ")
if opts.password is None:
opts.password = getpass.getpass("Password: ")
if len(args) == 2:
args = (args[0], args[1], '', '', '')
elif len(args) == 3:
args = (args[0], args[1], args[2], '', '')
elif len(args) == 4:
args = (args[0], args[1], args[2], args[3], '')
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
# Setup the Pubsub client
xmpp = PubsubClient(opts.jid, opts.password,
server=args[0],
node=args[2],
action=args[1],
data=args[3])
# 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 = 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.
if xmpp.connect():
# If you do not have the dnspython 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(block=True)
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process(forever=False)

View File

@@ -1,32 +1,20 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import logging
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.xmlstream import ET, tostring
from sleekxmpp.xmlstream.matcher import StanzaPath
from sleekxmpp.xmlstream.handler import Callback
import slixmpp
from slixmpp.xmlstream import ET, tostring
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.xmlstream.handler import Callback
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class PubsubEvents(sleekxmpp.ClientXMPP):
class PubsubEvents(slixmpp.ClientXMPP):
def __init__(self, jid, password):
super(PubsubEvents, self).__init__(jid, password)
super().__init__(jid, password)
self.register_plugin('xep_0030')
self.register_plugin('xep_0059')
@@ -96,59 +84,39 @@ class PubsubEvents(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: ")
logging.info("Run this in conjunction with the pubsub_client.py " + \
"example to watch events happen as you give commands.")
# Setup the PubsubEvents listener
xmpp = PubsubEvents(opts.jid, opts.password)
# 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 = PubsubEvents(args.jid, args.password)
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,34 +1,23 @@
#!/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 getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.exceptions import IqError, IqTimeout
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
from slixmpp.exceptions import IqError, IqTimeout
class RegisterBot(sleekxmpp.ClientXMPP):
class RegisterBot(slixmpp.ClientXMPP):
"""
A basic bot that will attempt to register an account
@@ -40,23 +29,23 @@ class RegisterBot(sleekxmpp.ClientXMPP):
"""
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 initialize
# our roster.
self.add_event_handler("session_start", self.start, threaded=True)
self.add_event_handler("session_start", self.start)
# The register event provides an Iq result stanza with
# a registration form from the server. This may include
# the basic registration fields, a data form, an
# out-of-band URL, or any combination. For more advanced
# cases, you will need to examine the fields provided
# and respond accordingly. SleekXMPP provides plugins
# and respond accordingly. Slixmpp provides plugins
# for data forms and OOB links that will make that easier.
self.add_event_handler("register", self.register, threaded=True)
self.add_event_handler("register", self.register)
def start(self, event):
"""
@@ -101,7 +90,7 @@ class RegisterBot(sleekxmpp.ClientXMPP):
resp['register']['password'] = self.password
try:
resp.send(now=True)
yield from resp.send()
logging.info("Account created for %s!" % self.boundjid)
except IqError as e:
logging.error("Could not register account: %s" %
@@ -114,40 +103,37 @@ class RegisterBot(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 RegisterBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = RegisterBot(opts.jid, opts.password)
xmpp = RegisterBot(args.jid, args.password)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data forms
xmpp.register_plugin('xep_0066') # Out-of-band Data
@@ -157,23 +143,6 @@ if __name__ == '__main__':
# though they allow it. If this applies to your server, use:
xmpp['xep_0077'].force_registration = True
# 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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,36 +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) 2011 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 getpass
import threading
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.exceptions import IqError, IqTimeout
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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class RosterBrowser(sleekxmpp.ClientXMPP):
class RosterBrowser(slixmpp.ClientXMPP):
"""
A basic script for dumping a client's roster to
@@ -38,20 +26,19 @@ class RosterBrowser(sleekxmpp.ClientXMPP):
"""
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 initialize
# our roster. We need threaded=True so that the
# session_start handler doesn't block event processing
# while we wait for presence stanzas to arrive.
self.add_event_handler("session_start", self.start, threaded=True)
# our roster.
self.add_event_handler("session_start", self.start)
self.add_event_handler("changed_status", self.wait_for_presences)
self.received = set()
self.presences_received = threading.Event()
self.presences_received = asyncio.Event()
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
@@ -65,17 +52,21 @@ class RosterBrowser(sleekxmpp.ClientXMPP):
event does not provide any additional
data.
"""
future = asyncio.Future()
def callback(result):
future.set_result(None)
try:
self.get_roster()
self.get_roster(callback=callback)
yield from future
except IqError as err:
print('Error: %' % err.iq['error']['condition'])
print('Error: %s' % err.iq['error']['condition'])
except IqTimeout:
print('Error: Request timed out')
self.send_presence()
print('Waiting for presence updates...\n')
self.presences_received.wait(5)
yield from asyncio.sleep(10)
print('Roster for %s' % self.boundjid.bare)
groups = self.client_roster.groups()
@@ -115,58 +106,37 @@ class RosterBrowser(sleekxmpp.ClientXMPP):
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
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 = 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.
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")
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: ")
xmpp = RosterBrowser(opts.jid, opts.password)
# 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 = RosterBrowser(args.jid, args.password)
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the dnspython 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(block=True)
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,15 +1,15 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2011 Dann Martens
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
ANY_ALL, Future
import time
@@ -20,7 +20,7 @@ class Boomerang(Endpoint):
@remote
def throw(self):
print "Duck!"
print("Duck!")

View File

@@ -1,15 +1,15 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2011 Dann Martens
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
ANY_ALL
import threading
import time

View File

@@ -1,15 +1,15 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2011 Dann Martens
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
ANY_ALL
import threading

View File

@@ -0,0 +1,90 @@
#!/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 asyncio
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
class S5BReceiver(slixmpp.ClientXMPP):
"""
A basic example of creating and using a SOCKS5 bytestream.
"""
def __init__(self, jid, password, filename):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.file = open(filename, 'wb')
self.add_event_handler("socks5_connected", self.stream_opened)
self.add_event_handler("socks5_data", self.stream_data)
self.add_event_handler("socks5_closed", self.stream_closed)
def stream_opened(self, sid):
logging.info('Stream opened. %s', sid)
def stream_data(self, data):
self.file.write(data)
def stream_closed(self, exception):
logging.info('Stream closed. %s', exception)
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 S5BReceiver and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = S5BReceiver(args.jid, args.password, args.filename)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0065', {
'auto_accept': True
}) # SOCKS5 Bytestreams
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process(forever=False)

View File

@@ -0,0 +1,124 @@
#!/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 asyncio
import logging
from getpass import getpass
from argparse import ArgumentParser
import slixmpp
from slixmpp.exceptions import IqError, IqTimeout
class S5BSender(slixmpp.ClientXMPP):
"""
A basic example of creating and using a SOCKS5 bytestream.
"""
def __init__(self, jid, password, receiver, filename):
slixmpp.ClientXMPP.__init__(self, jid, password)
self.receiver = receiver
self.file = open(filename, 'rb')
# The session_start event will be triggered when
# the bot establishes its connection with the server
# and the XML streams are ready for use.
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.
"""
try:
# Open the S5B stream in which to write to.
proxy = yield from self['xep_0065'].handshake(self.receiver)
# Send the entire file.
while True:
data = self.file.read(1048576)
if not data:
break
yield from proxy.write(data)
# And finally close the stream.
proxy.transport.write_eof()
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 S5BSender and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = S5BSender(args.jid, args.password, args.receiver, args.filename)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0065') # SOCKS5 Bytestreams
# Connect to the XMPP server and start processing XMPP stanzas.
xmpp.connect()
xmpp.process(forever=False)

View File

@@ -1,41 +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 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
class SendMsgBot(sleekxmpp.ClientXMPP):
class SendMsgBot(slixmpp.ClientXMPP):
"""
A basic SleekXMPP bot that will log in, send a message,
A basic Slixmpp bot that will log in, send a message,
and then log out.
"""
def __init__(self, jid, password, recipient, message):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
# The message we wish to send, and the JID that
# will receive it.
@@ -47,7 +36,7 @@ class SendMsgBot(sleekxmpp.ClientXMPP):
# 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, threaded=True)
self.add_event_handler("session_start", self.start)
def start(self, event):
"""
@@ -69,75 +58,53 @@ class SendMsgBot(sleekxmpp.ClientXMPP):
mbody=self.msg,
mtype='chat')
# Using wait=True ensures that the send queue will be
# emptied before ending the session.
self.disconnect(wait=True)
self.disconnect()
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
parser = ArgumentParser(description=SendMsgBot.__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")
optp.add_option("-t", "--to", dest="to",
help="JID to send the message to")
optp.add_option("-m", "--message", dest="message",
help="message to send")
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("-t", "--to", dest="to",
help="JID to send the message to")
parser.add_argument("-m", "--message", dest="message",
help="message to send")
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.to is None:
opts.to = raw_input("Send To: ")
if opts.message is None:
opts.message = raw_input("Message: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.to is None:
args.to = input("Send To: ")
if args.message is None:
args.message = input("Message: ")
# Setup the EchoBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does
# not matter.
xmpp = SendMsgBot(opts.jid, opts.password, opts.to, opts.message)
xmpp = SendMsgBot(args.jid, args.password, args.to, args.message)
xmpp.register_plugin('xep_0030') # Service Discovery
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 dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,50 +1,39 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SleekXMPP: The Sleek XMPP Library
Slixmpp: The Slick XMPP Library
Copyright (C) 2012 Nathanael C. Fritz
This file is part of SleekXMPP.
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import os
import sys
import imghdr
import logging
import getpass
from getpass import getpass
import threading
from optparse import OptionParser
from argparse import ArgumentParser
import sleekxmpp
from sleekxmpp.exceptions import XMPPError
import slixmpp
from slixmpp.exceptions import XMPPError
from slixmpp 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
class AvatarSetter(sleekxmpp.ClientXMPP):
class AvatarSetter(slixmpp.ClientXMPP):
"""
A basic script for downloading the avatars for a user's contacts.
"""
def __init__(self, jid, password, filepath):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
self.add_event_handler("session_start", self.start, threaded=True)
self.add_event_handler("session_start", self.start)
self.filepath = filepath
@asyncio.coroutine
def start(self, event):
"""
Process the session_start event.
@@ -63,7 +52,7 @@ class AvatarSetter(sleekxmpp.ClientXMPP):
avatar_file = None
try:
avatar_file = open(os.path.expanduser(self.filepath))
avatar_file = open(os.path.expanduser(self.filepath), 'rb')
except IOError:
print('Could not find file: %s' % self.filepath)
return self.disconnect()
@@ -77,32 +66,31 @@ class AvatarSetter(sleekxmpp.ClientXMPP):
avatar_file.close()
used_xep84 = False
try:
print('Publish XEP-0084 avatar data')
self['xep_0084'].publish_avatar(avatar)
used_xep84 = True
except XMPPError:
print('Could not publish XEP-0084 avatar')
try:
print('Update vCard with avatar')
self['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type)
except XMPPError:
print('Publish XEP-0084 avatar data')
result = yield from self['xep_0084'].publish_avatar(avatar)
if isinstance(result, XMPPError):
print('Could not publish XEP-0084 avatar')
else:
used_xep84 = True
print('Update vCard with avatar')
result = yield from self['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type)
if isinstance(result, XMPPError):
print('Could not set vCard avatar')
if used_xep84:
try:
print('Advertise XEP-0084 avatar metadata')
self['xep_0084'].publish_avatar_metadata([
{'id': avatar_id,
'type': avatar_type,
'bytes': avatar_bytes}
# We could advertise multiple avatars to provide
# options in image type, source (HTTP vs pubsub),
# size, etc.
# {'id': ....}
])
except XMPPError:
print('Advertise XEP-0084 avatar metadata')
result = yield from self['xep_0084'].publish_avatar_metadata([
{'id': avatar_id,
'type': avatar_type,
'bytes': avatar_bytes}
# We could advertise multiple avatars to provide
# options in image type, source (HTTP vs pubsub),
# size, etc.
# {'id': ....}
])
if isinstance(result, XMPPError):
print('Could not publish XEP-0084 metadata')
print('Wait for presence updates to propagate...')
@@ -111,64 +99,44 @@ class AvatarSetter(sleekxmpp.ClientXMPP):
if __name__ == '__main__':
# Setup the command line arguments.
optp = OptionParser()
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 = 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.
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("-f", "--file", dest="filepath",
help="path to the avatar file")
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("-f", "--file", dest="filepath",
help="path to the avatar file")
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.filepath is None:
opts.filepath = raw_input("Avatar file location: ")
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
if args.filepath is None:
args.filepath = input("Avatar file location: ")
xmpp = AvatarSetter(opts.jid, opts.password, opts.filepath)
xmpp = AvatarSetter(args.jid, args.password, args.filepath)
xmpp.register_plugin('xep_0054')
xmpp.register_plugin('xep_0153')
xmpp.register_plugin('xep_0084')
# 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 dnspython 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(block=True)
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,18 +1,18 @@
#!/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 getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
try:
from httplib import HTTPSConnection
@@ -21,24 +21,14 @@ except ImportError:
from urllib.parse import urlencode
from http.client import HTTPSConnection
import sleekxmpp
from sleekxmpp.xmlstream import JID
# 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):
from sleekxmpp.util.misc_ops import setdefaultencoding
setdefaultencoding('utf8')
else:
raw_input = input
import slixmpp
from slixmpp.xmlstream import JID
class ThirdPartyAuthBot(sleekxmpp.ClientXMPP):
class ThirdPartyAuthBot(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.
This version uses a thirdpary service for authentication,
@@ -46,7 +36,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP):
"""
def __init__(self, jid, password):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
# The X-GOOGLE-TOKEN mech is ranked lower than PLAIN
# due to Google only allowing a single SASL attempt per
@@ -55,7 +45,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP):
# X-GOOGLE-TOKEN with a TLS connection, explicitly select
# it using:
#
# sleekxmpp.ClientXMPP.__init__(self, jid, password,
# slixmpp.ClientXMPP.__init__(self, jid, password,
# sasl_mech="X-GOOGLE-TOKEN")
# The session_start event will be triggered when
@@ -104,37 +94,34 @@ class ThirdPartyAuthBot(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: ")
access_token = None
# Since documentation on how to work with Google tokens
@@ -156,11 +143,11 @@ if __name__ == '__main__':
params = urlencode({
'accountType': 'GOOGLE',
'service': 'mail',
'Email': JID(opts.jid).bare,
'Passwd': opts.password
'Email': JID(args.jid).bare,
'Passwd': args.password
})
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
'Content-Type': 'application/x-www-form-urlencoded'
}
try:
conn.request('POST', '/accounts/ClientLogin', params, headers)
@@ -208,12 +195,12 @@ if __name__ == '__main__':
# We're using an access token instead of a password, so we'll use `''` as
# a password argument filler.
xmpp = ThirdPartyAuthBot(opts.jid, '')
xmpp = ThirdPartyAuthBot(args.jid, '')
xmpp.credentials['access_token'] = access_token
# The credentials dictionary is used to provide additional authentication
# information beyond just a password.
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
@@ -231,17 +218,7 @@ if __name__ == '__main__':
# xmpp.ca_certs = "path/to/ca/cert"
# Connect to the XMPP server and start processing XMPP stanzas.
# Google only allows one SASL attempt per connection, so in order to
# Google only allows one SASL attempt per connection, so in order to
# enable the X-GOOGLE-TOKEN mechanism, we'll disable TLS.
if xmpp.connect(use_tls=False):
# If you do not have the dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
import logging
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
try:
import json
@@ -16,16 +16,16 @@ except ImportError:
print('This demo requires the requests package for using HTTP.')
sys.exit()
from sleekxmpp import ClientXMPP
from slixmpp import ClientXMPP
class LocationBot(ClientXMPP):
def __init__(self, jid, password):
super(LocationBot, self).__init__(jid, password)
super().__init__(jid, password)
self.add_event_handler('session_start', self.start, threaded=True)
self.add_event_handler('user_location_publish',
self.add_event_handler('session_start', self.start)
self.add_event_handler('user_location_publish',
self.user_location_publish)
self.register_plugin('xep_0004')
@@ -71,55 +71,35 @@ class LocationBot(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: ")
xmpp = LocationBot(opts.jid, opts.password)
# 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 = LocationBot(args.jid, args.password)
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
import logging
import getpass
from optparse import OptionParser
from getpass import getpass
from argparse import ArgumentParser
try:
from appscript import *
@@ -11,13 +11,13 @@ except ImportError:
print('This demo requires the appscript package to interact with iTunes.')
sys.exit()
from sleekxmpp import ClientXMPP
from slixmpp import ClientXMPP
class TuneBot(ClientXMPP):
def __init__(self, jid, password):
super(TuneBot, self).__init__(jid, password)
super().__init__(jid, password)
# Check for the current song every 5 seconds.
self.schedule('Check Current Tune', 5, self._update_tune, repeat=True)
@@ -83,55 +83,35 @@ class TuneBot(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: ")
xmpp = TuneBot(opts.jid, opts.password)
# 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 = TuneBot(args.jid, args.password)
# Connect to the XMPP server and start processing XMPP stanzas.
if xmpp.connect():
# If you do not have the dnspython 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(block=True)
print("Done")
else:
print("Unable to connect.")
xmpp.connect()
xmpp.process()

View File

@@ -1,233 +0,0 @@
#!python
"""Bootstrap setuptools installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from ez_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
DEFAULT_VERSION = "0.6c7"
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
}
import sys, os
def _validate_md5(egg_name, data):
if egg_name in md5_data:
from md5 import md5
digest = md5(data).hexdigest()
if digest != md5_data[egg_name]:
print >>sys.stderr, (
"md5 validation of %s failed! (Possible download problem?)"
% egg_name
)
sys.exit(2)
return data
def use_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, min_version=None,
download_delay=15
):
"""Automatically find/download setuptools and make it available on sys.path
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end with
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
it is not already available. If `download_delay` is specified, it should
be the number of seconds that will be paused before initiating a download,
should one be required. If an older version of setuptools is installed,
this routine will print a message to ``sys.stderr`` and raise SystemExit in
an attempt to abort the calling script.
"""
try:
import setuptools
if setuptools.__version__ == '0.0.1':
print >>sys.stderr, (
"You have an obsolete version of setuptools installed. Please\n"
"remove it from your system entirely before rerunning this script."
)
sys.exit(2)
except ImportError:
egg = download_setuptools(version, download_base, to_dir, download_delay)
sys.path.insert(0, egg)
import setuptools; setuptools.bootstrap_install_from = egg
import pkg_resources
try:
if not min_version:
min_version = version
pkg_resources.require("setuptools>="+min_version)
except pkg_resources.VersionConflict, e:
# XXX could we install in a subprocess here?
print >>sys.stderr, (
"The required version of setuptools (>=%s) is not available, and\n"
"can't be installed while this script is running. Please install\n"
" a more recent version first.\n\n(Currently using %r)"
) % (min_version, e.args[0])
sys.exit(2)
def download_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
delay = 15
):
"""Download setuptools from a specified location and return its filename
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download attempt.
"""
import urllib2, shutil
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
url = download_base + egg_name
saveto = os.path.join(to_dir, egg_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
from distutils import log
if delay:
log.warn("""
---------------------------------------------------------------------------
This script requires setuptools version %s to run (even to display
help). I will attempt to download it for you (from
%s), but
you may need to enable firewall access for this script first.
I will start the download in %d seconds.
(Note: if this machine does not have network access, please obtain the file
%s
and place it in this directory before rerunning this script.)
---------------------------------------------------------------------------""",
version, download_base, delay, url
); from time import sleep; sleep(delay)
log.warn("Downloading %s", url)
src = urllib2.urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = _validate_md5(egg_name, src.read())
dst = open(saveto,"wb"); dst.write(data)
finally:
if src: src.close()
if dst: dst.close()
return os.path.realpath(saveto)
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
try:
import setuptools
except ImportError:
egg = None
try:
egg = download_setuptools(version, delay=0)
sys.path.insert(0,egg)
from setuptools.command.easy_install import main
return main(list(argv)+[egg]) # we're done here
finally:
if egg and os.path.exists(egg):
os.unlink(egg)
else:
if setuptools.__version__ == '0.0.1':
# tell the user to uninstall obsolete version
use_setuptools(version)
req = "setuptools>="+version
import pkg_resources
try:
pkg_resources.require(req)
except pkg_resources.VersionConflict:
try:
from setuptools.command.easy_install import main
except ImportError:
from easy_install import main
main(list(argv)+[download_setuptools(delay=0)])
sys.exit(0) # try to force an exit
else:
if argv:
from setuptools.command.easy_install import main
main(argv)
else:
print "Setuptools version",version,"or greater has been installed."
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
def update_md5(filenames):
"""Update our built-in md5 registry"""
import re
from md5 import md5
for name in filenames:
base = os.path.basename(name)
f = open(name,'rb')
md5_data[base] = md5(f.read()).hexdigest()
f.close()
data = [" %r: %r,\n" % it for it in md5_data.items()]
data.sort()
repl = "".join(data)
import inspect
srcfile = inspect.getsourcefile(sys.modules[__name__])
f = open(srcfile, 'rb'); src = f.read(); f.close()
match = re.search("\nmd5_data = {\n([^}]+)}", src)
if not match:
print >>sys.stderr, "Internal error!"
sys.exit(2)
src = src[:match.start(1)] + repl + src[match.end(1):]
f = open(srcfile,'w')
f.write(src)
f.close()
if __name__=='__main__':
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
update_md5(sys.argv[2:])
else:
main(sys.argv[1:])

69
run_tests.py Executable file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
import sys
import logging
import unittest
from argparse import ArgumentParser
from distutils.core import Command
from importlib import import_module
from pathlib import Path
def run_tests(filenames=None):
"""
Find and run all tests in the tests/ directory.
Excludes live tests (tests/live_*).
"""
if not filenames:
filenames = [i for i in Path('tests').glob('test_*')]
else:
filenames = [Path(i) for i in filenames]
modules = ['.'.join(test.parts[:-1] + (test.stem,)) for test in filenames]
suites = []
for filename in modules:
module = import_module(filename)
suites.append(module.suite)
tests = unittest.TestSuite(suites)
runner = unittest.TextTestRunner(verbosity=2)
# Disable logging output
logging.basicConfig(level=100)
logging.disable(100)
result = runner.run(tests)
return result
# Add a 'test' command for setup.py
class TestCommand(Command):
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
run_tests()
if __name__ == '__main__':
parser = ArgumentParser(description='Run unit tests.')
parser.add_argument('tests', metavar='TEST', nargs='*', help='list of tests to run, or nothing to run them all')
args = parser.parse_args()
result = run_tests(args.tests)
print("<tests %s ran='%s' errors='%s' fails='%s' success='%s'/>" % (
"xmlns='http//andyet.net/protocol/tests'",
result.testsRun, len(result.errors),
len(result.failures), result.wasSuccessful()))
sys.exit(not result.wasSuccessful())

180
setup.py
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007-2011 Nathanael C. Fritz
@@ -7,150 +7,52 @@
# This software is licensed as described in the README.rst and LICENSE
# file, which you should have received as part of this distribution.
import sys
import codecs
from pathlib import Path
try:
from setuptools import setup, Command
from setuptools import setup
except ImportError:
from distutils.core import setup, Command
# from ez_setup import use_setuptools
from distutils.core import setup
from testall import TestCommand
from sleekxmpp.version import __version__
# if 'cygwin' in sys.platform.lower():
# min_version = '0.6c6'
# else:
# min_version = '0.6a9'
#
# try:
# use_setuptools(min_version=min_version)
# except TypeError:
# # locally installed ez_setup won't have min_version
# use_setuptools()
#
# from setuptools import setup, find_packages, Extension, Feature
try:
from Cython.Build import cythonize
except ImportError:
print('Cython not found, falling back to the slow stringprep module.')
ext_modules = None
else:
ext_modules = cythonize('slixmpp/stringprep.pyx')
VERSION = __version__
DESCRIPTION = 'SleekXMPP is an elegant Python library for XMPP (aka Jabber, Google Talk, etc).'
with codecs.open('README.rst', 'r', encoding='UTF-8') as readme:
LONG_DESCRIPTION = ''.join(readme)
from run_tests import TestCommand
from slixmpp.version import __version__
CLASSIFIERS = [ 'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.1',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Topic :: Software Development :: Libraries :: Python Modules',
]
VERSION = __version__
DESCRIPTION = ('Slixmpp is an elegant Python library for XMPP (aka Jabber, '
'Google Talk, etc).')
with open('README.rst', encoding='utf8') as readme:
LONG_DESCRIPTION = readme.read()
packages = [ 'sleekxmpp',
'sleekxmpp/stanza',
'sleekxmpp/test',
'sleekxmpp/roster',
'sleekxmpp/util',
'sleekxmpp/util/sasl',
'sleekxmpp/xmlstream',
'sleekxmpp/xmlstream/matcher',
'sleekxmpp/xmlstream/handler',
'sleekxmpp/plugins',
'sleekxmpp/plugins/xep_0004',
'sleekxmpp/plugins/xep_0004/stanza',
'sleekxmpp/plugins/xep_0009',
'sleekxmpp/plugins/xep_0009/stanza',
'sleekxmpp/plugins/xep_0012',
'sleekxmpp/plugins/xep_0013',
'sleekxmpp/plugins/xep_0016',
'sleekxmpp/plugins/xep_0020',
'sleekxmpp/plugins/xep_0027',
'sleekxmpp/plugins/xep_0030',
'sleekxmpp/plugins/xep_0030/stanza',
'sleekxmpp/plugins/xep_0033',
'sleekxmpp/plugins/xep_0047',
'sleekxmpp/plugins/xep_0048',
'sleekxmpp/plugins/xep_0049',
'sleekxmpp/plugins/xep_0050',
'sleekxmpp/plugins/xep_0054',
'sleekxmpp/plugins/xep_0059',
'sleekxmpp/plugins/xep_0060',
'sleekxmpp/plugins/xep_0060/stanza',
'sleekxmpp/plugins/xep_0065',
'sleekxmpp/plugins/xep_0066',
'sleekxmpp/plugins/xep_0071',
'sleekxmpp/plugins/xep_0077',
'sleekxmpp/plugins/xep_0078',
'sleekxmpp/plugins/xep_0080',
'sleekxmpp/plugins/xep_0084',
'sleekxmpp/plugins/xep_0085',
'sleekxmpp/plugins/xep_0086',
'sleekxmpp/plugins/xep_0091',
'sleekxmpp/plugins/xep_0092',
'sleekxmpp/plugins/xep_0095',
'sleekxmpp/plugins/xep_0096',
'sleekxmpp/plugins/xep_0107',
'sleekxmpp/plugins/xep_0108',
'sleekxmpp/plugins/xep_0115',
'sleekxmpp/plugins/xep_0118',
'sleekxmpp/plugins/xep_0128',
'sleekxmpp/plugins/xep_0131',
'sleekxmpp/plugins/xep_0152',
'sleekxmpp/plugins/xep_0153',
'sleekxmpp/plugins/xep_0172',
'sleekxmpp/plugins/xep_0184',
'sleekxmpp/plugins/xep_0186',
'sleekxmpp/plugins/xep_0191',
'sleekxmpp/plugins/xep_0196',
'sleekxmpp/plugins/xep_0198',
'sleekxmpp/plugins/xep_0199',
'sleekxmpp/plugins/xep_0202',
'sleekxmpp/plugins/xep_0203',
'sleekxmpp/plugins/xep_0221',
'sleekxmpp/plugins/xep_0224',
'sleekxmpp/plugins/xep_0231',
'sleekxmpp/plugins/xep_0235',
'sleekxmpp/plugins/xep_0249',
'sleekxmpp/plugins/xep_0257',
'sleekxmpp/plugins/xep_0258',
'sleekxmpp/plugins/xep_0279',
'sleekxmpp/plugins/xep_0280',
'sleekxmpp/plugins/xep_0297',
'sleekxmpp/plugins/xep_0308',
'sleekxmpp/plugins/xep_0313',
'sleekxmpp/plugins/xep_0319',
'sleekxmpp/plugins/xep_0323',
'sleekxmpp/plugins/xep_0323/stanza',
'sleekxmpp/plugins/xep_0325',
'sleekxmpp/plugins/xep_0325/stanza',
'sleekxmpp/plugins/google',
'sleekxmpp/plugins/google/gmail',
'sleekxmpp/plugins/google/auth',
'sleekxmpp/plugins/google/settings',
'sleekxmpp/plugins/google/nosave',
'sleekxmpp/features',
'sleekxmpp/features/feature_mechanisms',
'sleekxmpp/features/feature_mechanisms/stanza',
'sleekxmpp/features/feature_starttls',
'sleekxmpp/features/feature_bind',
'sleekxmpp/features/feature_session',
'sleekxmpp/features/feature_rosterver',
'sleekxmpp/features/feature_preapproval',
'sleekxmpp/thirdparty',
]
CLASSIFIERS = [
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 3.4',
'Topic :: Software Development :: Libraries :: Python Modules',
]
packages = [str(mod.parent) for mod in Path('slixmpp').rglob('__init__.py')]
setup(
name = "sleekxmpp",
version = VERSION,
description = DESCRIPTION,
long_description = LONG_DESCRIPTION,
author = 'Nathanael Fritz',
author_email = 'fritzy [at] netflint.net',
url = 'http://github.com/fritzy/SleekXMPP',
license = 'MIT',
platforms = [ 'any' ],
packages = packages,
requires = [ 'dnspython', 'pyasn1', 'pyasn1_modules' ],
classifiers = CLASSIFIERS,
cmdclass = {'test': TestCommand}
name="slixmpp",
version=VERSION,
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
author='Florent Le Coz',
author_email='louiz@louiz.org',
url='https://dev.louiz.org/projects/slixmpp',
license='MIT',
platforms=['any'],
packages=packages,
ext_modules=ext_modules,
install_requires=['aiodns>=1.0', 'pyasn1', 'pyasn1_modules'],
classifiers=CLASSIFIERS,
cmdclass={'test': TestCommand}
)

View File

@@ -1,30 +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
if hasattr(logging, 'NullHandler'):
NullHandler = logging.NullHandler
else:
class NullHandler(logging.Handler):
def handle(self, record):
pass
logging.getLogger(__name__).addHandler(NullHandler())
del NullHandler
from sleekxmpp.stanza import Message, Presence, Iq
from sleekxmpp.jid import JID, InvalidJID
from sleekxmpp.xmlstream.stanzabase import ET, ElementBase, register_stanza_plugin
from sleekxmpp.xmlstream.handler import *
from sleekxmpp.xmlstream import XMLStream, RestartStream
from sleekxmpp.xmlstream.matcher import *
from sleekxmpp.basexmpp import BaseXMPP
from sleekxmpp.clientxmpp import ClientXMPP
from sleekxmpp.componentxmpp import ComponentXMPP
from sleekxmpp.version import __version__, __version_info__

View File

@@ -1,19 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2011 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.features.feature_bind.bind import FeatureBind
from sleekxmpp.features.feature_bind.stanza import Bind
register_plugin(FeatureBind)
# Retain some backwards compatibility
feature_bind = FeatureBind

View File

@@ -1,22 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2011 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.features.feature_mechanisms.mechanisms import FeatureMechanisms
from sleekxmpp.features.feature_mechanisms.stanza import Mechanisms
from sleekxmpp.features.feature_mechanisms.stanza import Auth
from sleekxmpp.features.feature_mechanisms.stanza import Success
from sleekxmpp.features.feature_mechanisms.stanza import Failure
register_plugin(FeatureMechanisms)
# Retain some backwards compatibility
feature_mechanisms = FeatureMechanisms

View File

@@ -1,16 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2011 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.features.feature_mechanisms.stanza.mechanisms import Mechanisms
from sleekxmpp.features.feature_mechanisms.stanza.auth import Auth
from sleekxmpp.features.feature_mechanisms.stanza.success import Success
from sleekxmpp.features.feature_mechanisms.stanza.failure import Failure
from sleekxmpp.features.feature_mechanisms.stanza.challenge import Challenge
from sleekxmpp.features.feature_mechanisms.stanza.response import Response
from sleekxmpp.features.feature_mechanisms.stanza.abort import Abort

View File

@@ -1,15 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.features.feature_preapproval.preapproval import FeaturePreApproval
from sleekxmpp.features.feature_preapproval.stanza import PreApproval
register_plugin(FeaturePreApproval)

View File

@@ -1,19 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.features.feature_rosterver.rosterver import FeatureRosterVer
from sleekxmpp.features.feature_rosterver.stanza import RosterVer
register_plugin(FeatureRosterVer)
# Retain some backwards compatibility
feature_rosterver = FeatureRosterVer

View File

@@ -1,19 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2011 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.features.feature_session.session import FeatureSession
from sleekxmpp.features.feature_session.stanza import Session
register_plugin(FeatureSession)
# Retain some backwards compatibility
feature_session = FeatureSession

View File

@@ -1,19 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2011 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.features.feature_starttls.starttls import FeatureSTARTTLS
from sleekxmpp.features.feature_starttls.stanza import *
register_plugin(FeatureSTARTTLS)
# Retain some backwards compatibility
feature_starttls = FeatureSTARTTLS

View File

@@ -1,638 +0,0 @@
# -*- coding: utf-8 -*-
"""
sleekxmpp.jid
~~~~~~~~~~~~~~~~~~~~~~~
This module allows for working with Jabber IDs (JIDs).
Part of SleekXMPP: The Sleek XMPP Library
:copyright: (c) 2011 Nathanael C. Fritz
:license: MIT, see LICENSE for more details
"""
from __future__ import unicode_literals
import re
import socket
import stringprep
import threading
import encodings.idna
from copy import deepcopy
from sleekxmpp.util import stringprep_profiles
from sleekxmpp.thirdparty import OrderedDict
#: These characters are not allowed to appear in a JID.
ILLEGAL_CHARS = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r' + \
'\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19' + \
'\x1a\x1b\x1c\x1d\x1e\x1f' + \
' !"#$%&\'()*+,./:;<=>?@[\\]^_`{|}~\x7f'
#: The basic regex pattern that a JID must match in order to determine
#: the local, domain, and resource parts. This regex does NOT do any
#: validation, which requires application of nodeprep, resourceprep, etc.
JID_PATTERN = re.compile(
"^(?:([^\"&'/:<>@]{1,1023})@)?([^/@]{1,1023})(?:/(.{1,1023}))?$"
)
#: The set of escape sequences for the characters not allowed by nodeprep.
JID_ESCAPE_SEQUENCES = set(['\\20', '\\22', '\\26', '\\27', '\\2f',
'\\3a', '\\3c', '\\3e', '\\40', '\\5c'])
#: A mapping of unallowed characters to their escape sequences. An escape
#: sequence for '\' is also included since it must also be escaped in
#: certain situations.
JID_ESCAPE_TRANSFORMATIONS = {' ': '\\20',
'"': '\\22',
'&': '\\26',
"'": '\\27',
'/': '\\2f',
':': '\\3a',
'<': '\\3c',
'>': '\\3e',
'@': '\\40',
'\\': '\\5c'}
#: The reverse mapping of escape sequences to their original forms.
JID_UNESCAPE_TRANSFORMATIONS = {'\\20': ' ',
'\\22': '"',
'\\26': '&',
'\\27': "'",
'\\2f': '/',
'\\3a': ':',
'\\3c': '<',
'\\3e': '>',
'\\40': '@',
'\\5c': '\\'}
JID_CACHE = OrderedDict()
JID_CACHE_LOCK = threading.Lock()
JID_CACHE_MAX_SIZE = 1024
def _cache(key, parts, locked):
JID_CACHE[key] = (parts, locked)
if len(JID_CACHE) > JID_CACHE_MAX_SIZE:
with JID_CACHE_LOCK:
while len(JID_CACHE) > JID_CACHE_MAX_SIZE:
found = None
for key, item in JID_CACHE.items():
if not item[1]: # if not locked
found = key
break
if not found: # more than MAX_SIZE locked
# warn?
break
del JID_CACHE[found]
# pylint: disable=c0103
#: The nodeprep profile of stringprep used to validate the local,
#: or username, portion of a JID.
nodeprep = stringprep_profiles.create(
nfkc=True,
bidi=True,
mappings=[
stringprep_profiles.b1_mapping,
stringprep.map_table_b2],
prohibited=[
stringprep.in_table_c11,
stringprep.in_table_c12,
stringprep.in_table_c21,
stringprep.in_table_c22,
stringprep.in_table_c3,
stringprep.in_table_c4,
stringprep.in_table_c5,
stringprep.in_table_c6,
stringprep.in_table_c7,
stringprep.in_table_c8,
stringprep.in_table_c9,
lambda c: c in ' \'"&/:<>@'],
unassigned=[stringprep.in_table_a1])
# pylint: disable=c0103
#: The resourceprep profile of stringprep, which is used to validate
#: the resource portion of a JID.
resourceprep = stringprep_profiles.create(
nfkc=True,
bidi=True,
mappings=[stringprep_profiles.b1_mapping],
prohibited=[
stringprep.in_table_c12,
stringprep.in_table_c21,
stringprep.in_table_c22,
stringprep.in_table_c3,
stringprep.in_table_c4,
stringprep.in_table_c5,
stringprep.in_table_c6,
stringprep.in_table_c7,
stringprep.in_table_c8,
stringprep.in_table_c9],
unassigned=[stringprep.in_table_a1])
def _parse_jid(data):
"""
Parse string data into the node, domain, and resource
components of a JID, if possible.
:param string data: A string that is potentially a JID.
:raises InvalidJID:
:returns: tuple of the validated local, domain, and resource strings
"""
match = JID_PATTERN.match(data)
if not match:
raise InvalidJID('JID could not be parsed')
(node, domain, resource) = match.groups()
node = _validate_node(node)
domain = _validate_domain(domain)
resource = _validate_resource(resource)
return node, domain, resource
def _validate_node(node):
"""Validate the local, or username, portion of a JID.
:raises InvalidJID:
:returns: The local portion of a JID, as validated by nodeprep.
"""
try:
if node is not None:
node = nodeprep(node)
if not node:
raise InvalidJID('Localpart must not be 0 bytes')
if len(node) > 1023:
raise InvalidJID('Localpart must be less than 1024 bytes')
return node
except stringprep_profiles.StringPrepError:
raise InvalidJID('Invalid local part')
def _validate_domain(domain):
"""Validate the domain portion of a JID.
IP literal addresses are left as-is, if valid. Domain names
are stripped of any trailing label separators (`.`), and are
checked with the nameprep profile of stringprep. If the given
domain is actually a punyencoded version of a domain name, it
is converted back into its original Unicode form. Domains must
also not start or end with a dash (`-`).
:raises InvalidJID:
:returns: The validated domain name
"""
ip_addr = False
# First, check if this is an IPv4 address
try:
socket.inet_aton(domain)
ip_addr = True
except socket.error:
pass
# Check if this is an IPv6 address
if not ip_addr and hasattr(socket, 'inet_pton'):
try:
socket.inet_pton(socket.AF_INET6, domain.strip('[]'))
domain = '[%s]' % domain.strip('[]')
ip_addr = True
except (socket.error, ValueError):
pass
if not ip_addr:
# This is a domain name, which must be checked further
if domain and domain[-1] == '.':
domain = domain[:-1]
domain_parts = []
for label in domain.split('.'):
try:
label = encodings.idna.nameprep(label)
encodings.idna.ToASCII(label)
pass_nameprep = True
except UnicodeError:
pass_nameprep = False
if not pass_nameprep:
raise InvalidJID('Could not encode domain as ASCII')
if label.startswith('xn--'):
label = encodings.idna.ToUnicode(label)
for char in label:
if char in ILLEGAL_CHARS:
raise InvalidJID('Domain contains illegal characters')
if '-' in (label[0], label[-1]):
raise InvalidJID('Domain started or ended with -')
domain_parts.append(label)
domain = '.'.join(domain_parts)
if not domain:
raise InvalidJID('Domain must not be 0 bytes')
if len(domain) > 1023:
raise InvalidJID('Domain must be less than 1024 bytes')
return domain
def _validate_resource(resource):
"""Validate the resource portion of a JID.
:raises InvalidJID:
:returns: The local portion of a JID, as validated by resourceprep.
"""
try:
if resource is not None:
resource = resourceprep(resource)
if not resource:
raise InvalidJID('Resource must not be 0 bytes')
if len(resource) > 1023:
raise InvalidJID('Resource must be less than 1024 bytes')
return resource
except stringprep_profiles.StringPrepError:
raise InvalidJID('Invalid resource')
def _escape_node(node):
"""Escape the local portion of a JID."""
result = []
for i, char in enumerate(node):
if char == '\\':
if ''.join((node[i:i+3])) in JID_ESCAPE_SEQUENCES:
result.append('\\5c')
continue
result.append(char)
for i, char in enumerate(result):
if char != '\\':
result[i] = JID_ESCAPE_TRANSFORMATIONS.get(char, char)
escaped = ''.join(result)
if escaped.startswith('\\20') or escaped.endswith('\\20'):
raise InvalidJID('Escaped local part starts or ends with "\\20"')
_validate_node(escaped)
return escaped
def _unescape_node(node):
"""Unescape a local portion of a JID.
.. note::
The unescaped local portion is meant ONLY for presentation,
and should not be used for other purposes.
"""
unescaped = []
seq = ''
for i, char in enumerate(node):
if char == '\\':
seq = node[i:i+3]
if seq not in JID_ESCAPE_SEQUENCES:
seq = ''
if seq:
if len(seq) == 3:
unescaped.append(JID_UNESCAPE_TRANSFORMATIONS.get(seq, char))
# Pop character off the escape sequence, and ignore it
seq = seq[1:]
else:
unescaped.append(char)
unescaped = ''.join(unescaped)
return unescaped
def _format_jid(local=None, domain=None, resource=None):
"""Format the given JID components into a full or bare JID.
:param string local: Optional. The local portion of the JID.
:param string domain: Required. The domain name portion of the JID.
:param strin resource: Optional. The resource portion of the JID.
:return: A full or bare JID string.
"""
result = []
if local:
result.append(local)
result.append('@')
if domain:
result.append(domain)
if resource:
result.append('/')
result.append(resource)
return ''.join(result)
class InvalidJID(ValueError):
"""
Raised when attempting to create a JID that does not pass validation.
It can also be raised if modifying an existing JID in such a way as
to make it invalid, such trying to remove the domain from an existing
full JID while the local and resource portions still exist.
"""
# pylint: disable=R0903
class UnescapedJID(object):
"""
.. versionadded:: 1.1.10
"""
def __init__(self, local, domain, resource):
self._jid = (local, domain, resource)
# pylint: disable=R0911
def __getattr__(self, name):
"""Retrieve the given JID component.
:param name: one of: user, server, domain, resource,
full, or bare.
"""
if name == 'resource':
return self._jid[2] or ''
elif name in ('user', 'username', 'local', 'node'):
return self._jid[0] or ''
elif name in ('server', 'domain', 'host'):
return self._jid[1] or ''
elif name in ('full', 'jid'):
return _format_jid(*self._jid)
elif name == 'bare':
return _format_jid(self._jid[0], self._jid[1])
elif name == '_jid':
return getattr(super(JID, self), '_jid')
else:
return None
def __str__(self):
"""Use the full JID as the string value."""
return _format_jid(*self._jid)
def __repr__(self):
"""Use the full JID as the representation."""
return self.__str__()
class JID(object):
"""
A representation of a Jabber ID, or JID.
Each JID may have three components: a user, a domain, and an optional
resource. For example: user@domain/resource
When a resource is not used, the JID is called a bare JID.
The JID is a full JID otherwise.
**JID Properties:**
:jid: Alias for ``full``.
:full: The string value of the full JID.
:bare: The string value of the bare JID.
:user: The username portion of the JID.
:username: Alias for ``user``.
:local: Alias for ``user``.
:node: Alias for ``user``.
:domain: The domain name portion of the JID.
:server: Alias for ``domain``.
:host: Alias for ``domain``.
:resource: The resource portion of the JID.
:param string jid:
A string of the form ``'[user@]domain[/resource]'``.
:param string local:
Optional. Specify the local, or username, portion
of the JID. If provided, it will override the local
value provided by the `jid` parameter. The given
local value will also be escaped if necessary.
:param string domain:
Optional. Specify the domain of the JID. If
provided, it will override the domain given by
the `jid` parameter.
:param string resource:
Optional. Specify the resource value of the JID.
If provided, it will override the domain given
by the `jid` parameter.
:raises InvalidJID:
"""
# pylint: disable=W0212
def __init__(self, jid=None, **kwargs):
locked = kwargs.get('cache_lock', False)
in_local = kwargs.get('local', None)
in_domain = kwargs.get('domain', None)
in_resource = kwargs.get('resource', None)
parts = None
if in_local or in_domain or in_resource:
parts = (in_local, in_domain, in_resource)
# only check cache if there is a jid string, or parts, not if there
# are both
self._jid = None
key = None
if (jid is not None) and (parts is None):
if isinstance(jid, JID):
# it's already good to go, and there are no additions
self._jid = jid._jid
return
key = jid
self._jid, locked = JID_CACHE.get(jid, (None, locked))
elif jid is None and parts is not None:
key = parts
self._jid, locked = JID_CACHE.get(parts, (None, locked))
if not self._jid:
if not jid:
parsed_jid = (None, None, None)
elif not isinstance(jid, JID):
parsed_jid = _parse_jid(jid)
else:
parsed_jid = jid._jid
local, domain, resource = parsed_jid
if 'local' in kwargs:
local = _escape_node(in_local)
if 'domain' in kwargs:
domain = _validate_domain(in_domain)
if 'resource' in kwargs:
resource = _validate_resource(in_resource)
self._jid = (local, domain, resource)
if key:
_cache(key, self._jid, locked)
def unescape(self):
"""Return an unescaped JID object.
Using an unescaped JID is preferred for displaying JIDs
to humans, and they should NOT be used for any other
purposes than for presentation.
:return: :class:`UnescapedJID`
.. versionadded:: 1.1.10
"""
return UnescapedJID(_unescape_node(self._jid[0]),
self._jid[1],
self._jid[2])
def regenerate(self):
"""No-op
.. deprecated:: 1.1.10
"""
pass
def reset(self, data):
"""Start fresh from a new JID string.
:param string data: A string of the form ``'[user@]domain[/resource]'``.
.. deprecated:: 1.1.10
"""
self._jid = JID(data)._jid
@property
def resource(self):
return self._jid[2] or ''
@property
def user(self):
return self._jid[0] or ''
@property
def local(self):
return self._jid[0] or ''
@property
def node(self):
return self._jid[0] or ''
@property
def username(self):
return self._jid[0] or ''
@property
def bare(self):
return _format_jid(self._jid[0], self._jid[1])
@property
def server(self):
return self._jid[1] or ''
@property
def domain(self):
return self._jid[1] or ''
@property
def host(self):
return self._jid[1] or ''
@property
def full(self):
return _format_jid(*self._jid)
@property
def jid(self):
return _format_jid(*self._jid)
@property
def bare(self):
return _format_jid(self._jid[0], self._jid[1])
@resource.setter
def resource(self, value):
self._jid = JID(self, resource=value)._jid
@user.setter
def user(self, value):
self._jid = JID(self, local=value)._jid
@username.setter
def username(self, value):
self._jid = JID(self, local=value)._jid
@local.setter
def local(self, value):
self._jid = JID(self, local=value)._jid
@node.setter
def node(self, value):
self._jid = JID(self, local=value)._jid
@server.setter
def server(self, value):
self._jid = JID(self, domain=value)._jid
@domain.setter
def domain(self, value):
self._jid = JID(self, domain=value)._jid
@host.setter
def host(self, value):
self._jid = JID(self, domain=value)._jid
@full.setter
def full(self, value):
self._jid = JID(value)._jid
@jid.setter
def jid(self, value):
self._jid = JID(value)._jid
@bare.setter
def bare(self, value):
parsed = JID(value)._jid
self._jid = (parsed[0], parsed[1], self._jid[2])
def __str__(self):
"""Use the full JID as the string value."""
return _format_jid(*self._jid)
def __repr__(self):
"""Use the full JID as the representation."""
return self.__str__()
# pylint: disable=W0212
def __eq__(self, other):
"""Two JIDs are equal if they have the same full JID value."""
if isinstance(other, UnescapedJID):
return False
other = JID(other)
return self._jid == other._jid
# pylint: disable=W0212
def __ne__(self, other):
"""Two JIDs are considered unequal if they are not equal."""
return not self == other
def __hash__(self):
"""Hash a JID based on the string version of its full JID."""
return hash(self.__str__())
def __copy__(self):
"""Generate a duplicate JID."""
return JID(self)
def __deepcopy__(self, memo):
"""Generate a duplicate JID."""
return JID(deepcopy(str(self), memo))

View File

@@ -1,47 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin, BasePlugin
from sleekxmpp.plugins.google.gmail import Gmail
from sleekxmpp.plugins.google.auth import GoogleAuth
from sleekxmpp.plugins.google.settings import GoogleSettings
from sleekxmpp.plugins.google.nosave import GoogleNoSave
class Google(BasePlugin):
"""
Google: Custom GTalk Features
Also see: <https://developers.google.com/talk/jep_extensions/extensions>
"""
name = 'google'
description = 'Google: Custom GTalk Features'
dependencies = set([
'gmail',
'google_settings',
'google_nosave',
'google_auth'
])
def __getitem__(self, attr):
if attr in ('settings', 'nosave', 'auth'):
return self.xmpp['google_%s' % attr]
elif attr == 'gmail':
return self.xmpp['gmail']
else:
raise KeyError(attr)
register_plugin(Gmail)
register_plugin(GoogleAuth)
register_plugin(GoogleSettings)
register_plugin(GoogleNoSave)
register_plugin(Google)

View File

@@ -1,10 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.google.auth import stanza
from sleekxmpp.plugins.google.auth.auth import GoogleAuth

View File

@@ -1,52 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.plugins import BasePlugin
from sleekxmpp.plugins.google.auth import stanza
log = logging.getLogger(__name__)
class GoogleAuth(BasePlugin):
"""
Google: Auth Extensions (JID Domain Discovery, OAuth2)
Also see:
<https://developers.google.com/talk/jep_extensions/jid_domain_change>
<https://developers.google.com/talk/jep_extensions/oauth>
"""
name = 'google_auth'
description = 'Google: Auth Extensions (JID Domain Discovery, OAuth2)'
dependencies = set(['feature_mechanisms'])
stanza = stanza
def plugin_init(self):
self.xmpp.namespace_map['http://www.google.com/talk/protocol/auth'] = 'ga'
register_stanza_plugin(self.xmpp['feature_mechanisms'].stanza.Auth,
stanza.GoogleAuth)
self.xmpp.add_filter('out', self._auth)
def plugin_end(self):
self.xmpp.del_filter('out', self._auth)
def _auth(self, stanza):
if isinstance(stanza, self.xmpp['feature_mechanisms'].stanza.Auth):
stanza.stream = self.xmpp
stanza['google']['client_uses_full_bind_result'] = True
if stanza['mechanism'] == 'X-OAUTH2':
stanza['google']['service'] = 'oauth2'
print(stanza)
return stanza

View File

@@ -1,10 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.google.gmail import stanza
from sleekxmpp.plugins.google.gmail.notifications import Gmail

View File

@@ -1,101 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin
class GmailQuery(ElementBase):
namespace = 'google:mail:notify'
name = 'query'
plugin_attrib = 'gmail'
interfaces = set(['newer_than_time', 'newer_than_tid', 'search'])
def get_search(self):
return self._get_attr('q', '')
def set_search(self, search):
self._set_attr('q', search)
def del_search(self):
self._del_attr('q')
def get_newer_than_time(self):
return self._get_attr('newer-than-time', '')
def set_newer_than_time(self, value):
self._set_attr('newer-than-time', value)
def del_newer_than_time(self):
self._del_attr('newer-than-time')
def get_newer_than_tid(self):
return self._get_attr('newer-than-tid', '')
def set_newer_than_tid(self, value):
self._set_attr('newer-than-tid', value)
def del_newer_than_tid(self):
self._del_attr('newer-than-tid')
class MailBox(ElementBase):
namespace = 'google:mail:notify'
name = 'mailbox'
plugin_attrib = 'gmail_messages'
interfaces = set(['result_time', 'url', 'matched', 'estimate'])
def get_matched(self):
return self._get_attr('total-matched', '')
def get_estimate(self):
return self._get_attr('total-estimate', '') == '1'
def get_result_time(self):
return self._get_attr('result-time', '')
class MailThread(ElementBase):
namespace = 'google:mail:notify'
name = 'mail-thread-info'
plugin_attrib = 'thread'
plugin_multi_attrib = 'threads'
interfaces = set(['tid', 'participation', 'messages', 'date',
'senders', 'url', 'labels', 'subject', 'snippet'])
sub_interfaces = set(['labels', 'subject', 'snippet'])
def get_senders(self):
result = []
senders = self.xml.findall('{%s}senders/{%s}sender' % (
self.namespace, self.namespace))
for sender in senders:
result.append(MailSender(xml=sender))
return result
class MailSender(ElementBase):
namespace = 'google:mail:notify'
name = 'sender'
plugin_attrib = name
interfaces = set(['address', 'name', 'originator', 'unread'])
def get_originator(self):
return self.xml.attrib.get('originator', '0') == '1'
def get_unread(self):
return self.xml.attrib.get('unread', '0') == '1'
class NewMail(ElementBase):
namespace = 'google:mail:notify'
name = 'new-mail'
plugin_attrib = 'gmail_notification'
register_stanza_plugin(MailBox, MailThread, iterable=True)

View File

@@ -1,10 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.google.nosave import stanza
from sleekxmpp.plugins.google.nosave.nosave import GoogleNoSave

View File

@@ -1,83 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp.stanza import Iq, Message
from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.plugins import BasePlugin
from sleekxmpp.plugins.google.nosave import stanza
log = logging.getLogger(__name__)
class GoogleNoSave(BasePlugin):
"""
Google: Off the Record Chats
NOTE: This is NOT an encryption method.
Also see <https://developers.google.com/talk/jep_extensions/otr>.
"""
name = 'google_nosave'
description = 'Google: Off the Record Chats'
dependencies = set(['google_settings'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Message, stanza.NoSave)
register_stanza_plugin(Iq, stanza.NoSaveQuery)
self.xmpp.register_handler(
Callback('Google Nosave',
StanzaPath('iq@type=set/google_nosave'),
self._handle_nosave_change))
def plugin_end(self):
self.xmpp.remove_handler('Google Nosave')
def enable(self, jid=None, block=True, timeout=None, callback=None):
if jid is None:
self.xmpp['google_settings'].update({'archiving_enabled': False},
block=block, timeout=timeout, callback=callback)
else:
iq = self.xmpp.Iq()
iq['type'] = 'set'
iq['google_nosave']['item']['jid'] = jid
iq['google_nosave']['item']['value'] = True
return iq.send(block=block, timeout=timeout, callback=callback)
def disable(self, jid=None, block=True, timeout=None, callback=None):
if jid is None:
self.xmpp['google_settings'].update({'archiving_enabled': True},
block=block, timeout=timeout, callback=callback)
else:
iq = self.xmpp.Iq()
iq['type'] = 'set'
iq['google_nosave']['item']['jid'] = jid
iq['google_nosave']['item']['value'] = False
return iq.send(block=block, timeout=timeout, callback=callback)
def get(self, block=True, timeout=None, callback=None):
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq.enable('google_nosave')
return iq.send(block=block, timeout=timeout, callback=callback)
def _handle_nosave_change(self, iq):
reply = self.xmpp.Iq()
reply['type'] = 'result'
reply['id'] = iq['id']
reply['to'] = iq['from']
reply.send()
self.xmpp.event('google_nosave_change', iq)

View File

@@ -1,10 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.google.settings import stanza
from sleekxmpp.plugins.google.settings.settings import GoogleSettings

View File

@@ -1,110 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin
class UserSettings(ElementBase):
name = 'usersetting'
namespace = 'google:setting'
plugin_attrib = 'google_settings'
interfaces = set(['auto_accept_suggestions',
'mail_notifications',
'archiving_enabled',
'gmail',
'email_verified',
'domain_privacy_notice',
'display_name'])
def _get_setting(self, setting):
xml = self.xml.find('{%s}%s' % (self.namespace, setting))
if xml is not None:
return xml.attrib.get('value', '') == 'true'
return False
def _set_setting(self, setting, value):
self._del_setting(setting)
if value in (True, False):
xml = ET.Element('{%s}%s' % (self.namespace, setting))
xml.attrib['value'] = 'true' if value else 'false'
self.xml.append(xml)
def _del_setting(self, setting):
xml = self.xml.find('{%s}%s' % (self.namespace, setting))
if xml is not None:
self.xml.remove(xml)
def get_display_name(self):
xml = self.xml.find('{%s}%s' % (self.namespace, 'displayname'))
if xml is not None:
return xml.attrib.get('value', '')
return ''
def set_display_name(self, value):
self._del_setting(setting)
if value:
xml = ET.Element('{%s}%s' % (self.namespace, 'displayname'))
xml.attrib['value'] = value
self.xml.append(xml)
def del_display_name(self):
self._del_setting('displayname')
def get_auto_accept_suggestions(self):
return self._get_setting('autoacceptsuggestions')
def get_mail_notifications(self):
return self._get_setting('mailnotifications')
def get_archiving_enabled(self):
return self._get_setting('archivingenabled')
def get_gmail(self):
return self._get_setting('gmail')
def get_email_verified(self):
return self._get_setting('emailverified')
def get_domain_privacy_notice(self):
return self._get_setting('domainprivacynotice')
def set_auto_accept_suggestions(self, value):
self._set_setting('autoacceptsuggestions', value)
def set_mail_notifications(self, value):
self._set_setting('mailnotifications', value)
def set_archiving_enabled(self, value):
self._set_setting('archivingenabled', value)
def set_gmail(self, value):
self._set_setting('gmail', value)
def set_email_verified(self, value):
self._set_setting('emailverified', value)
def set_domain_privacy_notice(self, value):
self._set_setting('domainprivacynotice', value)
def del_auto_accept_suggestions(self):
self._del_setting('autoacceptsuggestions')
def del_mail_notifications(self):
self._del_setting('mailnotifications')
def del_archiving_enabled(self):
self._del_setting('archivingenabled')
def del_gmail(self):
self._del_setting('gmail')
def del_email_verified(self):
self._del_setting('emailverified')
def del_domain_privacy_notice(self):
self._del_setting('domainprivacynotice')

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