From 5ab77c745270d7d5c016c1dc7ef2a82533a4b16e Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 17 Jul 2014 14:19:04 +0200 Subject: Rename to slixmpp --- .gitignore | 2 +- README.rst | 97 +- docs/Makefile | 8 +- docs/api/basexmpp.rst | 2 +- docs/api/clientxmpp.rst | 2 +- docs/api/componentxmpp.rst | 2 +- docs/api/exceptions.rst | 2 +- docs/api/xmlstream/filesocket.rst | 2 +- docs/api/xmlstream/handler.rst | 6 +- docs/api/xmlstream/jid.rst | 2 +- docs/api/xmlstream/matcher.rst | 10 +- docs/api/xmlstream/scheduler.rst | 2 +- docs/api/xmlstream/stanzabase.rst | 14 +- docs/api/xmlstream/tostring.rst | 8 +- docs/api/xmlstream/xmlstream.rst | 2 +- docs/architecture.rst | 34 +- docs/conf.py | 12 +- docs/create_plugin.rst | 58 +- docs/event_index.rst | 124 +- docs/getting_started/component.rst | 18 +- docs/getting_started/echobot.rst | 68 +- docs/getting_started/iq.rst | 54 +- docs/getting_started/muc.rst | 24 +- docs/getting_started/proxy.rst | 6 +- docs/getting_started/sendlogout.rst | 20 +- docs/guide_xep_0030.rst | 4 +- docs/index.rst | 36 +- docs/make.bat | 4 +- docs/xmpp_tdg.rst | 20 +- examples/IoT_TestDevice.py | 20 +- examples/adhoc_provider.py | 16 +- examples/adhoc_user.py | 16 +- examples/admin_commands.py | 16 +- examples/custom_stanzas/custom_stanza_provider.py | 26 +- examples/custom_stanzas/custom_stanza_user.py | 22 +- examples/custom_stanzas/stanza.py | 8 +- examples/disco_browser.py | 16 +- examples/download_avatars.py | 16 +- examples/echo_client.py | 16 +- examples/echo_component.py | 14 +- examples/gtalk_custom_domain.py | 18 +- examples/ibb_transfer/ibb_receiver.py | 14 +- examples/ibb_transfer/ibb_sender.py | 14 +- examples/migrate_roster.py | 10 +- examples/muc.py | 16 +- examples/ping.py | 16 +- examples/proxy_echo_client.py | 16 +- examples/pubsub_client.py | 10 +- examples/pubsub_events.py | 14 +- examples/register_account.py | 18 +- examples/roster_browser.py | 16 +- examples/rpc_async.py | 6 +- examples/rpc_client_side.py | 6 +- examples/rpc_server_side.py | 6 +- examples/send_client.py | 16 +- examples/set_avatar.py | 16 +- examples/thirdparty_auth.py | 20 +- examples/user_location.py | 2 +- examples/user_tune.py | 2 +- setup.py | 190 +- sleekxmpp/__init__.py | 30 - sleekxmpp/api.py | 200 --- sleekxmpp/basexmpp.py | 832 --------- sleekxmpp/clientxmpp.py | 333 ---- sleekxmpp/componentxmpp.py | 159 -- sleekxmpp/exceptions.py | 91 - sleekxmpp/features/__init__.py | 16 - sleekxmpp/features/feature_bind/__init__.py | 19 - sleekxmpp/features/feature_bind/bind.py | 65 - sleekxmpp/features/feature_bind/stanza.py | 21 - sleekxmpp/features/feature_mechanisms/__init__.py | 22 - .../features/feature_mechanisms/mechanisms.py | 244 --- .../features/feature_mechanisms/stanza/__init__.py | 16 - .../features/feature_mechanisms/stanza/abort.py | 24 - .../features/feature_mechanisms/stanza/auth.py | 49 - .../feature_mechanisms/stanza/challenge.py | 39 - .../features/feature_mechanisms/stanza/failure.py | 76 - .../feature_mechanisms/stanza/mechanisms.py | 53 - .../features/feature_mechanisms/stanza/response.py | 39 - .../features/feature_mechanisms/stanza/success.py | 38 - sleekxmpp/features/feature_preapproval/__init__.py | 15 - .../features/feature_preapproval/preapproval.py | 42 - sleekxmpp/features/feature_preapproval/stanza.py | 17 - sleekxmpp/features/feature_rosterver/__init__.py | 19 - sleekxmpp/features/feature_rosterver/rosterver.py | 42 - sleekxmpp/features/feature_rosterver/stanza.py | 17 - sleekxmpp/features/feature_session/__init__.py | 19 - sleekxmpp/features/feature_session/session.py | 54 - sleekxmpp/features/feature_session/stanza.py | 20 - sleekxmpp/features/feature_starttls/__init__.py | 19 - sleekxmpp/features/feature_starttls/stanza.py | 45 - sleekxmpp/features/feature_starttls/starttls.py | 66 - sleekxmpp/jid.py | 638 ------- sleekxmpp/plugins/__init__.py | 86 - sleekxmpp/plugins/base.py | 360 ---- sleekxmpp/plugins/gmail_notify.py | 149 -- sleekxmpp/plugins/google/__init__.py | 47 - sleekxmpp/plugins/google/auth/__init__.py | 10 - sleekxmpp/plugins/google/auth/auth.py | 52 - sleekxmpp/plugins/google/auth/stanza.py | 49 - sleekxmpp/plugins/google/gmail/__init__.py | 10 - sleekxmpp/plugins/google/gmail/notifications.py | 96 -- sleekxmpp/plugins/google/gmail/stanza.py | 101 -- sleekxmpp/plugins/google/nosave/__init__.py | 10 - sleekxmpp/plugins/google/nosave/nosave.py | 83 - sleekxmpp/plugins/google/nosave/stanza.py | 59 - sleekxmpp/plugins/google/settings/__init__.py | 10 - sleekxmpp/plugins/google/settings/settings.py | 65 - sleekxmpp/plugins/google/settings/stanza.py | 110 -- sleekxmpp/plugins/xep_0004/__init__.py | 22 - sleekxmpp/plugins/xep_0004/dataforms.py | 57 - sleekxmpp/plugins/xep_0004/stanza/__init__.py | 10 - sleekxmpp/plugins/xep_0004/stanza/field.py | 183 -- sleekxmpp/plugins/xep_0004/stanza/form.py | 257 --- sleekxmpp/plugins/xep_0009/__init__.py | 20 - sleekxmpp/plugins/xep_0009/binding.py | 173 -- sleekxmpp/plugins/xep_0009/remote.py | 742 -------- sleekxmpp/plugins/xep_0009/rpc.py | 218 --- sleekxmpp/plugins/xep_0009/stanza/RPC.py | 64 - sleekxmpp/plugins/xep_0009/stanza/__init__.py | 9 - sleekxmpp/plugins/xep_0012/__init__.py | 19 - sleekxmpp/plugins/xep_0012/last_activity.py | 157 -- sleekxmpp/plugins/xep_0012/stanza.py | 32 - sleekxmpp/plugins/xep_0013/__init__.py | 15 - sleekxmpp/plugins/xep_0013/offline.py | 134 -- sleekxmpp/plugins/xep_0013/stanza.py | 53 - sleekxmpp/plugins/xep_0016/__init__.py | 16 - sleekxmpp/plugins/xep_0016/privacy.py | 110 -- sleekxmpp/plugins/xep_0016/stanza.py | 103 -- sleekxmpp/plugins/xep_0020/__init__.py | 16 - sleekxmpp/plugins/xep_0020/feature_negotiation.py | 36 - sleekxmpp/plugins/xep_0020/stanza.py | 17 - sleekxmpp/plugins/xep_0027/__init__.py | 15 - sleekxmpp/plugins/xep_0027/gpg.py | 170 -- sleekxmpp/plugins/xep_0027/stanza.py | 53 - sleekxmpp/plugins/xep_0030/__init__.py | 23 - sleekxmpp/plugins/xep_0030/disco.py | 740 -------- sleekxmpp/plugins/xep_0030/stanza/__init__.py | 10 - sleekxmpp/plugins/xep_0030/stanza/info.py | 276 --- sleekxmpp/plugins/xep_0030/stanza/items.py | 152 -- sleekxmpp/plugins/xep_0030/static.py | 430 ----- sleekxmpp/plugins/xep_0033/__init__.py | 20 - sleekxmpp/plugins/xep_0033/addresses.py | 37 - sleekxmpp/plugins/xep_0033/stanza.py | 131 -- sleekxmpp/plugins/xep_0045.py | 402 ----- sleekxmpp/plugins/xep_0047/__init__.py | 21 - sleekxmpp/plugins/xep_0047/ibb.py | 215 --- sleekxmpp/plugins/xep_0047/stanza.py | 67 - sleekxmpp/plugins/xep_0047/stream.py | 148 -- sleekxmpp/plugins/xep_0048/__init__.py | 15 - sleekxmpp/plugins/xep_0048/bookmarks.py | 76 - sleekxmpp/plugins/xep_0048/stanza.py | 65 - sleekxmpp/plugins/xep_0049/__init__.py | 15 - sleekxmpp/plugins/xep_0049/private_storage.py | 53 - sleekxmpp/plugins/xep_0049/stanza.py | 17 - sleekxmpp/plugins/xep_0050/__init__.py | 19 - sleekxmpp/plugins/xep_0050/adhoc.py | 688 -------- sleekxmpp/plugins/xep_0050/stanza.py | 185 -- sleekxmpp/plugins/xep_0054/__init__.py | 15 - sleekxmpp/plugins/xep_0054/stanza.py | 561 ------ sleekxmpp/plugins/xep_0054/vcard_temp.py | 146 -- sleekxmpp/plugins/xep_0059/__init__.py | 18 - sleekxmpp/plugins/xep_0059/rsm.py | 145 -- sleekxmpp/plugins/xep_0059/stanza.py | 108 -- sleekxmpp/plugins/xep_0060/__init__.py | 19 - sleekxmpp/plugins/xep_0060/pubsub.py | 577 ------- sleekxmpp/plugins/xep_0060/stanza/__init__.py | 12 - sleekxmpp/plugins/xep_0060/stanza/base.py | 29 - sleekxmpp/plugins/xep_0060/stanza/pubsub.py | 272 --- sleekxmpp/plugins/xep_0060/stanza/pubsub_errors.py | 86 - sleekxmpp/plugins/xep_0060/stanza/pubsub_event.py | 151 -- sleekxmpp/plugins/xep_0060/stanza/pubsub_owner.py | 134 -- sleekxmpp/plugins/xep_0065/__init__.py | 7 - sleekxmpp/plugins/xep_0065/proxy.py | 292 ---- sleekxmpp/plugins/xep_0065/stanza.py | 47 - sleekxmpp/plugins/xep_0066/__init__.py | 20 - sleekxmpp/plugins/xep_0066/oob.py | 158 -- sleekxmpp/plugins/xep_0066/stanza.py | 33 - sleekxmpp/plugins/xep_0071/__init__.py | 15 - sleekxmpp/plugins/xep_0071/stanza.py | 81 - sleekxmpp/plugins/xep_0071/xhtml_im.py | 30 - sleekxmpp/plugins/xep_0077/__init__.py | 19 - sleekxmpp/plugins/xep_0077/register.py | 115 -- sleekxmpp/plugins/xep_0077/stanza.py | 73 - sleekxmpp/plugins/xep_0078/__init__.py | 20 - sleekxmpp/plugins/xep_0078/legacyauth.py | 147 -- sleekxmpp/plugins/xep_0078/stanza.py | 41 - sleekxmpp/plugins/xep_0079/__init__.py | 18 - sleekxmpp/plugins/xep_0079/amp.py | 79 - sleekxmpp/plugins/xep_0079/stanza.py | 96 -- sleekxmpp/plugins/xep_0080/__init__.py | 15 - sleekxmpp/plugins/xep_0080/geoloc.py | 125 -- sleekxmpp/plugins/xep_0080/stanza.py | 266 --- sleekxmpp/plugins/xep_0082.py | 228 --- sleekxmpp/plugins/xep_0084/__init__.py | 16 - sleekxmpp/plugins/xep_0084/avatar.py | 111 -- sleekxmpp/plugins/xep_0084/stanza.py | 78 - sleekxmpp/plugins/xep_0085/__init__.py | 19 - sleekxmpp/plugins/xep_0085/chat_states.py | 56 - sleekxmpp/plugins/xep_0085/stanza.py | 94 - sleekxmpp/plugins/xep_0086/__init__.py | 19 - sleekxmpp/plugins/xep_0086/legacy_error.py | 46 - sleekxmpp/plugins/xep_0086/stanza.py | 91 - sleekxmpp/plugins/xep_0091/__init__.py | 16 - sleekxmpp/plugins/xep_0091/legacy_delay.py | 29 - sleekxmpp/plugins/xep_0091/stanza.py | 47 - sleekxmpp/plugins/xep_0092/__init__.py | 20 - sleekxmpp/plugins/xep_0092/stanza.py | 42 - sleekxmpp/plugins/xep_0092/version.py | 85 - sleekxmpp/plugins/xep_0095/__init__.py | 16 - sleekxmpp/plugins/xep_0095/stanza.py | 25 - sleekxmpp/plugins/xep_0095/stream_initiation.py | 214 --- sleekxmpp/plugins/xep_0096/__init__.py | 16 - sleekxmpp/plugins/xep_0096/file_transfer.py | 58 - sleekxmpp/plugins/xep_0096/stanza.py | 48 - sleekxmpp/plugins/xep_0106.py | 26 - sleekxmpp/plugins/xep_0107/__init__.py | 16 - sleekxmpp/plugins/xep_0107/stanza.py | 55 - sleekxmpp/plugins/xep_0107/user_mood.py | 93 - sleekxmpp/plugins/xep_0108/__init__.py | 16 - sleekxmpp/plugins/xep_0108/stanza.py | 83 - sleekxmpp/plugins/xep_0108/user_activity.py | 88 - sleekxmpp/plugins/xep_0115/__init__.py | 20 - sleekxmpp/plugins/xep_0115/caps.py | 345 ---- sleekxmpp/plugins/xep_0115/stanza.py | 19 - sleekxmpp/plugins/xep_0115/static.py | 146 -- sleekxmpp/plugins/xep_0118/__init__.py | 16 - sleekxmpp/plugins/xep_0118/stanza.py | 25 - sleekxmpp/plugins/xep_0118/user_tune.py | 96 -- sleekxmpp/plugins/xep_0128/__init__.py | 19 - sleekxmpp/plugins/xep_0128/extended_disco.py | 99 -- sleekxmpp/plugins/xep_0128/static.py | 73 - sleekxmpp/plugins/xep_0131/__init__.py | 16 - sleekxmpp/plugins/xep_0131/headers.py | 41 - sleekxmpp/plugins/xep_0131/stanza.py | 51 - sleekxmpp/plugins/xep_0133.py | 54 - sleekxmpp/plugins/xep_0152/__init__.py | 16 - sleekxmpp/plugins/xep_0152/reachability.py | 93 - sleekxmpp/plugins/xep_0152/stanza.py | 29 - sleekxmpp/plugins/xep_0153/__init__.py | 15 - sleekxmpp/plugins/xep_0153/stanza.py | 29 - sleekxmpp/plugins/xep_0153/vcard_avatar.py | 152 -- sleekxmpp/plugins/xep_0163.py | 123 -- sleekxmpp/plugins/xep_0172/__init__.py | 16 - sleekxmpp/plugins/xep_0172/stanza.py | 67 - sleekxmpp/plugins/xep_0172/user_nick.py | 92 - sleekxmpp/plugins/xep_0184/__init__.py | 19 - sleekxmpp/plugins/xep_0184/receipt.py | 131 -- sleekxmpp/plugins/xep_0184/stanza.py | 72 - sleekxmpp/plugins/xep_0186/__init__.py | 16 - sleekxmpp/plugins/xep_0186/invisible_command.py | 44 - sleekxmpp/plugins/xep_0186/stanza.py | 23 - sleekxmpp/plugins/xep_0191/__init__.py | 15 - sleekxmpp/plugins/xep_0191/blocking.py | 83 - sleekxmpp/plugins/xep_0191/stanza.py | 50 - sleekxmpp/plugins/xep_0196/__init__.py | 16 - sleekxmpp/plugins/xep_0196/stanza.py | 20 - sleekxmpp/plugins/xep_0196/user_gaming.py | 97 -- sleekxmpp/plugins/xep_0198/__init__.py | 20 - sleekxmpp/plugins/xep_0198/stanza.py | 150 -- sleekxmpp/plugins/xep_0198/stream_management.py | 314 ---- sleekxmpp/plugins/xep_0199/__init__.py | 20 - sleekxmpp/plugins/xep_0199/ping.py | 186 -- sleekxmpp/plugins/xep_0199/stanza.py | 36 - sleekxmpp/plugins/xep_0202/__init__.py | 20 - sleekxmpp/plugins/xep_0202/stanza.py | 127 -- sleekxmpp/plugins/xep_0202/time.py | 98 -- sleekxmpp/plugins/xep_0203/__init__.py | 19 - sleekxmpp/plugins/xep_0203/delay.py | 37 - sleekxmpp/plugins/xep_0203/stanza.py | 46 - sleekxmpp/plugins/xep_0221/__init__.py | 16 - sleekxmpp/plugins/xep_0221/media.py | 27 - sleekxmpp/plugins/xep_0221/stanza.py | 42 - sleekxmpp/plugins/xep_0222.py | 127 -- sleekxmpp/plugins/xep_0223.py | 127 -- sleekxmpp/plugins/xep_0224/__init__.py | 20 - sleekxmpp/plugins/xep_0224/attention.py | 75 - sleekxmpp/plugins/xep_0224/stanza.py | 40 - sleekxmpp/plugins/xep_0231/__init__.py | 16 - sleekxmpp/plugins/xep_0231/bob.py | 140 -- sleekxmpp/plugins/xep_0231/stanza.py | 36 - sleekxmpp/plugins/xep_0235/__init__.py | 16 - sleekxmpp/plugins/xep_0235/oauth.py | 32 - sleekxmpp/plugins/xep_0235/stanza.py | 80 - sleekxmpp/plugins/xep_0242.py | 21 - sleekxmpp/plugins/xep_0249/__init__.py | 19 - sleekxmpp/plugins/xep_0249/invite.py | 83 - sleekxmpp/plugins/xep_0249/stanza.py | 39 - sleekxmpp/plugins/xep_0256.py | 73 - sleekxmpp/plugins/xep_0257/__init__.py | 17 - .../plugins/xep_0257/client_cert_management.py | 65 - sleekxmpp/plugins/xep_0257/stanza.py | 87 - sleekxmpp/plugins/xep_0258/__init__.py | 18 - sleekxmpp/plugins/xep_0258/security_labels.py | 44 - sleekxmpp/plugins/xep_0258/stanza.py | 141 -- sleekxmpp/plugins/xep_0270.py | 20 - sleekxmpp/plugins/xep_0279/__init__.py | 16 - sleekxmpp/plugins/xep_0279/ipcheck.py | 39 - sleekxmpp/plugins/xep_0279/stanza.py | 30 - sleekxmpp/plugins/xep_0280/__init__.py | 17 - sleekxmpp/plugins/xep_0280/carbons.py | 81 - sleekxmpp/plugins/xep_0280/stanza.py | 64 - sleekxmpp/plugins/xep_0297/__init__.py | 16 - sleekxmpp/plugins/xep_0297/forwarded.py | 64 - sleekxmpp/plugins/xep_0297/stanza.py | 36 - sleekxmpp/plugins/xep_0302.py | 21 - sleekxmpp/plugins/xep_0308/__init__.py | 15 - sleekxmpp/plugins/xep_0308/correction.py | 52 - sleekxmpp/plugins/xep_0308/stanza.py | 16 - sleekxmpp/plugins/xep_0313/__init__.py | 15 - sleekxmpp/plugins/xep_0313/mam.py | 94 - sleekxmpp/plugins/xep_0313/stanza.py | 139 -- sleekxmpp/plugins/xep_0319/__init__.py | 16 - sleekxmpp/plugins/xep_0319/idle.py | 75 - sleekxmpp/plugins/xep_0319/stanza.py | 28 - sleekxmpp/plugins/xep_0323/__init__.py | 18 - sleekxmpp/plugins/xep_0323/device.py | 255 --- sleekxmpp/plugins/xep_0323/sensordata.py | 723 -------- sleekxmpp/plugins/xep_0323/stanza/__init__.py | 12 - sleekxmpp/plugins/xep_0323/stanza/base.py | 13 - sleekxmpp/plugins/xep_0323/stanza/sensordata.py | 792 --------- sleekxmpp/plugins/xep_0323/timerreset.py | 64 - sleekxmpp/plugins/xep_0325/__init__.py | 18 - sleekxmpp/plugins/xep_0325/control.py | 574 ------- sleekxmpp/plugins/xep_0325/device.py | 125 -- sleekxmpp/plugins/xep_0325/stanza/__init__.py | 12 - sleekxmpp/plugins/xep_0325/stanza/base.py | 13 - sleekxmpp/plugins/xep_0325/stanza/control.py | 526 ------ sleekxmpp/roster/__init__.py | 11 - sleekxmpp/roster/item.py | 497 ------ sleekxmpp/roster/multi.py | 224 --- sleekxmpp/roster/single.py | 337 ---- sleekxmpp/stanza/__init__.py | 15 - sleekxmpp/stanza/atom.py | 26 - sleekxmpp/stanza/error.py | 174 -- sleekxmpp/stanza/htmlim.py | 21 - sleekxmpp/stanza/iq.py | 281 --- sleekxmpp/stanza/message.py | 199 --- sleekxmpp/stanza/nick.py | 23 - sleekxmpp/stanza/presence.py | 191 --- sleekxmpp/stanza/rootstanza.py | 86 - sleekxmpp/stanza/roster.py | 158 -- sleekxmpp/stanza/stream_error.py | 83 - sleekxmpp/stanza/stream_features.py | 57 - sleekxmpp/test/__init__.py | 11 - sleekxmpp/test/livesocket.py | 172 -- sleekxmpp/test/mocksocket.py | 153 -- sleekxmpp/test/sleektest.py | 772 --------- sleekxmpp/thirdparty/__init__.py | 12 - sleekxmpp/thirdparty/gnupg.py | 1017 ----------- sleekxmpp/thirdparty/mini_dateutil.py | 273 --- sleekxmpp/thirdparty/ordereddict.py | 127 -- sleekxmpp/thirdparty/socks.py | 378 ---- sleekxmpp/thirdparty/statemachine.py | 286 ---- sleekxmpp/util/__init__.py | 43 - sleekxmpp/util/misc_ops.py | 165 -- sleekxmpp/util/sasl/__init__.py | 17 - sleekxmpp/util/sasl/client.py | 174 -- sleekxmpp/util/sasl/mechanisms.py | 551 ------ sleekxmpp/util/stringprep_profiles.py | 151 -- sleekxmpp/version.py | 13 - sleekxmpp/xmlstream/__init__.py | 19 - sleekxmpp/xmlstream/cert.py | 184 -- sleekxmpp/xmlstream/filesocket.py | 54 - sleekxmpp/xmlstream/handler/__init__.py | 15 - sleekxmpp/xmlstream/handler/base.py | 84 - sleekxmpp/xmlstream/handler/callback.py | 79 - sleekxmpp/xmlstream/handler/collector.py | 66 - sleekxmpp/xmlstream/handler/waiter.py | 83 - sleekxmpp/xmlstream/handler/xmlcallback.py | 36 - sleekxmpp/xmlstream/handler/xmlwaiter.py | 33 - sleekxmpp/xmlstream/jid.py | 5 - sleekxmpp/xmlstream/matcher/__init__.py | 17 - sleekxmpp/xmlstream/matcher/base.py | 31 - sleekxmpp/xmlstream/matcher/id.py | 29 - sleekxmpp/xmlstream/matcher/idsender.py | 47 - sleekxmpp/xmlstream/matcher/many.py | 40 - sleekxmpp/xmlstream/matcher/stanzapath.py | 43 - sleekxmpp/xmlstream/matcher/xmlmask.py | 117 -- sleekxmpp/xmlstream/matcher/xpath.py | 59 - sleekxmpp/xmlstream/resolver.py | 333 ---- sleekxmpp/xmlstream/scheduler.py | 250 --- sleekxmpp/xmlstream/stanzabase.py | 1644 ------------------ sleekxmpp/xmlstream/tostring.py | 172 -- sleekxmpp/xmlstream/xmlstream.py | 1808 -------------------- slixmpp/__init__.py | 30 + slixmpp/api.py | 200 +++ slixmpp/basexmpp.py | 832 +++++++++ slixmpp/clientxmpp.py | 333 ++++ slixmpp/componentxmpp.py | 159 ++ slixmpp/exceptions.py | 91 + slixmpp/features/__init__.py | 16 + slixmpp/features/feature_bind/__init__.py | 19 + slixmpp/features/feature_bind/bind.py | 65 + slixmpp/features/feature_bind/stanza.py | 21 + slixmpp/features/feature_mechanisms/__init__.py | 22 + slixmpp/features/feature_mechanisms/mechanisms.py | 244 +++ .../features/feature_mechanisms/stanza/__init__.py | 16 + .../features/feature_mechanisms/stanza/abort.py | 24 + slixmpp/features/feature_mechanisms/stanza/auth.py | 49 + .../feature_mechanisms/stanza/challenge.py | 39 + .../features/feature_mechanisms/stanza/failure.py | 76 + .../feature_mechanisms/stanza/mechanisms.py | 53 + .../features/feature_mechanisms/stanza/response.py | 39 + .../features/feature_mechanisms/stanza/success.py | 38 + slixmpp/features/feature_preapproval/__init__.py | 15 + .../features/feature_preapproval/preapproval.py | 42 + slixmpp/features/feature_preapproval/stanza.py | 17 + slixmpp/features/feature_rosterver/__init__.py | 19 + slixmpp/features/feature_rosterver/rosterver.py | 42 + slixmpp/features/feature_rosterver/stanza.py | 17 + slixmpp/features/feature_session/__init__.py | 19 + slixmpp/features/feature_session/session.py | 54 + slixmpp/features/feature_session/stanza.py | 20 + slixmpp/features/feature_starttls/__init__.py | 19 + slixmpp/features/feature_starttls/stanza.py | 45 + slixmpp/features/feature_starttls/starttls.py | 66 + slixmpp/jid.py | 638 +++++++ slixmpp/plugins/__init__.py | 86 + slixmpp/plugins/base.py | 360 ++++ slixmpp/plugins/gmail_notify.py | 149 ++ slixmpp/plugins/google/__init__.py | 47 + slixmpp/plugins/google/auth/__init__.py | 10 + slixmpp/plugins/google/auth/auth.py | 52 + slixmpp/plugins/google/auth/stanza.py | 49 + slixmpp/plugins/google/gmail/__init__.py | 10 + slixmpp/plugins/google/gmail/notifications.py | 96 ++ slixmpp/plugins/google/gmail/stanza.py | 101 ++ slixmpp/plugins/google/nosave/__init__.py | 10 + slixmpp/plugins/google/nosave/nosave.py | 83 + slixmpp/plugins/google/nosave/stanza.py | 59 + slixmpp/plugins/google/settings/__init__.py | 10 + slixmpp/plugins/google/settings/settings.py | 65 + slixmpp/plugins/google/settings/stanza.py | 110 ++ slixmpp/plugins/xep_0004/__init__.py | 22 + slixmpp/plugins/xep_0004/dataforms.py | 57 + slixmpp/plugins/xep_0004/stanza/__init__.py | 10 + slixmpp/plugins/xep_0004/stanza/field.py | 183 ++ slixmpp/plugins/xep_0004/stanza/form.py | 257 +++ slixmpp/plugins/xep_0009/__init__.py | 20 + slixmpp/plugins/xep_0009/binding.py | 173 ++ slixmpp/plugins/xep_0009/remote.py | 742 ++++++++ slixmpp/plugins/xep_0009/rpc.py | 218 +++ slixmpp/plugins/xep_0009/stanza/RPC.py | 64 + slixmpp/plugins/xep_0009/stanza/__init__.py | 9 + slixmpp/plugins/xep_0012/__init__.py | 19 + slixmpp/plugins/xep_0012/last_activity.py | 157 ++ slixmpp/plugins/xep_0012/stanza.py | 32 + slixmpp/plugins/xep_0013/__init__.py | 15 + slixmpp/plugins/xep_0013/offline.py | 134 ++ slixmpp/plugins/xep_0013/stanza.py | 53 + slixmpp/plugins/xep_0016/__init__.py | 16 + slixmpp/plugins/xep_0016/privacy.py | 110 ++ slixmpp/plugins/xep_0016/stanza.py | 103 ++ slixmpp/plugins/xep_0020/__init__.py | 16 + slixmpp/plugins/xep_0020/feature_negotiation.py | 36 + slixmpp/plugins/xep_0020/stanza.py | 17 + slixmpp/plugins/xep_0027/__init__.py | 15 + slixmpp/plugins/xep_0027/gpg.py | 170 ++ slixmpp/plugins/xep_0027/stanza.py | 53 + slixmpp/plugins/xep_0030/__init__.py | 23 + slixmpp/plugins/xep_0030/disco.py | 740 ++++++++ slixmpp/plugins/xep_0030/stanza/__init__.py | 10 + slixmpp/plugins/xep_0030/stanza/info.py | 276 +++ slixmpp/plugins/xep_0030/stanza/items.py | 152 ++ slixmpp/plugins/xep_0030/static.py | 430 +++++ slixmpp/plugins/xep_0033/__init__.py | 20 + slixmpp/plugins/xep_0033/addresses.py | 37 + slixmpp/plugins/xep_0033/stanza.py | 131 ++ slixmpp/plugins/xep_0045.py | 402 +++++ slixmpp/plugins/xep_0047/__init__.py | 21 + slixmpp/plugins/xep_0047/ibb.py | 215 +++ slixmpp/plugins/xep_0047/stanza.py | 67 + slixmpp/plugins/xep_0047/stream.py | 148 ++ slixmpp/plugins/xep_0048/__init__.py | 15 + slixmpp/plugins/xep_0048/bookmarks.py | 76 + slixmpp/plugins/xep_0048/stanza.py | 65 + slixmpp/plugins/xep_0049/__init__.py | 15 + slixmpp/plugins/xep_0049/private_storage.py | 53 + slixmpp/plugins/xep_0049/stanza.py | 17 + slixmpp/plugins/xep_0050/__init__.py | 19 + slixmpp/plugins/xep_0050/adhoc.py | 688 ++++++++ slixmpp/plugins/xep_0050/stanza.py | 185 ++ slixmpp/plugins/xep_0054/__init__.py | 15 + slixmpp/plugins/xep_0054/stanza.py | 561 ++++++ slixmpp/plugins/xep_0054/vcard_temp.py | 146 ++ slixmpp/plugins/xep_0059/__init__.py | 18 + slixmpp/plugins/xep_0059/rsm.py | 145 ++ slixmpp/plugins/xep_0059/stanza.py | 108 ++ slixmpp/plugins/xep_0060/__init__.py | 19 + slixmpp/plugins/xep_0060/pubsub.py | 577 +++++++ slixmpp/plugins/xep_0060/stanza/__init__.py | 12 + slixmpp/plugins/xep_0060/stanza/base.py | 29 + slixmpp/plugins/xep_0060/stanza/pubsub.py | 272 +++ slixmpp/plugins/xep_0060/stanza/pubsub_errors.py | 86 + slixmpp/plugins/xep_0060/stanza/pubsub_event.py | 151 ++ slixmpp/plugins/xep_0060/stanza/pubsub_owner.py | 134 ++ slixmpp/plugins/xep_0065/__init__.py | 7 + slixmpp/plugins/xep_0065/proxy.py | 292 ++++ slixmpp/plugins/xep_0065/stanza.py | 47 + slixmpp/plugins/xep_0066/__init__.py | 20 + slixmpp/plugins/xep_0066/oob.py | 158 ++ slixmpp/plugins/xep_0066/stanza.py | 33 + slixmpp/plugins/xep_0071/__init__.py | 15 + slixmpp/plugins/xep_0071/stanza.py | 81 + slixmpp/plugins/xep_0071/xhtml_im.py | 30 + slixmpp/plugins/xep_0077/__init__.py | 19 + slixmpp/plugins/xep_0077/register.py | 115 ++ slixmpp/plugins/xep_0077/stanza.py | 73 + slixmpp/plugins/xep_0078/__init__.py | 20 + slixmpp/plugins/xep_0078/legacyauth.py | 147 ++ slixmpp/plugins/xep_0078/stanza.py | 41 + slixmpp/plugins/xep_0079/__init__.py | 18 + slixmpp/plugins/xep_0079/amp.py | 79 + slixmpp/plugins/xep_0079/stanza.py | 96 ++ slixmpp/plugins/xep_0080/__init__.py | 15 + slixmpp/plugins/xep_0080/geoloc.py | 125 ++ slixmpp/plugins/xep_0080/stanza.py | 266 +++ slixmpp/plugins/xep_0082.py | 228 +++ slixmpp/plugins/xep_0084/__init__.py | 16 + slixmpp/plugins/xep_0084/avatar.py | 111 ++ slixmpp/plugins/xep_0084/stanza.py | 78 + slixmpp/plugins/xep_0085/__init__.py | 19 + slixmpp/plugins/xep_0085/chat_states.py | 56 + slixmpp/plugins/xep_0085/stanza.py | 94 + slixmpp/plugins/xep_0086/__init__.py | 19 + slixmpp/plugins/xep_0086/legacy_error.py | 46 + slixmpp/plugins/xep_0086/stanza.py | 91 + slixmpp/plugins/xep_0091/__init__.py | 16 + slixmpp/plugins/xep_0091/legacy_delay.py | 29 + slixmpp/plugins/xep_0091/stanza.py | 47 + slixmpp/plugins/xep_0092/__init__.py | 20 + slixmpp/plugins/xep_0092/stanza.py | 42 + slixmpp/plugins/xep_0092/version.py | 85 + slixmpp/plugins/xep_0095/__init__.py | 16 + slixmpp/plugins/xep_0095/stanza.py | 25 + slixmpp/plugins/xep_0095/stream_initiation.py | 214 +++ slixmpp/plugins/xep_0096/__init__.py | 16 + slixmpp/plugins/xep_0096/file_transfer.py | 58 + slixmpp/plugins/xep_0096/stanza.py | 48 + slixmpp/plugins/xep_0106.py | 26 + slixmpp/plugins/xep_0107/__init__.py | 16 + slixmpp/plugins/xep_0107/stanza.py | 55 + slixmpp/plugins/xep_0107/user_mood.py | 93 + slixmpp/plugins/xep_0108/__init__.py | 16 + slixmpp/plugins/xep_0108/stanza.py | 83 + slixmpp/plugins/xep_0108/user_activity.py | 88 + slixmpp/plugins/xep_0115/__init__.py | 20 + slixmpp/plugins/xep_0115/caps.py | 345 ++++ slixmpp/plugins/xep_0115/stanza.py | 19 + slixmpp/plugins/xep_0115/static.py | 146 ++ slixmpp/plugins/xep_0118/__init__.py | 16 + slixmpp/plugins/xep_0118/stanza.py | 25 + slixmpp/plugins/xep_0118/user_tune.py | 96 ++ slixmpp/plugins/xep_0128/__init__.py | 19 + slixmpp/plugins/xep_0128/extended_disco.py | 99 ++ slixmpp/plugins/xep_0128/static.py | 73 + slixmpp/plugins/xep_0131/__init__.py | 16 + slixmpp/plugins/xep_0131/headers.py | 41 + slixmpp/plugins/xep_0131/stanza.py | 51 + slixmpp/plugins/xep_0133.py | 54 + slixmpp/plugins/xep_0152/__init__.py | 16 + slixmpp/plugins/xep_0152/reachability.py | 93 + slixmpp/plugins/xep_0152/stanza.py | 29 + slixmpp/plugins/xep_0153/__init__.py | 15 + slixmpp/plugins/xep_0153/stanza.py | 29 + slixmpp/plugins/xep_0153/vcard_avatar.py | 152 ++ slixmpp/plugins/xep_0163.py | 123 ++ slixmpp/plugins/xep_0172/__init__.py | 16 + slixmpp/plugins/xep_0172/stanza.py | 67 + slixmpp/plugins/xep_0172/user_nick.py | 92 + slixmpp/plugins/xep_0184/__init__.py | 19 + slixmpp/plugins/xep_0184/receipt.py | 131 ++ slixmpp/plugins/xep_0184/stanza.py | 72 + slixmpp/plugins/xep_0186/__init__.py | 16 + slixmpp/plugins/xep_0186/invisible_command.py | 44 + slixmpp/plugins/xep_0186/stanza.py | 23 + slixmpp/plugins/xep_0191/__init__.py | 15 + slixmpp/plugins/xep_0191/blocking.py | 83 + slixmpp/plugins/xep_0191/stanza.py | 50 + slixmpp/plugins/xep_0196/__init__.py | 16 + slixmpp/plugins/xep_0196/stanza.py | 20 + slixmpp/plugins/xep_0196/user_gaming.py | 97 ++ slixmpp/plugins/xep_0198/__init__.py | 20 + slixmpp/plugins/xep_0198/stanza.py | 150 ++ slixmpp/plugins/xep_0198/stream_management.py | 314 ++++ slixmpp/plugins/xep_0199/__init__.py | 20 + slixmpp/plugins/xep_0199/ping.py | 186 ++ slixmpp/plugins/xep_0199/stanza.py | 36 + slixmpp/plugins/xep_0202/__init__.py | 20 + slixmpp/plugins/xep_0202/stanza.py | 127 ++ slixmpp/plugins/xep_0202/time.py | 98 ++ slixmpp/plugins/xep_0203/__init__.py | 19 + slixmpp/plugins/xep_0203/delay.py | 37 + slixmpp/plugins/xep_0203/stanza.py | 46 + slixmpp/plugins/xep_0221/__init__.py | 16 + slixmpp/plugins/xep_0221/media.py | 27 + slixmpp/plugins/xep_0221/stanza.py | 42 + slixmpp/plugins/xep_0222.py | 127 ++ slixmpp/plugins/xep_0223.py | 127 ++ slixmpp/plugins/xep_0224/__init__.py | 20 + slixmpp/plugins/xep_0224/attention.py | 75 + slixmpp/plugins/xep_0224/stanza.py | 40 + slixmpp/plugins/xep_0231/__init__.py | 16 + slixmpp/plugins/xep_0231/bob.py | 140 ++ slixmpp/plugins/xep_0231/stanza.py | 36 + slixmpp/plugins/xep_0235/__init__.py | 16 + slixmpp/plugins/xep_0235/oauth.py | 32 + slixmpp/plugins/xep_0235/stanza.py | 80 + slixmpp/plugins/xep_0242.py | 21 + slixmpp/plugins/xep_0249/__init__.py | 19 + slixmpp/plugins/xep_0249/invite.py | 83 + slixmpp/plugins/xep_0249/stanza.py | 39 + slixmpp/plugins/xep_0256.py | 73 + slixmpp/plugins/xep_0257/__init__.py | 17 + slixmpp/plugins/xep_0257/client_cert_management.py | 65 + slixmpp/plugins/xep_0257/stanza.py | 87 + slixmpp/plugins/xep_0258/__init__.py | 18 + slixmpp/plugins/xep_0258/security_labels.py | 44 + slixmpp/plugins/xep_0258/stanza.py | 141 ++ slixmpp/plugins/xep_0270.py | 20 + slixmpp/plugins/xep_0279/__init__.py | 16 + slixmpp/plugins/xep_0279/ipcheck.py | 39 + slixmpp/plugins/xep_0279/stanza.py | 30 + slixmpp/plugins/xep_0280/__init__.py | 17 + slixmpp/plugins/xep_0280/carbons.py | 81 + slixmpp/plugins/xep_0280/stanza.py | 64 + slixmpp/plugins/xep_0297/__init__.py | 16 + slixmpp/plugins/xep_0297/forwarded.py | 64 + slixmpp/plugins/xep_0297/stanza.py | 36 + slixmpp/plugins/xep_0302.py | 21 + slixmpp/plugins/xep_0308/__init__.py | 15 + slixmpp/plugins/xep_0308/correction.py | 52 + slixmpp/plugins/xep_0308/stanza.py | 16 + slixmpp/plugins/xep_0313/__init__.py | 15 + slixmpp/plugins/xep_0313/mam.py | 94 + slixmpp/plugins/xep_0313/stanza.py | 139 ++ slixmpp/plugins/xep_0319/__init__.py | 16 + slixmpp/plugins/xep_0319/idle.py | 75 + slixmpp/plugins/xep_0319/stanza.py | 28 + slixmpp/plugins/xep_0323/__init__.py | 18 + slixmpp/plugins/xep_0323/device.py | 255 +++ slixmpp/plugins/xep_0323/sensordata.py | 723 ++++++++ slixmpp/plugins/xep_0323/stanza/__init__.py | 12 + slixmpp/plugins/xep_0323/stanza/base.py | 13 + slixmpp/plugins/xep_0323/stanza/sensordata.py | 792 +++++++++ slixmpp/plugins/xep_0323/timerreset.py | 64 + slixmpp/plugins/xep_0325/__init__.py | 18 + slixmpp/plugins/xep_0325/control.py | 574 +++++++ slixmpp/plugins/xep_0325/device.py | 125 ++ slixmpp/plugins/xep_0325/stanza/__init__.py | 12 + slixmpp/plugins/xep_0325/stanza/base.py | 13 + slixmpp/plugins/xep_0325/stanza/control.py | 526 ++++++ slixmpp/roster/__init__.py | 11 + slixmpp/roster/item.py | 497 ++++++ slixmpp/roster/multi.py | 224 +++ slixmpp/roster/single.py | 337 ++++ slixmpp/stanza/__init__.py | 15 + slixmpp/stanza/atom.py | 26 + slixmpp/stanza/error.py | 174 ++ slixmpp/stanza/htmlim.py | 21 + slixmpp/stanza/iq.py | 281 +++ slixmpp/stanza/message.py | 199 +++ slixmpp/stanza/nick.py | 23 + slixmpp/stanza/presence.py | 191 +++ slixmpp/stanza/rootstanza.py | 86 + slixmpp/stanza/roster.py | 158 ++ slixmpp/stanza/stream_error.py | 83 + slixmpp/stanza/stream_features.py | 57 + slixmpp/test/__init__.py | 11 + slixmpp/test/livesocket.py | 172 ++ slixmpp/test/mocksocket.py | 153 ++ slixmpp/test/slixtest.py | 772 +++++++++ slixmpp/thirdparty/__init__.py | 12 + slixmpp/thirdparty/gnupg.py | 1017 +++++++++++ slixmpp/thirdparty/mini_dateutil.py | 273 +++ slixmpp/thirdparty/ordereddict.py | 127 ++ slixmpp/thirdparty/socks.py | 378 ++++ slixmpp/thirdparty/statemachine.py | 286 ++++ slixmpp/util/__init__.py | 43 + slixmpp/util/misc_ops.py | 165 ++ slixmpp/util/sasl/__init__.py | 17 + slixmpp/util/sasl/client.py | 174 ++ slixmpp/util/sasl/mechanisms.py | 551 ++++++ slixmpp/util/stringprep_profiles.py | 151 ++ slixmpp/version.py | 13 + slixmpp/xmlstream/__init__.py | 19 + slixmpp/xmlstream/cert.py | 184 ++ slixmpp/xmlstream/filesocket.py | 54 + slixmpp/xmlstream/handler/__init__.py | 15 + slixmpp/xmlstream/handler/base.py | 84 + slixmpp/xmlstream/handler/callback.py | 79 + slixmpp/xmlstream/handler/collector.py | 66 + slixmpp/xmlstream/handler/waiter.py | 83 + slixmpp/xmlstream/handler/xmlcallback.py | 36 + slixmpp/xmlstream/handler/xmlwaiter.py | 33 + slixmpp/xmlstream/jid.py | 5 + slixmpp/xmlstream/matcher/__init__.py | 17 + slixmpp/xmlstream/matcher/base.py | 31 + slixmpp/xmlstream/matcher/id.py | 29 + slixmpp/xmlstream/matcher/idsender.py | 47 + slixmpp/xmlstream/matcher/many.py | 40 + slixmpp/xmlstream/matcher/stanzapath.py | 43 + slixmpp/xmlstream/matcher/xmlmask.py | 117 ++ slixmpp/xmlstream/matcher/xpath.py | 59 + slixmpp/xmlstream/resolver.py | 333 ++++ slixmpp/xmlstream/scheduler.py | 250 +++ slixmpp/xmlstream/stanzabase.py | 1644 ++++++++++++++++++ slixmpp/xmlstream/tostring.py | 172 ++ slixmpp/xmlstream/xmlstream.py | 1808 ++++++++++++++++++++ tests/live_multiple_streams.py | 8 +- tests/live_test.py | 4 +- tests/test_events.py | 4 +- tests/test_jid.py | 8 +- tests/test_overall.py | 4 +- tests/test_plugins.py | 2 +- tests/test_stanza_base.py | 6 +- tests/test_stanza_element.py | 8 +- tests/test_stanza_error.py | 4 +- tests/test_stanza_gmail.py | 10 +- tests/test_stanza_iq.py | 6 +- tests/test_stanza_message.py | 14 +- tests/test_stanza_presence.py | 8 +- tests/test_stanza_roster.py | 6 +- tests/test_stanza_xep_0004.py | 12 +- tests/test_stanza_xep_0009.py | 18 +- tests/test_stanza_xep_0030.py | 10 +- tests/test_stanza_xep_0033.py | 10 +- tests/test_stanza_xep_0047.py | 14 +- tests/test_stanza_xep_0050.py | 10 +- tests/test_stanza_xep_0059.py | 8 +- tests/test_stanza_xep_0060.py | 22 +- tests/test_stanza_xep_0085.py | 10 +- tests/test_stanza_xep_0184.py | 10 +- tests/test_stanza_xep_0323.py | 6 +- tests/test_stanza_xep_0325.py | 10 +- tests/test_stream.py | 4 +- tests/test_stream_exceptions.py | 20 +- tests/test_stream_filters.py | 6 +- tests/test_stream_handlers.py | 18 +- tests/test_stream_presence.py | 4 +- tests/test_stream_roster.py | 6 +- tests/test_stream_xep_0030.py | 4 +- tests/test_stream_xep_0047.py | 4 +- tests/test_stream_xep_0050.py | 6 +- tests/test_stream_xep_0059.py | 10 +- tests/test_stream_xep_0060.py | 8 +- tests/test_stream_xep_0066.py | 12 +- tests/test_stream_xep_0085.py | 4 +- tests/test_stream_xep_0092.py | 8 +- tests/test_stream_xep_0128.py | 4 +- tests/test_stream_xep_0249.py | 8 +- tests/test_stream_xep_0323.py | 8 +- tests/test_stream_xep_0325.py | 12 +- tests/test_tostring.py | 10 +- tox.ini | 2 +- 756 files changed, 38354 insertions(+), 38411 deletions(-) delete mode 100644 sleekxmpp/__init__.py delete mode 100644 sleekxmpp/api.py delete mode 100644 sleekxmpp/basexmpp.py delete mode 100644 sleekxmpp/clientxmpp.py delete mode 100644 sleekxmpp/componentxmpp.py delete mode 100644 sleekxmpp/exceptions.py delete mode 100644 sleekxmpp/features/__init__.py delete mode 100644 sleekxmpp/features/feature_bind/__init__.py delete mode 100644 sleekxmpp/features/feature_bind/bind.py delete mode 100644 sleekxmpp/features/feature_bind/stanza.py delete mode 100644 sleekxmpp/features/feature_mechanisms/__init__.py delete mode 100644 sleekxmpp/features/feature_mechanisms/mechanisms.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/__init__.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/abort.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/auth.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/challenge.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/failure.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/response.py delete mode 100644 sleekxmpp/features/feature_mechanisms/stanza/success.py delete mode 100644 sleekxmpp/features/feature_preapproval/__init__.py delete mode 100644 sleekxmpp/features/feature_preapproval/preapproval.py delete mode 100644 sleekxmpp/features/feature_preapproval/stanza.py delete mode 100644 sleekxmpp/features/feature_rosterver/__init__.py delete mode 100644 sleekxmpp/features/feature_rosterver/rosterver.py delete mode 100644 sleekxmpp/features/feature_rosterver/stanza.py delete mode 100644 sleekxmpp/features/feature_session/__init__.py delete mode 100644 sleekxmpp/features/feature_session/session.py delete mode 100644 sleekxmpp/features/feature_session/stanza.py delete mode 100644 sleekxmpp/features/feature_starttls/__init__.py delete mode 100644 sleekxmpp/features/feature_starttls/stanza.py delete mode 100644 sleekxmpp/features/feature_starttls/starttls.py delete mode 100644 sleekxmpp/jid.py delete mode 100644 sleekxmpp/plugins/__init__.py delete mode 100644 sleekxmpp/plugins/base.py delete mode 100644 sleekxmpp/plugins/gmail_notify.py delete mode 100644 sleekxmpp/plugins/google/__init__.py delete mode 100644 sleekxmpp/plugins/google/auth/__init__.py delete mode 100644 sleekxmpp/plugins/google/auth/auth.py delete mode 100644 sleekxmpp/plugins/google/auth/stanza.py delete mode 100644 sleekxmpp/plugins/google/gmail/__init__.py delete mode 100644 sleekxmpp/plugins/google/gmail/notifications.py delete mode 100644 sleekxmpp/plugins/google/gmail/stanza.py delete mode 100644 sleekxmpp/plugins/google/nosave/__init__.py delete mode 100644 sleekxmpp/plugins/google/nosave/nosave.py delete mode 100644 sleekxmpp/plugins/google/nosave/stanza.py delete mode 100644 sleekxmpp/plugins/google/settings/__init__.py delete mode 100644 sleekxmpp/plugins/google/settings/settings.py delete mode 100644 sleekxmpp/plugins/google/settings/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0004/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0004/dataforms.py delete mode 100644 sleekxmpp/plugins/xep_0004/stanza/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0004/stanza/field.py delete mode 100644 sleekxmpp/plugins/xep_0004/stanza/form.py delete mode 100644 sleekxmpp/plugins/xep_0009/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0009/binding.py delete mode 100644 sleekxmpp/plugins/xep_0009/remote.py delete mode 100644 sleekxmpp/plugins/xep_0009/rpc.py delete mode 100644 sleekxmpp/plugins/xep_0009/stanza/RPC.py delete mode 100644 sleekxmpp/plugins/xep_0009/stanza/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0012/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0012/last_activity.py delete mode 100644 sleekxmpp/plugins/xep_0012/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0013/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0013/offline.py delete mode 100644 sleekxmpp/plugins/xep_0013/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0016/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0016/privacy.py delete mode 100644 sleekxmpp/plugins/xep_0016/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0020/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0020/feature_negotiation.py delete mode 100644 sleekxmpp/plugins/xep_0020/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0027/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0027/gpg.py delete mode 100644 sleekxmpp/plugins/xep_0027/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0030/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0030/disco.py delete mode 100644 sleekxmpp/plugins/xep_0030/stanza/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0030/stanza/info.py delete mode 100644 sleekxmpp/plugins/xep_0030/stanza/items.py delete mode 100644 sleekxmpp/plugins/xep_0030/static.py delete mode 100644 sleekxmpp/plugins/xep_0033/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0033/addresses.py delete mode 100644 sleekxmpp/plugins/xep_0033/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0045.py delete mode 100644 sleekxmpp/plugins/xep_0047/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0047/ibb.py delete mode 100644 sleekxmpp/plugins/xep_0047/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0047/stream.py delete mode 100644 sleekxmpp/plugins/xep_0048/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0048/bookmarks.py delete mode 100644 sleekxmpp/plugins/xep_0048/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0049/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0049/private_storage.py delete mode 100644 sleekxmpp/plugins/xep_0049/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0050/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0050/adhoc.py delete mode 100644 sleekxmpp/plugins/xep_0050/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0054/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0054/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0054/vcard_temp.py delete mode 100644 sleekxmpp/plugins/xep_0059/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0059/rsm.py delete mode 100644 sleekxmpp/plugins/xep_0059/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0060/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0060/pubsub.py delete mode 100644 sleekxmpp/plugins/xep_0060/stanza/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0060/stanza/base.py delete mode 100644 sleekxmpp/plugins/xep_0060/stanza/pubsub.py delete mode 100644 sleekxmpp/plugins/xep_0060/stanza/pubsub_errors.py delete mode 100644 sleekxmpp/plugins/xep_0060/stanza/pubsub_event.py delete mode 100644 sleekxmpp/plugins/xep_0060/stanza/pubsub_owner.py delete mode 100644 sleekxmpp/plugins/xep_0065/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0065/proxy.py delete mode 100644 sleekxmpp/plugins/xep_0065/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0066/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0066/oob.py delete mode 100644 sleekxmpp/plugins/xep_0066/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0071/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0071/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0071/xhtml_im.py delete mode 100644 sleekxmpp/plugins/xep_0077/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0077/register.py delete mode 100644 sleekxmpp/plugins/xep_0077/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0078/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0078/legacyauth.py delete mode 100644 sleekxmpp/plugins/xep_0078/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0079/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0079/amp.py delete mode 100644 sleekxmpp/plugins/xep_0079/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0080/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0080/geoloc.py delete mode 100644 sleekxmpp/plugins/xep_0080/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0082.py delete mode 100644 sleekxmpp/plugins/xep_0084/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0084/avatar.py delete mode 100644 sleekxmpp/plugins/xep_0084/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0085/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0085/chat_states.py delete mode 100644 sleekxmpp/plugins/xep_0085/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0086/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0086/legacy_error.py delete mode 100644 sleekxmpp/plugins/xep_0086/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0091/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0091/legacy_delay.py delete mode 100644 sleekxmpp/plugins/xep_0091/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0092/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0092/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0092/version.py delete mode 100644 sleekxmpp/plugins/xep_0095/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0095/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0095/stream_initiation.py delete mode 100644 sleekxmpp/plugins/xep_0096/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0096/file_transfer.py delete mode 100644 sleekxmpp/plugins/xep_0096/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0106.py delete mode 100644 sleekxmpp/plugins/xep_0107/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0107/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0107/user_mood.py delete mode 100644 sleekxmpp/plugins/xep_0108/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0108/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0108/user_activity.py delete mode 100644 sleekxmpp/plugins/xep_0115/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0115/caps.py delete mode 100644 sleekxmpp/plugins/xep_0115/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0115/static.py delete mode 100644 sleekxmpp/plugins/xep_0118/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0118/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0118/user_tune.py delete mode 100644 sleekxmpp/plugins/xep_0128/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0128/extended_disco.py delete mode 100644 sleekxmpp/plugins/xep_0128/static.py delete mode 100644 sleekxmpp/plugins/xep_0131/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0131/headers.py delete mode 100644 sleekxmpp/plugins/xep_0131/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0133.py delete mode 100644 sleekxmpp/plugins/xep_0152/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0152/reachability.py delete mode 100644 sleekxmpp/plugins/xep_0152/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0153/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0153/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0153/vcard_avatar.py delete mode 100644 sleekxmpp/plugins/xep_0163.py delete mode 100644 sleekxmpp/plugins/xep_0172/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0172/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0172/user_nick.py delete mode 100644 sleekxmpp/plugins/xep_0184/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0184/receipt.py delete mode 100644 sleekxmpp/plugins/xep_0184/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0186/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0186/invisible_command.py delete mode 100644 sleekxmpp/plugins/xep_0186/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0191/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0191/blocking.py delete mode 100644 sleekxmpp/plugins/xep_0191/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0196/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0196/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0196/user_gaming.py delete mode 100644 sleekxmpp/plugins/xep_0198/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0198/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0198/stream_management.py delete mode 100644 sleekxmpp/plugins/xep_0199/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0199/ping.py delete mode 100644 sleekxmpp/plugins/xep_0199/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0202/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0202/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0202/time.py delete mode 100644 sleekxmpp/plugins/xep_0203/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0203/delay.py delete mode 100644 sleekxmpp/plugins/xep_0203/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0221/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0221/media.py delete mode 100644 sleekxmpp/plugins/xep_0221/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0222.py delete mode 100644 sleekxmpp/plugins/xep_0223.py delete mode 100644 sleekxmpp/plugins/xep_0224/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0224/attention.py delete mode 100644 sleekxmpp/plugins/xep_0224/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0231/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0231/bob.py delete mode 100644 sleekxmpp/plugins/xep_0231/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0235/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0235/oauth.py delete mode 100644 sleekxmpp/plugins/xep_0235/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0242.py delete mode 100644 sleekxmpp/plugins/xep_0249/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0249/invite.py delete mode 100644 sleekxmpp/plugins/xep_0249/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0256.py delete mode 100644 sleekxmpp/plugins/xep_0257/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0257/client_cert_management.py delete mode 100644 sleekxmpp/plugins/xep_0257/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0258/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0258/security_labels.py delete mode 100644 sleekxmpp/plugins/xep_0258/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0270.py delete mode 100644 sleekxmpp/plugins/xep_0279/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0279/ipcheck.py delete mode 100644 sleekxmpp/plugins/xep_0279/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0280/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0280/carbons.py delete mode 100644 sleekxmpp/plugins/xep_0280/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0297/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0297/forwarded.py delete mode 100644 sleekxmpp/plugins/xep_0297/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0302.py delete mode 100644 sleekxmpp/plugins/xep_0308/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0308/correction.py delete mode 100644 sleekxmpp/plugins/xep_0308/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0313/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0313/mam.py delete mode 100644 sleekxmpp/plugins/xep_0313/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0319/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0319/idle.py delete mode 100644 sleekxmpp/plugins/xep_0319/stanza.py delete mode 100644 sleekxmpp/plugins/xep_0323/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0323/device.py delete mode 100644 sleekxmpp/plugins/xep_0323/sensordata.py delete mode 100644 sleekxmpp/plugins/xep_0323/stanza/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0323/stanza/base.py delete mode 100644 sleekxmpp/plugins/xep_0323/stanza/sensordata.py delete mode 100644 sleekxmpp/plugins/xep_0323/timerreset.py delete mode 100644 sleekxmpp/plugins/xep_0325/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0325/control.py delete mode 100644 sleekxmpp/plugins/xep_0325/device.py delete mode 100644 sleekxmpp/plugins/xep_0325/stanza/__init__.py delete mode 100644 sleekxmpp/plugins/xep_0325/stanza/base.py delete mode 100644 sleekxmpp/plugins/xep_0325/stanza/control.py delete mode 100644 sleekxmpp/roster/__init__.py delete mode 100644 sleekxmpp/roster/item.py delete mode 100644 sleekxmpp/roster/multi.py delete mode 100644 sleekxmpp/roster/single.py delete mode 100644 sleekxmpp/stanza/__init__.py delete mode 100644 sleekxmpp/stanza/atom.py delete mode 100644 sleekxmpp/stanza/error.py delete mode 100644 sleekxmpp/stanza/htmlim.py delete mode 100644 sleekxmpp/stanza/iq.py delete mode 100644 sleekxmpp/stanza/message.py delete mode 100644 sleekxmpp/stanza/nick.py delete mode 100644 sleekxmpp/stanza/presence.py delete mode 100644 sleekxmpp/stanza/rootstanza.py delete mode 100644 sleekxmpp/stanza/roster.py delete mode 100644 sleekxmpp/stanza/stream_error.py delete mode 100644 sleekxmpp/stanza/stream_features.py delete mode 100644 sleekxmpp/test/__init__.py delete mode 100644 sleekxmpp/test/livesocket.py delete mode 100644 sleekxmpp/test/mocksocket.py delete mode 100644 sleekxmpp/test/sleektest.py delete mode 100644 sleekxmpp/thirdparty/__init__.py delete mode 100644 sleekxmpp/thirdparty/gnupg.py delete mode 100644 sleekxmpp/thirdparty/mini_dateutil.py delete mode 100644 sleekxmpp/thirdparty/ordereddict.py delete mode 100644 sleekxmpp/thirdparty/socks.py delete mode 100644 sleekxmpp/thirdparty/statemachine.py delete mode 100644 sleekxmpp/util/__init__.py delete mode 100644 sleekxmpp/util/misc_ops.py delete mode 100644 sleekxmpp/util/sasl/__init__.py delete mode 100644 sleekxmpp/util/sasl/client.py delete mode 100644 sleekxmpp/util/sasl/mechanisms.py delete mode 100644 sleekxmpp/util/stringprep_profiles.py delete mode 100644 sleekxmpp/version.py delete mode 100644 sleekxmpp/xmlstream/__init__.py delete mode 100644 sleekxmpp/xmlstream/cert.py delete mode 100644 sleekxmpp/xmlstream/filesocket.py delete mode 100644 sleekxmpp/xmlstream/handler/__init__.py delete mode 100644 sleekxmpp/xmlstream/handler/base.py delete mode 100644 sleekxmpp/xmlstream/handler/callback.py delete mode 100644 sleekxmpp/xmlstream/handler/collector.py delete mode 100644 sleekxmpp/xmlstream/handler/waiter.py delete mode 100644 sleekxmpp/xmlstream/handler/xmlcallback.py delete mode 100644 sleekxmpp/xmlstream/handler/xmlwaiter.py delete mode 100644 sleekxmpp/xmlstream/jid.py delete mode 100644 sleekxmpp/xmlstream/matcher/__init__.py delete mode 100644 sleekxmpp/xmlstream/matcher/base.py delete mode 100644 sleekxmpp/xmlstream/matcher/id.py delete mode 100644 sleekxmpp/xmlstream/matcher/idsender.py delete mode 100644 sleekxmpp/xmlstream/matcher/many.py delete mode 100644 sleekxmpp/xmlstream/matcher/stanzapath.py delete mode 100644 sleekxmpp/xmlstream/matcher/xmlmask.py delete mode 100644 sleekxmpp/xmlstream/matcher/xpath.py delete mode 100644 sleekxmpp/xmlstream/resolver.py delete mode 100644 sleekxmpp/xmlstream/scheduler.py delete mode 100644 sleekxmpp/xmlstream/stanzabase.py delete mode 100644 sleekxmpp/xmlstream/tostring.py delete mode 100644 sleekxmpp/xmlstream/xmlstream.py create mode 100644 slixmpp/__init__.py create mode 100644 slixmpp/api.py create mode 100644 slixmpp/basexmpp.py create mode 100644 slixmpp/clientxmpp.py create mode 100644 slixmpp/componentxmpp.py create mode 100644 slixmpp/exceptions.py create mode 100644 slixmpp/features/__init__.py create mode 100644 slixmpp/features/feature_bind/__init__.py create mode 100644 slixmpp/features/feature_bind/bind.py create mode 100644 slixmpp/features/feature_bind/stanza.py create mode 100644 slixmpp/features/feature_mechanisms/__init__.py create mode 100644 slixmpp/features/feature_mechanisms/mechanisms.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/__init__.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/abort.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/auth.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/challenge.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/failure.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/mechanisms.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/response.py create mode 100644 slixmpp/features/feature_mechanisms/stanza/success.py create mode 100644 slixmpp/features/feature_preapproval/__init__.py create mode 100644 slixmpp/features/feature_preapproval/preapproval.py create mode 100644 slixmpp/features/feature_preapproval/stanza.py create mode 100644 slixmpp/features/feature_rosterver/__init__.py create mode 100644 slixmpp/features/feature_rosterver/rosterver.py create mode 100644 slixmpp/features/feature_rosterver/stanza.py create mode 100644 slixmpp/features/feature_session/__init__.py create mode 100644 slixmpp/features/feature_session/session.py create mode 100644 slixmpp/features/feature_session/stanza.py create mode 100644 slixmpp/features/feature_starttls/__init__.py create mode 100644 slixmpp/features/feature_starttls/stanza.py create mode 100644 slixmpp/features/feature_starttls/starttls.py create mode 100644 slixmpp/jid.py create mode 100644 slixmpp/plugins/__init__.py create mode 100644 slixmpp/plugins/base.py create mode 100644 slixmpp/plugins/gmail_notify.py create mode 100644 slixmpp/plugins/google/__init__.py create mode 100644 slixmpp/plugins/google/auth/__init__.py create mode 100644 slixmpp/plugins/google/auth/auth.py create mode 100644 slixmpp/plugins/google/auth/stanza.py create mode 100644 slixmpp/plugins/google/gmail/__init__.py create mode 100644 slixmpp/plugins/google/gmail/notifications.py create mode 100644 slixmpp/plugins/google/gmail/stanza.py create mode 100644 slixmpp/plugins/google/nosave/__init__.py create mode 100644 slixmpp/plugins/google/nosave/nosave.py create mode 100644 slixmpp/plugins/google/nosave/stanza.py create mode 100644 slixmpp/plugins/google/settings/__init__.py create mode 100644 slixmpp/plugins/google/settings/settings.py create mode 100644 slixmpp/plugins/google/settings/stanza.py create mode 100644 slixmpp/plugins/xep_0004/__init__.py create mode 100644 slixmpp/plugins/xep_0004/dataforms.py create mode 100644 slixmpp/plugins/xep_0004/stanza/__init__.py create mode 100644 slixmpp/plugins/xep_0004/stanza/field.py create mode 100644 slixmpp/plugins/xep_0004/stanza/form.py create mode 100644 slixmpp/plugins/xep_0009/__init__.py create mode 100644 slixmpp/plugins/xep_0009/binding.py create mode 100644 slixmpp/plugins/xep_0009/remote.py create mode 100644 slixmpp/plugins/xep_0009/rpc.py create mode 100644 slixmpp/plugins/xep_0009/stanza/RPC.py create mode 100644 slixmpp/plugins/xep_0009/stanza/__init__.py create mode 100644 slixmpp/plugins/xep_0012/__init__.py create mode 100644 slixmpp/plugins/xep_0012/last_activity.py create mode 100644 slixmpp/plugins/xep_0012/stanza.py create mode 100644 slixmpp/plugins/xep_0013/__init__.py create mode 100644 slixmpp/plugins/xep_0013/offline.py create mode 100644 slixmpp/plugins/xep_0013/stanza.py create mode 100644 slixmpp/plugins/xep_0016/__init__.py create mode 100644 slixmpp/plugins/xep_0016/privacy.py create mode 100644 slixmpp/plugins/xep_0016/stanza.py create mode 100644 slixmpp/plugins/xep_0020/__init__.py create mode 100644 slixmpp/plugins/xep_0020/feature_negotiation.py create mode 100644 slixmpp/plugins/xep_0020/stanza.py create mode 100644 slixmpp/plugins/xep_0027/__init__.py create mode 100644 slixmpp/plugins/xep_0027/gpg.py create mode 100644 slixmpp/plugins/xep_0027/stanza.py create mode 100644 slixmpp/plugins/xep_0030/__init__.py create mode 100644 slixmpp/plugins/xep_0030/disco.py create mode 100644 slixmpp/plugins/xep_0030/stanza/__init__.py create mode 100644 slixmpp/plugins/xep_0030/stanza/info.py create mode 100644 slixmpp/plugins/xep_0030/stanza/items.py create mode 100644 slixmpp/plugins/xep_0030/static.py create mode 100644 slixmpp/plugins/xep_0033/__init__.py create mode 100644 slixmpp/plugins/xep_0033/addresses.py create mode 100644 slixmpp/plugins/xep_0033/stanza.py create mode 100644 slixmpp/plugins/xep_0045.py create mode 100644 slixmpp/plugins/xep_0047/__init__.py create mode 100644 slixmpp/plugins/xep_0047/ibb.py create mode 100644 slixmpp/plugins/xep_0047/stanza.py create mode 100644 slixmpp/plugins/xep_0047/stream.py create mode 100644 slixmpp/plugins/xep_0048/__init__.py create mode 100644 slixmpp/plugins/xep_0048/bookmarks.py create mode 100644 slixmpp/plugins/xep_0048/stanza.py create mode 100644 slixmpp/plugins/xep_0049/__init__.py create mode 100644 slixmpp/plugins/xep_0049/private_storage.py create mode 100644 slixmpp/plugins/xep_0049/stanza.py create mode 100644 slixmpp/plugins/xep_0050/__init__.py create mode 100644 slixmpp/plugins/xep_0050/adhoc.py create mode 100644 slixmpp/plugins/xep_0050/stanza.py create mode 100644 slixmpp/plugins/xep_0054/__init__.py create mode 100644 slixmpp/plugins/xep_0054/stanza.py create mode 100644 slixmpp/plugins/xep_0054/vcard_temp.py create mode 100644 slixmpp/plugins/xep_0059/__init__.py create mode 100644 slixmpp/plugins/xep_0059/rsm.py create mode 100644 slixmpp/plugins/xep_0059/stanza.py create mode 100644 slixmpp/plugins/xep_0060/__init__.py create mode 100644 slixmpp/plugins/xep_0060/pubsub.py create mode 100644 slixmpp/plugins/xep_0060/stanza/__init__.py create mode 100644 slixmpp/plugins/xep_0060/stanza/base.py create mode 100644 slixmpp/plugins/xep_0060/stanza/pubsub.py create mode 100644 slixmpp/plugins/xep_0060/stanza/pubsub_errors.py create mode 100644 slixmpp/plugins/xep_0060/stanza/pubsub_event.py create mode 100644 slixmpp/plugins/xep_0060/stanza/pubsub_owner.py create mode 100644 slixmpp/plugins/xep_0065/__init__.py create mode 100644 slixmpp/plugins/xep_0065/proxy.py create mode 100644 slixmpp/plugins/xep_0065/stanza.py create mode 100644 slixmpp/plugins/xep_0066/__init__.py create mode 100644 slixmpp/plugins/xep_0066/oob.py create mode 100644 slixmpp/plugins/xep_0066/stanza.py create mode 100644 slixmpp/plugins/xep_0071/__init__.py create mode 100644 slixmpp/plugins/xep_0071/stanza.py create mode 100644 slixmpp/plugins/xep_0071/xhtml_im.py create mode 100644 slixmpp/plugins/xep_0077/__init__.py create mode 100644 slixmpp/plugins/xep_0077/register.py create mode 100644 slixmpp/plugins/xep_0077/stanza.py create mode 100644 slixmpp/plugins/xep_0078/__init__.py create mode 100644 slixmpp/plugins/xep_0078/legacyauth.py create mode 100644 slixmpp/plugins/xep_0078/stanza.py create mode 100644 slixmpp/plugins/xep_0079/__init__.py create mode 100644 slixmpp/plugins/xep_0079/amp.py create mode 100644 slixmpp/plugins/xep_0079/stanza.py create mode 100644 slixmpp/plugins/xep_0080/__init__.py create mode 100644 slixmpp/plugins/xep_0080/geoloc.py create mode 100644 slixmpp/plugins/xep_0080/stanza.py create mode 100644 slixmpp/plugins/xep_0082.py create mode 100644 slixmpp/plugins/xep_0084/__init__.py create mode 100644 slixmpp/plugins/xep_0084/avatar.py create mode 100644 slixmpp/plugins/xep_0084/stanza.py create mode 100644 slixmpp/plugins/xep_0085/__init__.py create mode 100644 slixmpp/plugins/xep_0085/chat_states.py create mode 100644 slixmpp/plugins/xep_0085/stanza.py create mode 100644 slixmpp/plugins/xep_0086/__init__.py create mode 100644 slixmpp/plugins/xep_0086/legacy_error.py create mode 100644 slixmpp/plugins/xep_0086/stanza.py create mode 100644 slixmpp/plugins/xep_0091/__init__.py create mode 100644 slixmpp/plugins/xep_0091/legacy_delay.py create mode 100644 slixmpp/plugins/xep_0091/stanza.py create mode 100644 slixmpp/plugins/xep_0092/__init__.py create mode 100644 slixmpp/plugins/xep_0092/stanza.py create mode 100644 slixmpp/plugins/xep_0092/version.py create mode 100644 slixmpp/plugins/xep_0095/__init__.py create mode 100644 slixmpp/plugins/xep_0095/stanza.py create mode 100644 slixmpp/plugins/xep_0095/stream_initiation.py create mode 100644 slixmpp/plugins/xep_0096/__init__.py create mode 100644 slixmpp/plugins/xep_0096/file_transfer.py create mode 100644 slixmpp/plugins/xep_0096/stanza.py create mode 100644 slixmpp/plugins/xep_0106.py create mode 100644 slixmpp/plugins/xep_0107/__init__.py create mode 100644 slixmpp/plugins/xep_0107/stanza.py create mode 100644 slixmpp/plugins/xep_0107/user_mood.py create mode 100644 slixmpp/plugins/xep_0108/__init__.py create mode 100644 slixmpp/plugins/xep_0108/stanza.py create mode 100644 slixmpp/plugins/xep_0108/user_activity.py create mode 100644 slixmpp/plugins/xep_0115/__init__.py create mode 100644 slixmpp/plugins/xep_0115/caps.py create mode 100644 slixmpp/plugins/xep_0115/stanza.py create mode 100644 slixmpp/plugins/xep_0115/static.py create mode 100644 slixmpp/plugins/xep_0118/__init__.py create mode 100644 slixmpp/plugins/xep_0118/stanza.py create mode 100644 slixmpp/plugins/xep_0118/user_tune.py create mode 100644 slixmpp/plugins/xep_0128/__init__.py create mode 100644 slixmpp/plugins/xep_0128/extended_disco.py create mode 100644 slixmpp/plugins/xep_0128/static.py create mode 100644 slixmpp/plugins/xep_0131/__init__.py create mode 100644 slixmpp/plugins/xep_0131/headers.py create mode 100644 slixmpp/plugins/xep_0131/stanza.py create mode 100644 slixmpp/plugins/xep_0133.py create mode 100644 slixmpp/plugins/xep_0152/__init__.py create mode 100644 slixmpp/plugins/xep_0152/reachability.py create mode 100644 slixmpp/plugins/xep_0152/stanza.py create mode 100644 slixmpp/plugins/xep_0153/__init__.py create mode 100644 slixmpp/plugins/xep_0153/stanza.py create mode 100644 slixmpp/plugins/xep_0153/vcard_avatar.py create mode 100644 slixmpp/plugins/xep_0163.py create mode 100644 slixmpp/plugins/xep_0172/__init__.py create mode 100644 slixmpp/plugins/xep_0172/stanza.py create mode 100644 slixmpp/plugins/xep_0172/user_nick.py create mode 100644 slixmpp/plugins/xep_0184/__init__.py create mode 100644 slixmpp/plugins/xep_0184/receipt.py create mode 100644 slixmpp/plugins/xep_0184/stanza.py create mode 100644 slixmpp/plugins/xep_0186/__init__.py create mode 100644 slixmpp/plugins/xep_0186/invisible_command.py create mode 100644 slixmpp/plugins/xep_0186/stanza.py create mode 100644 slixmpp/plugins/xep_0191/__init__.py create mode 100644 slixmpp/plugins/xep_0191/blocking.py create mode 100644 slixmpp/plugins/xep_0191/stanza.py create mode 100644 slixmpp/plugins/xep_0196/__init__.py create mode 100644 slixmpp/plugins/xep_0196/stanza.py create mode 100644 slixmpp/plugins/xep_0196/user_gaming.py create mode 100644 slixmpp/plugins/xep_0198/__init__.py create mode 100644 slixmpp/plugins/xep_0198/stanza.py create mode 100644 slixmpp/plugins/xep_0198/stream_management.py create mode 100644 slixmpp/plugins/xep_0199/__init__.py create mode 100644 slixmpp/plugins/xep_0199/ping.py create mode 100644 slixmpp/plugins/xep_0199/stanza.py create mode 100644 slixmpp/plugins/xep_0202/__init__.py create mode 100644 slixmpp/plugins/xep_0202/stanza.py create mode 100644 slixmpp/plugins/xep_0202/time.py create mode 100644 slixmpp/plugins/xep_0203/__init__.py create mode 100644 slixmpp/plugins/xep_0203/delay.py create mode 100644 slixmpp/plugins/xep_0203/stanza.py create mode 100644 slixmpp/plugins/xep_0221/__init__.py create mode 100644 slixmpp/plugins/xep_0221/media.py create mode 100644 slixmpp/plugins/xep_0221/stanza.py create mode 100644 slixmpp/plugins/xep_0222.py create mode 100644 slixmpp/plugins/xep_0223.py create mode 100644 slixmpp/plugins/xep_0224/__init__.py create mode 100644 slixmpp/plugins/xep_0224/attention.py create mode 100644 slixmpp/plugins/xep_0224/stanza.py create mode 100644 slixmpp/plugins/xep_0231/__init__.py create mode 100644 slixmpp/plugins/xep_0231/bob.py create mode 100644 slixmpp/plugins/xep_0231/stanza.py create mode 100644 slixmpp/plugins/xep_0235/__init__.py create mode 100644 slixmpp/plugins/xep_0235/oauth.py create mode 100644 slixmpp/plugins/xep_0235/stanza.py create mode 100644 slixmpp/plugins/xep_0242.py create mode 100644 slixmpp/plugins/xep_0249/__init__.py create mode 100644 slixmpp/plugins/xep_0249/invite.py create mode 100644 slixmpp/plugins/xep_0249/stanza.py create mode 100644 slixmpp/plugins/xep_0256.py create mode 100644 slixmpp/plugins/xep_0257/__init__.py create mode 100644 slixmpp/plugins/xep_0257/client_cert_management.py create mode 100644 slixmpp/plugins/xep_0257/stanza.py create mode 100644 slixmpp/plugins/xep_0258/__init__.py create mode 100644 slixmpp/plugins/xep_0258/security_labels.py create mode 100644 slixmpp/plugins/xep_0258/stanza.py create mode 100644 slixmpp/plugins/xep_0270.py create mode 100644 slixmpp/plugins/xep_0279/__init__.py create mode 100644 slixmpp/plugins/xep_0279/ipcheck.py create mode 100644 slixmpp/plugins/xep_0279/stanza.py create mode 100644 slixmpp/plugins/xep_0280/__init__.py create mode 100644 slixmpp/plugins/xep_0280/carbons.py create mode 100644 slixmpp/plugins/xep_0280/stanza.py create mode 100644 slixmpp/plugins/xep_0297/__init__.py create mode 100644 slixmpp/plugins/xep_0297/forwarded.py create mode 100644 slixmpp/plugins/xep_0297/stanza.py create mode 100644 slixmpp/plugins/xep_0302.py create mode 100644 slixmpp/plugins/xep_0308/__init__.py create mode 100644 slixmpp/plugins/xep_0308/correction.py create mode 100644 slixmpp/plugins/xep_0308/stanza.py create mode 100644 slixmpp/plugins/xep_0313/__init__.py create mode 100644 slixmpp/plugins/xep_0313/mam.py create mode 100644 slixmpp/plugins/xep_0313/stanza.py create mode 100644 slixmpp/plugins/xep_0319/__init__.py create mode 100644 slixmpp/plugins/xep_0319/idle.py create mode 100644 slixmpp/plugins/xep_0319/stanza.py create mode 100644 slixmpp/plugins/xep_0323/__init__.py create mode 100644 slixmpp/plugins/xep_0323/device.py create mode 100644 slixmpp/plugins/xep_0323/sensordata.py create mode 100644 slixmpp/plugins/xep_0323/stanza/__init__.py create mode 100644 slixmpp/plugins/xep_0323/stanza/base.py create mode 100644 slixmpp/plugins/xep_0323/stanza/sensordata.py create mode 100644 slixmpp/plugins/xep_0323/timerreset.py create mode 100644 slixmpp/plugins/xep_0325/__init__.py create mode 100644 slixmpp/plugins/xep_0325/control.py create mode 100644 slixmpp/plugins/xep_0325/device.py create mode 100644 slixmpp/plugins/xep_0325/stanza/__init__.py create mode 100644 slixmpp/plugins/xep_0325/stanza/base.py create mode 100644 slixmpp/plugins/xep_0325/stanza/control.py create mode 100644 slixmpp/roster/__init__.py create mode 100644 slixmpp/roster/item.py create mode 100644 slixmpp/roster/multi.py create mode 100644 slixmpp/roster/single.py create mode 100644 slixmpp/stanza/__init__.py create mode 100644 slixmpp/stanza/atom.py create mode 100644 slixmpp/stanza/error.py create mode 100644 slixmpp/stanza/htmlim.py create mode 100644 slixmpp/stanza/iq.py create mode 100644 slixmpp/stanza/message.py create mode 100644 slixmpp/stanza/nick.py create mode 100644 slixmpp/stanza/presence.py create mode 100644 slixmpp/stanza/rootstanza.py create mode 100644 slixmpp/stanza/roster.py create mode 100644 slixmpp/stanza/stream_error.py create mode 100644 slixmpp/stanza/stream_features.py create mode 100644 slixmpp/test/__init__.py create mode 100644 slixmpp/test/livesocket.py create mode 100644 slixmpp/test/mocksocket.py create mode 100644 slixmpp/test/slixtest.py create mode 100644 slixmpp/thirdparty/__init__.py create mode 100644 slixmpp/thirdparty/gnupg.py create mode 100644 slixmpp/thirdparty/mini_dateutil.py create mode 100644 slixmpp/thirdparty/ordereddict.py create mode 100644 slixmpp/thirdparty/socks.py create mode 100644 slixmpp/thirdparty/statemachine.py create mode 100644 slixmpp/util/__init__.py create mode 100644 slixmpp/util/misc_ops.py create mode 100644 slixmpp/util/sasl/__init__.py create mode 100644 slixmpp/util/sasl/client.py create mode 100644 slixmpp/util/sasl/mechanisms.py create mode 100644 slixmpp/util/stringprep_profiles.py create mode 100644 slixmpp/version.py create mode 100644 slixmpp/xmlstream/__init__.py create mode 100644 slixmpp/xmlstream/cert.py create mode 100644 slixmpp/xmlstream/filesocket.py create mode 100644 slixmpp/xmlstream/handler/__init__.py create mode 100644 slixmpp/xmlstream/handler/base.py create mode 100644 slixmpp/xmlstream/handler/callback.py create mode 100644 slixmpp/xmlstream/handler/collector.py create mode 100644 slixmpp/xmlstream/handler/waiter.py create mode 100644 slixmpp/xmlstream/handler/xmlcallback.py create mode 100644 slixmpp/xmlstream/handler/xmlwaiter.py create mode 100644 slixmpp/xmlstream/jid.py create mode 100644 slixmpp/xmlstream/matcher/__init__.py create mode 100644 slixmpp/xmlstream/matcher/base.py create mode 100644 slixmpp/xmlstream/matcher/id.py create mode 100644 slixmpp/xmlstream/matcher/idsender.py create mode 100644 slixmpp/xmlstream/matcher/many.py create mode 100644 slixmpp/xmlstream/matcher/stanzapath.py create mode 100644 slixmpp/xmlstream/matcher/xmlmask.py create mode 100644 slixmpp/xmlstream/matcher/xpath.py create mode 100644 slixmpp/xmlstream/resolver.py create mode 100644 slixmpp/xmlstream/scheduler.py create mode 100644 slixmpp/xmlstream/stanzabase.py create mode 100644 slixmpp/xmlstream/tostring.py create mode 100644 slixmpp/xmlstream/xmlstream.py diff --git a/.gitignore b/.gitignore index 602416e8..21757a52 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ docs/_build/ *.swp .tox/ .coverage -sleekxmpp.egg-info/ +slixmpp.egg-info/ .ropeproject/ 4913 *~ diff --git a/README.rst b/README.rst index 7c14ab5a..e2c82258 100644 --- a/README.rst +++ b/README.rst @@ -1,76 +1,12 @@ -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 `_ -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: - -**Low number of dependencies** - Installing and using SleekXMPP should be as simple as possible, without - having to deal with long dependency chains. - - As part of reducing the number of dependencies, some third party - modules are included with SleekXMPP in the ``thirdparty`` directory. - Imports from this module first try to import an existing installed - version before loading the packaged version, when possible. - -**Every XEP as a plugin** - Following Python's "batteries included" approach, the goal is to - provide support for all currently active XEPs (final and draft). Since - adding XEP support is done through easy to create plugins, the hope is - to also provide a solid base for implementing and creating experimental - XEPs. - -**Rewarding to work with** - As much as possible, SleekXMPP should allow things to "just work" using - sensible defaults and appropriate abstractions. XML can be ugly to work - with, but it doesn't have to be that way. - - -Get the Code ------------- - -Get the latest stable version from PyPI:: - - pip install sleekxmpp - -The latest source code for SleekXMPP may be found on `Github -`_. Releases can be found in the -``master`` branch, while the latest development version is in the -``develop`` branch. - -**Latest Release** - - `1.3.1 `_ - -**Develop Releases** - - `Latest Develop Version `_ - - -Installing DNSPython ---------------------- -If you are using Python3 and wish to use dnspython, you will have to checkout and -install the ``python3`` branch:: - - git clone http://github.com/rthalley/dnspython - cd dnspython - git checkout python3 - python3 setup.py install - -Discussion ----------- -A mailing list and XMPP chat room are available for discussing and getting -help with SleekXMPP. - -**Mailing List** - `SleekXMPP Discussion on Google Groups `_ - -**Chat** - `sleek@conference.jabber.org `_ +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. Documentation and Testing @@ -83,22 +19,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 -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): @@ -155,8 +91,15 @@ SleekXMPP projects:: xmpp.process(block=True) +Slixmpp Credits +--------------- + +**Maintainer of the slixmpp fork:** Florent Le Coz + `louiz@louiz.org `_, + Credits ------- + **Main Author:** Nathan Fritz `fritzy@netflint.net `_, `@fritzy `_ diff --git a/docs/Makefile b/docs/Makefile index a520f6a1..d44cd8a4 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -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: diff --git a/docs/api/basexmpp.rst b/docs/api/basexmpp.rst index fa96322e..df05bb0b 100644 --- a/docs/api/basexmpp.rst +++ b/docs/api/basexmpp.rst @@ -2,7 +2,7 @@ BaseXMPP ======== -.. module:: sleekxmpp.basexmpp +.. module:: slixmpp.basexmpp .. autoclass:: BaseXMPP :members: diff --git a/docs/api/clientxmpp.rst b/docs/api/clientxmpp.rst index a6f32c43..232c37c3 100644 --- a/docs/api/clientxmpp.rst +++ b/docs/api/clientxmpp.rst @@ -2,7 +2,7 @@ ClientXMPP ========== -.. module:: sleekxmpp.clientxmpp +.. module:: slixmpp.clientxmpp .. autoclass:: ClientXMPP :members: diff --git a/docs/api/componentxmpp.rst b/docs/api/componentxmpp.rst index 989120c2..9c6366aa 100644 --- a/docs/api/componentxmpp.rst +++ b/docs/api/componentxmpp.rst @@ -2,7 +2,7 @@ ComponentXMPP ============= -.. module:: sleekxmpp.componentxmpp +.. module:: slixmpp.componentxmpp .. autoclass:: ComponentXMPP :members: diff --git a/docs/api/exceptions.rst b/docs/api/exceptions.rst index 7bc72ce5..0736a09c 100644 --- a/docs/api/exceptions.rst +++ b/docs/api/exceptions.rst @@ -1,7 +1,7 @@ Exceptions ========== -.. module:: sleekxmpp.exceptions +.. module:: slixmpp.exceptions .. autoexception:: XMPPError diff --git a/docs/api/xmlstream/filesocket.rst b/docs/api/xmlstream/filesocket.rst index 35f44019..eff062d8 100644 --- a/docs/api/xmlstream/filesocket.rst +++ b/docs/api/xmlstream/filesocket.rst @@ -1,4 +1,4 @@ -.. module:: sleekxmpp.xmlstream.filesocket +.. module:: slixmpp.xmlstream.filesocket .. _filesocket: diff --git a/docs/api/xmlstream/handler.rst b/docs/api/xmlstream/handler.rst index 33c0bf42..ab8091a3 100644 --- a/docs/api/xmlstream/handler.rst +++ b/docs/api/xmlstream/handler.rst @@ -3,14 +3,14 @@ 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.callback .. autoclass:: Callback :members: @@ -18,7 +18,7 @@ Callback Waiter ------ -.. module:: sleekxmpp.xmlstream.handler.waiter +.. module:: slixmpp.xmlstream.handler.waiter .. autoclass:: Waiter :members: diff --git a/docs/api/xmlstream/jid.rst b/docs/api/xmlstream/jid.rst index 22a2db45..1844b75a 100644 --- a/docs/api/xmlstream/jid.rst +++ b/docs/api/xmlstream/jid.rst @@ -1,7 +1,7 @@ Jabber IDs (JID) ================= -.. module:: sleekxmpp.xmlstream.jid +.. module:: slixmpp.xmlstream.jid .. autoclass:: JID :members: diff --git a/docs/api/xmlstream/matcher.rst b/docs/api/xmlstream/matcher.rst index df3591bc..793059f2 100644 --- a/docs/api/xmlstream/matcher.rst +++ b/docs/api/xmlstream/matcher.rst @@ -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: diff --git a/docs/api/xmlstream/scheduler.rst b/docs/api/xmlstream/scheduler.rst index ff91701e..59752eca 100644 --- a/docs/api/xmlstream/scheduler.rst +++ b/docs/api/xmlstream/scheduler.rst @@ -2,7 +2,7 @@ Scheduler ========= -.. module:: sleekxmpp.xmlstream.scheduler +.. module:: slixmpp.xmlstream.scheduler .. autoclass:: Task :members: diff --git a/docs/api/xmlstream/stanzabase.rst b/docs/api/xmlstream/stanzabase.rst index f575299e..ec28bafe 100644 --- a/docs/api/xmlstream/stanzabase.rst +++ b/docs/api/xmlstream/stanzabase.rst @@ -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,9 +52,9 @@ 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 `_ library, these chunks of XML are -referred to as :term:`stanzas `, and in SleekXMPP we refer to a +referred to as :term:`stanzas `, 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`. @@ -72,7 +72,7 @@ plugin stanza object. Here is an example: - + @@ -84,13 +84,13 @@ we can access the plugin as so:: >>> iq['disco_info'] ' - + ' 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 diff --git a/docs/api/xmlstream/tostring.rst b/docs/api/xmlstream/tostring.rst index 82a8c2a5..8d75f1db 100644 --- a/docs/api/xmlstream/tostring.rst +++ b/docs/api/xmlstream/tostring.rst @@ -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('') >>> ET.tostring(xml) @@ -25,7 +25,7 @@ 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 diff --git a/docs/api/xmlstream/xmlstream.rst b/docs/api/xmlstream/xmlstream.rst index 90a7a6af..ced2ed14 100644 --- a/docs/api/xmlstream/xmlstream.rst +++ b/docs/api/xmlstream/xmlstream.rst @@ -2,7 +2,7 @@ XML Stream ========== -.. module:: sleekxmpp.xmlstream.xmlstream +.. module:: slixmpp.xmlstream.xmlstream .. autoexception:: RestartStream diff --git a/docs/architecture.rst b/docs/architecture.rst index a2e0a27d..52bb8d9c 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -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,7 +17,7 @@ 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 @@ -26,7 +26,7 @@ which can be triggered either manually or on a timed schedule. The Main Threads ~~~~~~~~~~~~~~~~ -:class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` instances run using at +:class:`~slixmpp.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 @@ -34,7 +34,7 @@ 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. Additionally, the main event processing loop may be executed in its -own thread if SleekXMPP is being used in the background for another +own thread if Slixmpp is being used in the background for another application. Short-lived threads may also be spawned as requested for threaded @@ -61,10 +61,10 @@ 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.** @@ -73,14 +73,14 @@ when this bit of XML is received (with an assumed namespace of :term:`stanza object` is paired with a reference to the handler and placed into the event queue. - Our :class:`~sleekxmpp.stanza.Message` object is thus paired with the message stanza handler + Our :class:`~slixmpp.stanza.Message` object is thus paired with the message stanza handler :meth:`BaseXMPP._handle_message` to create the tuple:: ('stanza', stanza_obj, handler) 3. **Process the event queue.** - The event queue is the heart of SleekXMPP. Nearly every action that + The event queue is the heart of Slixmpp. Nearly every action that takes place is first inserted into this queue, whether that be received stanzas, custom events, or scheduled events. @@ -97,7 +97,7 @@ when this bit of XML is received (with an assumed namespace of 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. @@ -148,8 +148,8 @@ when this bit of XML is received (with an assumed namespace of 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 +157,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 +172,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. diff --git a/docs/conf.py b/docs/conf.py index 72e39d0f..fbb61b37 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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 @@ -105,7 +105,7 @@ html_theme = 'haiku' # The name for this set of Sphinx documents. If None, it defaults to # " v 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,7 +215,7 @@ 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) ] diff --git a/docs/create_plugin.rst b/docs/create_plugin.rst index 2b0514b8..7e082a7e 100644 --- a/docs/create_plugin.rst +++ b/docs/create_plugin.rst @@ -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 `_). To do this, SleekXMPP has a +One of the goals of Slixmpp is to provide support for every draft or final +XMPP extension (`XEP `_). 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 `_. In-band registration was implemented in example 14-6 (page 223) of `XMPP: The Definitive -Guide `_ because there was no SleekXMPP +Guide `_ 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 `, +Every plugin inherits from the class :mod:`base_plugin `, 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 @@ -42,7 +42,7 @@ module. To do so, use the following form when registering the 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,13 +50,13 @@ 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 base_plugin class xep_0077(base_plugin): """ @@ -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 @@ -83,12 +83,12 @@ finish activating the plugin. The ``post_init`` method needs to call ``base_plugin.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 @@ -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. @@ -484,12 +484,12 @@ 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') @@ -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 base_plugin + 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 diff --git a/docs/event_index.rst b/docs/event_index.rst index ee8f5a95..b5f249f2 100644 --- a/docs/event_index.rst +++ b/docs/event_index.rst @@ -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,24 +116,24 @@ 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. @@ -146,21 +146,21 @@ Event Index - **Source:** message - - **Data:** :py:class:`~sleekxmpp.Message` - - **Source:** :py:class:`BaseXMPP ` + - **Data:** :py:class:`~slixmpp.Message` + - **Source:** :py:class:`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_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,74 +181,74 @@ 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 @@ -260,16 +260,16 @@ Event Index session_start - **Data:** ``{}`` - - **Source:** :py:class:`ClientXMPP `, - :py:class:`ComponentXMPP ` - :py:class:`XEP-0078 ` + - **Source:** :py:class:`ClientXMPP `, + :py:class:`ComponentXMPP ` + :py:class:`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` diff --git a/docs/getting_started/component.rst b/docs/getting_started/component.rst index ce548ba4..efac7ad3 100644 --- a/docs/getting_started/component.rst +++ b/docs/getting_started/component.rst @@ -8,17 +8,17 @@ Create and Run a Server Component If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the - `mailing list `_ + `mailing list `_ or join the chat room at `sleek@conference.jabber.org `_. -If you have not yet installed SleekXMPP, do so now by either checking out a version -from `Github `_, or installing it using ``pip`` +If you have not yet installed Slixmpp, do so now by either checking out a version +from `Github `_, or installing it using ``pip`` or ``easy_install``. .. code-block:: sh - pip install sleekxmpp # Or: easy_install sleekxmpp + pip install slixmpp # Or: easy_install slixmpp Many XMPP applications eventually graduate to requiring to run as a server @@ -30,7 +30,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 +48,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 +62,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 diff --git a/docs/getting_started/echobot.rst b/docs/getting_started/echobot.rst index 7d29ec58..df5aa2b0 100644 --- a/docs/getting_started/echobot.rst +++ b/docs/getting_started/echobot.rst @@ -1,24 +1,24 @@ .. _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 `_ + `mailing list `_ or join the chat room at `sleek@conference.jabber.org `_. -If you have not yet installed SleekXMPP, do so now by either checking out a version -from `Github `_, or installing it using ``pip`` +If you have not yet installed Slixmpp, do so now by either checking out a version +from `Github `_, or installing it using ``pip`` or ``easy_install``. .. code-block:: sh - pip install sleekxmpp # Or: easy_install sleekxmpp + pip install slixmpp # Or: easy_install slixmpp As a basic starting project, we will create an echo bot which will reply to any @@ -48,7 +48,7 @@ To get started, here is a brief outline of the structure that the final project import getpass from optparse import OptionParser - import sleekxmpp + import slixmpp '''Here we will create out echo bot class''' @@ -61,7 +61,7 @@ To get started, here is a brief outline of the structure that the final project Default Encoding ---------------- -XMPP requires support for UTF-8 and so SleekXMPP must use UTF-8 as well. In +XMPP requires support for UTF-8 and so Slixmpp 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: @@ -69,13 +69,13 @@ 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 + from slixmpp.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. + Until we are able to ensure that Slixmpp will always use Unicode in Python2.6+, this + may cause issues embedding Slixmpp into other applications which assume ASCII encoding. Creating the EchoBot Class -------------------------- @@ -85,14 +85,14 @@ 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 ` class -which we can extend to add our message echoing feature. :class:`ClientXMPP ` +Slixmpp comes with a :class:`ClientXMPP ` class +which we can extend to add our message echoing feature. :class:`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) @@ -132,8 +132,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 `. -Calling :meth:`send_presence ` without any arguments will send the simplest +Our first task of sending an initial presence is done using :meth:`send_presence `. +Calling :meth:`send_presence ` without any arguments will send the simplest stanza allowed in XMPP: .. code-block:: xml @@ -141,17 +141,17 @@ stanza allowed in XMPP: -The second requirement is fulfilled using :meth:`get_roster `, which +The second requirement is fulfilled using :meth:`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 ` returns since we are not saving any return +what :meth:`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 -` instance to ``self.client_roster``. (The difference between ``self.roster`` and +` 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 -` is raised. Similarly, an :class:`IQError ` exception can +` is raised. Similarly, an :class:`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. @@ -201,7 +201,7 @@ Let's take a closer look at the ``.reply()`` method used above. For message stan which is then used as the value of the ```` 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 `, +Another way to have sent the reply message would be to use :meth:`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,13 +229,13 @@ 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. @@ -305,7 +305,7 @@ the ``EchoBot.__init__`` method instead. 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 @@ -313,11 +313,11 @@ the ``EchoBot.__init__`` method instead. 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 +``dnspython`` 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 ``dnspython``, 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 @@ -346,19 +346,19 @@ to :meth:`sleekxmpp.clientxmpp.ClientXMPP`. 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.base_plugin.post_init` method on all registered plugins. By +passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the +main processing loop in the main thread of execution. The :meth:`slixmpp.basexmpp.BaseXMPP.process` +call will not return until after Slixmpp disconnects. If you need to run the client in the background for another program, use ``block=False`` to spawn the processing loop in its own thread. .. note:: - Before 1.0, controlling the blocking behaviour of :meth:`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 +370,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 `_. +can also be found in the Slixmpp `examples directory `_. .. compound:: diff --git a/docs/getting_started/iq.rst b/docs/getting_started/iq.rst index 98e0bdaf..cbf3d476 100644 --- a/docs/getting_started/iq.rst +++ b/docs/getting_started/iq.rst @@ -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 ```` elements. For clients, just sending the empty ```` 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 +:class:`~slixmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based on the method name, and finally add a ```` 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 @@ -90,11 +90,11 @@ These options are: # ... 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,9 +124,9 @@ 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:: @@ -135,13 +135,13 @@ interfacting with the :class:`~sleekxmpp.stanza.iq.Iq` payload. * :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 ````, -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 diff --git a/docs/getting_started/muc.rst b/docs/getting_started/muc.rst index 26e1fa57..8e41790f 100644 --- a/docs/getting_started/muc.rst +++ b/docs/getting_started/muc.rst @@ -8,20 +8,20 @@ Mulit-User Chat (MUC) Bot If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the - `mailing list `_ + `mailing list `_ or join the chat room at `sleek@conference.jabber.org `_. -If you have not yet installed SleekXMPP, do so now by either checking out a version -from `Github `_, or installing it using ``pip`` +If you have not yet installed Slixmpp, do so now by either checking out a version +from `Github `_, or installing it using ``pip`` or ``easy_install``. .. code-block:: sh - pip install sleekxmpp # Or: easy_install sleekxmpp + pip install slixmpp # Or: easy_install slixmpp -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 +36,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 ` and which accepts +:class:`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 +44,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 @@ -81,7 +81,7 @@ the roster. Next, we want to join the group chat, so we call the .. note:: - The :attr:`plugin ` attribute is + The :attr:`plugin ` attribute is dictionary that maps to instances of plugins that we have previously registered, by their names. @@ -115,7 +115,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 +159,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 diff --git a/docs/getting_started/proxy.rst b/docs/getting_started/proxy.rst index 60d521c5..b5e74180 100644 --- a/docs/getting_started/proxy.rst +++ b/docs/getting_started/proxy.rst @@ -8,16 +8,16 @@ Enable HTTP Proxy Support If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the - `mailing list `_ + `mailing list `_ or join the chat room at `sleek@conference.jabber.org `_. 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 diff --git a/docs/getting_started/sendlogout.rst b/docs/getting_started/sendlogout.rst index a1352db9..5b23a469 100644 --- a/docs/getting_started/sendlogout.rst +++ b/docs/getting_started/sendlogout.rst @@ -5,25 +5,25 @@ Sign in, Send a Message, and Disconnect If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the - `mailing list `_ + `mailing list `_ or join the chat room at `sleek@conference.jabber.org `_. -A common use case for SleekXMPP is to send one-off messages from +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 ` and +start, we create a client class based on :class:`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) @@ -38,7 +38,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 `. +the roster. Next, we want to send our message, and to do that we will use :meth:`send_message `. .. code-block:: python @@ -48,12 +48,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 `. +Finally, we need to disconnect the client using :meth:`disconnect `. Now, sent stanzas are placed in a queue to pass them to the send thread. If we were to call -:meth:`disconnect ` without any parameters, then it is possible +:meth:`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) `. +:meth:`disconnect(wait=True) `. .. code-block:: python @@ -68,7 +68,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) ` + can process them, then :meth:`disconnect(wait=True) ` will block and not disconnect. Final Product diff --git a/docs/guide_xep_0030.rst b/docs/guide_xep_0030.rst index cb8d7d25..cd0f4850 100644 --- a/docs/guide_xep_0030.rst +++ b/docs/guide_xep_0030.rst @@ -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 `_, 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 @@ -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') diff --git a/docs/index.rst b/docs/index.rst index 6f6d8913..33d6cd00 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,49 +1,49 @@ -SleekXMPP +Slixmpp ######### .. sidebar:: Get the Code .. code-block:: sh - pip install sleekxmpp + pip install slixmpp - The latest source code for SleekXMPP may be found on `Github - `_. Releases can be found in the + The latest source code for Slixmpp may be found on `Github + `_. Releases can be found in the ``master`` branch, while the latest development version is in the ``develop`` branch. **Latest Stable Release** - - `1.0 `_ + - `1.0 `_ **Develop Releases** - - `Latest Develop Version `_ + - `Latest Develop Version `_ A mailing list and XMPP chat room are available for discussing and getting - help with SleekXMPP. + help with Slixmpp. **Mailing List** - `SleekXMPP Discussion on Google Groups `_ + `Slixmpp Discussion on Google Groups `_ **Chat** `sleek@conference.jabber.org `_ -SleekXMPP is an :ref:`MIT licensed ` XMPP library for Python 2.6/3.1+, +Slixmpp is an :ref:`MIT licensed ` XMPP library for Python 2.6/3.1+, and is featured in examples in `XMPP: The Definitive Guide `_ by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived here from reading the Definitive Guide, please see the notes on updating -the examples to the latest version of SleekXMPP. +the examples to the latest version of Slixmpp. -SleekXMPP's design goals and philosphy are: +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 +55,19 @@ 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 logging - from sleekxmpp import ClientXMPP - from sleekxmpp.exceptions import IqError, IqTimeout + from slixmpp import ClientXMPP + from slixmpp.exceptions import IqError, IqTimeout class EchoBot(ClientXMPP): @@ -161,7 +161,7 @@ Plugin Guides guide_xep_0030 -SleekXMPP Architecture and Design +Slixmpp Architecture and Design --------------------------------- .. toctree:: :maxdepth: 3 diff --git a/docs/make.bat b/docs/make.bat index d97407a6..33fda62b 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -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 ) diff --git a/docs/xmpp_tdg.rst b/docs/xmpp_tdg.rst index 3d12b1b6..c0d85196 100644 --- a/docs/xmpp_tdg.rst +++ b/docs/xmpp_tdg.rst @@ -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 `_ 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 ` 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. @@ -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,8 +72,8 @@ 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) @@ -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. @@ -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 `_ | @@ -209,7 +209,7 @@ Example 14-7. (Page 225) 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 diff --git a/examples/IoT_TestDevice.py b/examples/IoT_TestDevice.py index 8105aaff..1d99c61e 100755 --- a/examples/IoT_TestDevice.py +++ b/examples/IoT_TestDevice.py @@ -2,11 +2,11 @@ # -*- 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. """ @@ -14,7 +14,7 @@ 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 +sys.path=['/Users/jocke/Dropbox/06_dev/Slixmpp']+sys.path import logging import unittest @@ -26,28 +26,28 @@ from os.path import splitext, basename, join as pjoin from optparse import OptionParser from urllib import urlopen -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -from sleekxmpp.plugins.xep_0323.device import Device +from slixmpp.plugins.xep_0323.device import Device -#from sleekxmpp.exceptions import IqError, IqTimeout +#from slixmpp.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 diff --git a/examples/adhoc_provider.py b/examples/adhoc_provider.py index 86a575c9..c709fead 100755 --- a/examples/adhoc_provider.py +++ b/examples/adhoc_provider.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,28 +14,28 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 diff --git a/examples/adhoc_user.py b/examples/adhoc_user.py index 7df9f793..d4b650bc 100755 --- a/examples/adhoc_user.py +++ b/examples/adhoc_user.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,28 +14,28 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 diff --git a/examples/admin_commands.py b/examples/admin_commands.py index 5d9bf841..ed81b885 100755 --- a/examples/admin_commands.py +++ b/examples/admin_commands.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,28 +14,28 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 diff --git a/examples/custom_stanzas/custom_stanza_provider.py b/examples/custom_stanzas/custom_stanza_provider.py index 0ebdb77e..163f307d 100755 --- a/examples/custom_stanzas/custom_stanza_provider.py +++ b/examples/custom_stanzas/custom_stanza_provider.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,35 +14,35 @@ import logging import getpass from optparse import OptionParser -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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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 diff --git a/examples/custom_stanzas/custom_stanza_user.py b/examples/custom_stanzas/custom_stanza_user.py index 418e3218..ceadb036 100755 --- a/examples/custom_stanzas/custom_stanza_user.py +++ b/examples/custom_stanzas/custom_stanza_user.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,33 +14,33 @@ import logging import getpass from optparse import OptionParser -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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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 diff --git a/examples/custom_stanzas/stanza.py b/examples/custom_stanzas/stanza.py index 50d0f9f2..ba109b06 100644 --- a/examples/custom_stanzas/stanza.py +++ b/examples/custom_stanzas/stanza.py @@ -1,11 +1,11 @@ -from sleekxmpp.xmlstream import ElementBase +from slixmpp.xmlstream import ElementBase class Action(ElementBase): """ A stanza class for XML content of the form: - + X X X @@ -17,7 +17,7 @@ class Action(ElementBase): 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 @@ -50,7 +50,7 @@ class Action(ElementBase): #: are marked as sub_interfaces, and so the XML produced will #: look like: #: - #: + #: #: foo #: sub_interfaces = interfaces diff --git a/examples/disco_browser.py b/examples/disco_browser.py index aeb4fb5e..9df22bbc 100755 --- a/examples/disco_browser.py +++ b/examples/disco_browser.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,22 +14,22 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp -from sleekxmpp.exceptions import IqError, IqTimeout +import slixmpp +from slixmpp.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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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 +42,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') diff --git a/examples/download_avatars.py b/examples/download_avatars.py index 64300cff..bd505432 100755 --- a/examples/download_avatars.py +++ b/examples/download_avatars.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -15,16 +15,16 @@ import getpass import threading from optparse import OptionParser -import sleekxmpp -from sleekxmpp.exceptions import XMPPError +import slixmpp +from slixmpp.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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input @@ -37,14 +37,14 @@ 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) + slixmpp.ClientXMPP.__init__(self, jid, password) self.add_event_handler("session_start", self.start, threaded=True) self.add_event_handler("changed_status", self.wait_for_presences) diff --git a/examples/echo_client.py b/examples/echo_client.py index f2d38847..2c992155 100755 --- a/examples/echo_client.py +++ b/examples/echo_client.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,28 +14,28 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 diff --git a/examples/echo_component.py b/examples/echo_component.py index 9a24f2fa..a20f8c15 100755 --- a/examples/echo_component.py +++ b/examples/echo_component.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,15 +14,15 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp -from sleekxmpp.componentxmpp import ComponentXMPP +import slixmpp +from slixmpp.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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input @@ -31,7 +31,7 @@ else: class EchoComponent(ComponentXMPP): """ - A simple SleekXMPP component that echoes messages. + A simple Slixmpp component that echoes messages. """ def __init__(self, jid, secret, server, port): diff --git a/examples/gtalk_custom_domain.py b/examples/gtalk_custom_domain.py index c974fc55..b12a047f 100755 --- a/examples/gtalk_custom_domain.py +++ b/examples/gtalk_custom_domain.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,33 +14,33 @@ import logging import getpass from optparse import OptionParser -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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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 diff --git a/examples/ibb_transfer/ibb_receiver.py b/examples/ibb_transfer/ibb_receiver.py index 6aba98e3..625dd456 100755 --- a/examples/ibb_transfer/ibb_receiver.py +++ b/examples/ibb_transfer/ibb_receiver.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,27 +14,27 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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) + slixmpp.ClientXMPP.__init__(self, jid, password) self.register_plugin('xep_0030') # Service Discovery self.register_plugin('xep_0047', { diff --git a/examples/ibb_transfer/ibb_sender.py b/examples/ibb_transfer/ibb_sender.py index 7c380b68..e89e3239 100755 --- a/examples/ibb_transfer/ibb_sender.py +++ b/examples/ibb_transfer/ibb_sender.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,27 +14,27 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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) + slixmpp.ClientXMPP.__init__(self, jid, password) self.receiver = receiver self.filename = filename diff --git a/examples/migrate_roster.py b/examples/migrate_roster.py index 797e4f44..7aed1d30 100755 --- a/examples/migrate_roster.py +++ b/examples/migrate_roster.py @@ -6,14 +6,14 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input @@ -62,7 +62,7 @@ if opts.new_password is None: opts.new_password = getpass.getpass("New Password: ") -old_xmpp = sleekxmpp.ClientXMPP(opts.old_jid, opts.old_password) +old_xmpp = slixmpp.ClientXMPP(opts.old_jid, opts.old_password) # If you are connecting to Facebook and wish to use the # X-FACEBOOK-PLATFORM authentication mechanism, you will need @@ -98,7 +98,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(opts.new_jid, opts.new_password) def on_session2(event): new_xmpp.get_roster() new_xmpp.send_presence() diff --git a/examples/muc.py b/examples/muc.py index 5b5c764c..083c4c2f 100755 --- a/examples/muc.py +++ b/examples/muc.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,29 +14,29 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 diff --git a/examples/ping.py b/examples/ping.py index 1a1c2e94..b079c41a 100755 --- a/examples/ping.py +++ b/examples/ping.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,28 +14,28 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 diff --git a/examples/proxy_echo_client.py b/examples/proxy_echo_client.py index 98935b9c..966dd0ab 100755 --- a/examples/proxy_echo_client.py +++ b/examples/proxy_echo_client.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,28 +14,28 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 diff --git a/examples/pubsub_client.py b/examples/pubsub_client.py index 9a65553b..56135ec1 100755 --- a/examples/pubsub_client.py +++ b/examples/pubsub_client.py @@ -6,22 +6,22 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp -from sleekxmpp.xmlstream import ET, tostring +import slixmpp +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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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=''): diff --git a/examples/pubsub_events.py b/examples/pubsub_events.py index 12c33a76..679112af 100755 --- a/examples/pubsub_events.py +++ b/examples/pubsub_events.py @@ -6,24 +6,24 @@ import logging import getpass from optparse import OptionParser -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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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) diff --git a/examples/register_account.py b/examples/register_account.py index 422e5602..199f697c 100755 --- a/examples/register_account.py +++ b/examples/register_account.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,21 +14,21 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp -from sleekxmpp.exceptions import IqError, IqTimeout +import slixmpp +from slixmpp.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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -class RegisterBot(sleekxmpp.ClientXMPP): +class RegisterBot(slixmpp.ClientXMPP): """ A basic bot that will attempt to register an account @@ -40,7 +40,7 @@ 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 @@ -54,7 +54,7 @@ class RegisterBot(sleekxmpp.ClientXMPP): # 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) diff --git a/examples/roster_browser.py b/examples/roster_browser.py index 485ac941..1f08796c 100755 --- a/examples/roster_browser.py +++ b/examples/roster_browser.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -15,22 +15,22 @@ import getpass import threading from optparse import OptionParser -import sleekxmpp -from sleekxmpp.exceptions import IqError, IqTimeout +import slixmpp +from slixmpp.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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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,7 +38,7 @@ 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 diff --git a/examples/rpc_async.py b/examples/rpc_async.py index e3e23b69..edbad554 100755 --- a/examples/rpc_async.py +++ b/examples/rpc_async.py @@ -2,14 +2,14 @@ # -*- 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 diff --git a/examples/rpc_client_side.py b/examples/rpc_client_side.py index e792fc94..57c0dd58 100755 --- a/examples/rpc_client_side.py +++ b/examples/rpc_client_side.py @@ -2,14 +2,14 @@ # -*- 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 diff --git a/examples/rpc_server_side.py b/examples/rpc_server_side.py index 9e8b48d6..438828b9 100755 --- a/examples/rpc_server_side.py +++ b/examples/rpc_server_side.py @@ -2,14 +2,14 @@ # -*- 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 diff --git a/examples/send_client.py b/examples/send_client.py index 192469ae..d40ac1cb 100755 --- a/examples/send_client.py +++ b/examples/send_client.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -14,28 +14,28 @@ import logging import getpass from optparse import OptionParser -import sleekxmpp +import slixmpp # 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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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. diff --git a/examples/set_avatar.py b/examples/set_avatar.py index cae93c99..647bbd8c 100755 --- a/examples/set_avatar.py +++ b/examples/set_avatar.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -17,29 +17,29 @@ import getpass import threading from optparse import OptionParser -import sleekxmpp -from sleekxmpp.exceptions import XMPPError +import slixmpp +from slixmpp.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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.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) diff --git a/examples/thirdparty_auth.py b/examples/thirdparty_auth.py index f4d5c400..94d4a02a 100755 --- a/examples/thirdparty_auth.py +++ b/examples/thirdparty_auth.py @@ -2,9 +2,9 @@ # -*- 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. """ @@ -21,24 +21,24 @@ except ImportError: from urllib.parse import urlencode from http.client import HTTPSConnection -import sleekxmpp -from sleekxmpp.xmlstream import JID +import slixmpp +from slixmpp.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 +# throughout Slixmpp, we will set the default encoding # ourselves to UTF-8. if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding + from slixmpp.util.misc_ops import setdefaultencoding setdefaultencoding('utf8') else: raw_input = input -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 +46,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 +55,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 diff --git a/examples/user_location.py b/examples/user_location.py index 2a64cada..1ef78666 100755 --- a/examples/user_location.py +++ b/examples/user_location.py @@ -16,7 +16,7 @@ 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): diff --git a/examples/user_tune.py b/examples/user_tune.py index 09e050f0..afaa0c2d 100755 --- a/examples/user_tune.py +++ b/examples/user_tune.py @@ -11,7 +11,7 @@ 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): diff --git a/setup.py b/setup.py index cc4fdd5b..395fcc00 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ except ImportError: # from ez_setup import use_setuptools from testall import TestCommand -from sleekxmpp.version import __version__ +from slixmpp.version import __version__ # if 'cygwin' in sys.platform.lower(): # min_version = '0.6c6' # else: @@ -31,7 +31,7 @@ from sleekxmpp.version import __version__ # from setuptools import setup, find_packages, Extension, Feature VERSION = __version__ -DESCRIPTION = 'SleekXMPP is an elegant Python library for XMPP (aka Jabber, Google Talk, etc).' +DESCRIPTION = 'Slixmpp 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) @@ -46,107 +46,107 @@ CLASSIFIERS = [ 'Intended Audience :: Developers', 'Topic :: Software Development :: Libraries :: Python Modules', ] -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', +packages = [ 'slixmpp', + 'slixmpp/stanza', + 'slixmpp/test', + 'slixmpp/roster', + 'slixmpp/util', + 'slixmpp/util/sasl', + 'slixmpp/xmlstream', + 'slixmpp/xmlstream/matcher', + 'slixmpp/xmlstream/handler', + 'slixmpp/plugins', + 'slixmpp/plugins/xep_0004', + 'slixmpp/plugins/xep_0004/stanza', + 'slixmpp/plugins/xep_0009', + 'slixmpp/plugins/xep_0009/stanza', + 'slixmpp/plugins/xep_0012', + 'slixmpp/plugins/xep_0013', + 'slixmpp/plugins/xep_0016', + 'slixmpp/plugins/xep_0020', + 'slixmpp/plugins/xep_0027', + 'slixmpp/plugins/xep_0030', + 'slixmpp/plugins/xep_0030/stanza', + 'slixmpp/plugins/xep_0033', + 'slixmpp/plugins/xep_0047', + 'slixmpp/plugins/xep_0048', + 'slixmpp/plugins/xep_0049', + 'slixmpp/plugins/xep_0050', + 'slixmpp/plugins/xep_0054', + 'slixmpp/plugins/xep_0059', + 'slixmpp/plugins/xep_0060', + 'slixmpp/plugins/xep_0060/stanza', + 'slixmpp/plugins/xep_0065', + 'slixmpp/plugins/xep_0066', + 'slixmpp/plugins/xep_0071', + 'slixmpp/plugins/xep_0077', + 'slixmpp/plugins/xep_0078', + 'slixmpp/plugins/xep_0080', + 'slixmpp/plugins/xep_0084', + 'slixmpp/plugins/xep_0085', + 'slixmpp/plugins/xep_0086', + 'slixmpp/plugins/xep_0091', + 'slixmpp/plugins/xep_0092', + 'slixmpp/plugins/xep_0095', + 'slixmpp/plugins/xep_0096', + 'slixmpp/plugins/xep_0107', + 'slixmpp/plugins/xep_0108', + 'slixmpp/plugins/xep_0115', + 'slixmpp/plugins/xep_0118', + 'slixmpp/plugins/xep_0128', + 'slixmpp/plugins/xep_0131', + 'slixmpp/plugins/xep_0152', + 'slixmpp/plugins/xep_0153', + 'slixmpp/plugins/xep_0172', + 'slixmpp/plugins/xep_0184', + 'slixmpp/plugins/xep_0186', + 'slixmpp/plugins/xep_0191', + 'slixmpp/plugins/xep_0196', + 'slixmpp/plugins/xep_0198', + 'slixmpp/plugins/xep_0199', + 'slixmpp/plugins/xep_0202', + 'slixmpp/plugins/xep_0203', + 'slixmpp/plugins/xep_0221', + 'slixmpp/plugins/xep_0224', + 'slixmpp/plugins/xep_0231', + 'slixmpp/plugins/xep_0235', + 'slixmpp/plugins/xep_0249', + 'slixmpp/plugins/xep_0257', + 'slixmpp/plugins/xep_0258', + 'slixmpp/plugins/xep_0279', + 'slixmpp/plugins/xep_0280', + 'slixmpp/plugins/xep_0297', + 'slixmpp/plugins/xep_0308', + 'slixmpp/plugins/xep_0313', + 'slixmpp/plugins/xep_0319', + 'slixmpp/plugins/xep_0323', + 'slixmpp/plugins/xep_0323/stanza', + 'slixmpp/plugins/xep_0325', + 'slixmpp/plugins/xep_0325/stanza', + 'slixmpp/plugins/google', + 'slixmpp/plugins/google/gmail', + 'slixmpp/plugins/google/auth', + 'slixmpp/plugins/google/settings', + 'slixmpp/plugins/google/nosave', + 'slixmpp/features', + 'slixmpp/features/feature_mechanisms', + 'slixmpp/features/feature_mechanisms/stanza', + 'slixmpp/features/feature_starttls', + 'slixmpp/features/feature_bind', + 'slixmpp/features/feature_session', + 'slixmpp/features/feature_rosterver', + 'slixmpp/features/feature_preapproval', + 'slixmpp/thirdparty', ] setup( - name = "sleekxmpp", + name = "slixmpp", version = VERSION, description = DESCRIPTION, long_description = LONG_DESCRIPTION, author = 'Nathanael Fritz', author_email = 'fritzy [at] netflint.net', - url = 'http://github.com/fritzy/SleekXMPP', + url = 'http://github.com/fritzy/Slixmpp', license = 'MIT', platforms = [ 'any' ], packages = packages, diff --git a/sleekxmpp/__init__.py b/sleekxmpp/__init__.py deleted file mode 100644 index 85ee32b6..00000000 --- a/sleekxmpp/__init__.py +++ /dev/null @@ -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__ diff --git a/sleekxmpp/api.py b/sleekxmpp/api.py deleted file mode 100644 index 8de61b34..00000000 --- a/sleekxmpp/api.py +++ /dev/null @@ -1,200 +0,0 @@ -from sleekxmpp.xmlstream import JID - - -class APIWrapper(object): - - def __init__(self, api, name): - self.api = api - self.name = name - if name not in self.api.settings: - self.api.settings[name] = {} - - def __getattr__(self, attr): - """Curry API management commands with the API name.""" - if attr == 'name': - return self.name - elif attr == 'settings': - return self.api.settings[self.name] - elif attr == 'register': - def partial(handler, op, jid=None, node=None, default=False): - register = getattr(self.api, attr) - return register(handler, self.name, op, jid, node, default) - return partial - elif attr == 'register_default': - def partial(handler, op, jid=None, node=None): - return getattr(self.api, attr)(handler, self.name, op) - return partial - elif attr in ('run', 'restore_default', 'unregister'): - def partial(*args, **kwargs): - return getattr(self.api, attr)(self.name, *args, **kwargs) - return partial - return None - - def __getitem__(self, attr): - def partial(jid=None, node=None, ifrom=None, args=None): - return self.api.run(self.name, attr, jid, node, ifrom, args) - return partial - - -class APIRegistry(object): - - def __init__(self, xmpp): - self._handlers = {} - self._handler_defaults = {} - self.xmpp = xmpp - self.settings = {} - - def _setup(self, ctype, op): - """Initialize the API callback dictionaries. - - :param string ctype: The name of the API to initialize. - :param string op: The API operation to initialize. - """ - if ctype not in self.settings: - self.settings[ctype] = {} - if ctype not in self._handler_defaults: - self._handler_defaults[ctype] = {} - if ctype not in self._handlers: - self._handlers[ctype] = {} - if op not in self._handlers[ctype]: - self._handlers[ctype][op] = {'global': None, - 'jid': {}, - 'node': {}} - - def wrap(self, ctype): - """Return a wrapper object that targets a specific API.""" - return APIWrapper(self, ctype) - - def purge(self, ctype): - """Remove all information for a given API.""" - del self.settings[ctype] - del self._handler_defaults[ctype] - del self._handlers[ctype] - - def run(self, ctype, op, jid=None, node=None, ifrom=None, args=None): - """Execute an API callback, based on specificity. - - The API callback that is executed is chosen based on the combination - of the provided JID and node: - - JID | node | Handler - ============================== - Given | Given | Node handler - Given | None | JID handler - None | None | Global handler - - A node handler is responsible for servicing a single node at a single - JID, while a JID handler may respond for any node at a given JID, and - the global handler will answer to any JID+node combination. - - Handlers should check that the JID ``ifrom`` is authorized to perform - the desired action. - - :param string ctype: The name of the API to use. - :param string op: The API operation to perform. - :param JID jid: Optionally provide specific JID. - :param string node: Optionally provide specific node. - :param JID ifrom: Optionally provide the requesting JID. - :param tuple args: Optional positional arguments to the handler. - """ - self._setup(ctype, op) - - if not jid: - jid = self.xmpp.boundjid - elif jid and not isinstance(jid, JID): - jid = JID(jid) - elif jid == JID(''): - jid = self.xmpp.boundjid - - if node is None: - node = '' - - if self.xmpp.is_component: - if self.settings[ctype].get('component_bare', False): - jid = jid.bare - else: - jid = jid.full - else: - if self.settings[ctype].get('client_bare', False): - jid = jid.bare - else: - jid = jid.full - - jid = JID(jid) - - handler = self._handlers[ctype][op]['node'].get((jid, node), None) - if handler is None: - handler = self._handlers[ctype][op]['jid'].get(jid, None) - if handler is None: - handler = self._handlers[ctype][op].get('global', None) - - if handler: - try: - return handler(jid, node, ifrom, args) - except TypeError: - # To preserve backward compatibility, drop the ifrom - # parameter for existing handlers that don't understand it. - return handler(jid, node, args) - - def register(self, handler, ctype, op, jid=None, node=None, default=False): - """Register an API callback, with JID+node specificity. - - The API callback can later be executed based on the - specificity of the provided JID+node combination. - - See :meth:`~ApiRegistry.run` for more details. - - :param string ctype: The name of the API to use. - :param string op: The API operation to perform. - :param JID jid: Optionally provide specific JID. - :param string node: Optionally provide specific node. - """ - self._setup(ctype, op) - if jid is None and node is None: - if handler is None: - handler = self._handler_defaults[op] - self._handlers[ctype][op]['global'] = handler - elif jid is not None and node is None: - self._handlers[ctype][op]['jid'][jid] = handler - else: - self._handlers[ctype][op]['node'][(jid, node)] = handler - - if default: - self.register_default(handler, ctype, op) - - def register_default(self, handler, ctype, op): - """Register a default, global handler for an operation. - - :param func handler: The default, global handler for the operation. - :param string ctype: The name of the API to modify. - :param string op: The API operation to use. - """ - self._setup(ctype, op) - self._handler_defaults[ctype][op] = handler - - def unregister(self, ctype, op, jid=None, node=None): - """Remove an API callback. - - The API callback chosen for removal is based on the - specificity of the provided JID+node combination. - - See :meth:`~ApiRegistry.run` for more details. - - :param string ctype: The name of the API to use. - :param string op: The API operation to perform. - :param JID jid: Optionally provide specific JID. - :param string node: Optionally provide specific node. - """ - self._setup(ctype, op) - self.register(None, ctype, op, jid, node) - - def restore_default(self, ctype, op, jid=None, node=None): - """Reset an API callback to use a default handler. - - :param string ctype: The name of the API to use. - :param string op: The API operation to perform. - :param JID jid: Optionally provide specific JID. - :param string node: Optionally provide specific node. - """ - self.unregister(ctype, op, jid, node) - self.register(self._handler_defaults[ctype][op], ctype, op, jid, node) diff --git a/sleekxmpp/basexmpp.py b/sleekxmpp/basexmpp.py deleted file mode 100644 index bf0ae4df..00000000 --- a/sleekxmpp/basexmpp.py +++ /dev/null @@ -1,832 +0,0 @@ -# -*- coding: utf-8 -*- -""" - sleekxmpp.basexmpp - ~~~~~~~~~~~~~~~~~~ - - This module provides the common XMPP functionality - for both clients and components. - - Part of SleekXMPP: The Sleek XMPP Library - - :copyright: (c) 2011 Nathanael C. Fritz - :license: MIT, see LICENSE for more details -""" - -from __future__ import with_statement, unicode_literals - -import sys -import logging -import threading - -from sleekxmpp import plugins, roster, stanza -from sleekxmpp.api import APIRegistry -from sleekxmpp.exceptions import IqError, IqTimeout - -from sleekxmpp.stanza import Message, Presence, Iq, StreamError -from sleekxmpp.stanza.roster import Roster -from sleekxmpp.stanza.nick import Nick -from sleekxmpp.stanza.htmlim import HTMLIM - -from sleekxmpp.xmlstream import XMLStream, JID -from sleekxmpp.xmlstream import ET, register_stanza_plugin -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.stanzabase import XML_NS - -from sleekxmpp.plugins import PluginManager, load_plugin - - -log = logging.getLogger(__name__) - -# In order to make sure that Unicode is handled properly -# in Python 2.x, reset the default encoding. -if sys.version_info < (3, 0): - from sleekxmpp.util.misc_ops import setdefaultencoding - setdefaultencoding('utf8') - - -class BaseXMPP(XMLStream): - - """ - The BaseXMPP class adapts the generic XMLStream class for use - with XMPP. It also provides a plugin mechanism to easily extend - and add support for new XMPP features. - - :param default_ns: Ensure that the correct default XML namespace - is used during initialization. - """ - - def __init__(self, jid='', default_ns='jabber:client'): - XMLStream.__init__(self) - - self.default_ns = default_ns - self.stream_ns = 'http://etherx.jabber.org/streams' - self.namespace_map[self.stream_ns] = 'stream' - - #: An identifier for the stream as given by the server. - self.stream_id = None - - #: The JabberID (JID) requested for this connection. - self.requested_jid = JID(jid, cache_lock=True) - - #: The JabberID (JID) used by this connection, - #: as set after session binding. This may even be a - #: different bare JID than what was requested. - self.boundjid = JID(jid, cache_lock=True) - - self._expected_server_name = self.boundjid.host - self._redirect_attempts = 0 - - #: The maximum number of consecutive see-other-host - #: redirections that will be followed before quitting. - self.max_redirects = 5 - - self.session_bind_event = threading.Event() - - #: A dictionary mapping plugin names to plugins. - self.plugin = PluginManager(self) - - #: Configuration options for whitelisted plugins. - #: If a plugin is registered without any configuration, - #: and there is an entry here, it will be used. - self.plugin_config = {} - - #: A list of plugins that will be loaded if - #: :meth:`register_plugins` is called. - self.plugin_whitelist = [] - - #: The main roster object. This roster supports multiple - #: owner JIDs, as in the case for components. For clients - #: which only have a single JID, see :attr:`client_roster`. - self.roster = roster.Roster(self) - self.roster.add(self.boundjid) - - #: The single roster for the bound JID. This is the - #: equivalent of:: - #: - #: self.roster[self.boundjid.bare] - self.client_roster = self.roster[self.boundjid] - - #: The distinction between clients and components can be - #: important, primarily for choosing how to handle the - #: ``'to'`` and ``'from'`` JIDs of stanzas. - self.is_component = False - - #: Messages may optionally be tagged with ID values. Setting - #: :attr:`use_message_ids` to `True` will assign all outgoing - #: messages an ID. Some plugin features require enabling - #: this option. - self.use_message_ids = False - - #: Presence updates may optionally be tagged with ID values. - #: Setting :attr:`use_message_ids` to `True` will assign all - #: outgoing messages an ID. - self.use_presence_ids = False - - #: The API registry is a way to process callbacks based on - #: JID+node combinations. Each callback in the registry is - #: marked with: - #: - #: - An API name, e.g. xep_0030 - #: - The name of an action, e.g. get_info - #: - The JID that will be affected - #: - The node that will be affected - #: - #: API handlers with no JID or node will act as global handlers, - #: while those with a JID and no node will service all nodes - #: for a JID, and handlers with both a JID and node will be - #: used only for that specific combination. The handler that - #: provides the most specificity will be used. - self.api = APIRegistry(self) - - #: Flag indicating that the initial presence broadcast has - #: been sent. Until this happens, some servers may not - #: behave as expected when sending stanzas. - self.sentpresence = False - - #: A reference to :mod:`sleekxmpp.stanza` to make accessing - #: stanza classes easier. - self.stanza = stanza - - self.register_handler( - Callback('IM', - MatchXPath('{%s}message/{%s}body' % (self.default_ns, - self.default_ns)), - self._handle_message)) - self.register_handler( - Callback('Presence', - MatchXPath("{%s}presence" % self.default_ns), - self._handle_presence)) - - self.register_handler( - Callback('Stream Error', - MatchXPath("{%s}error" % self.stream_ns), - self._handle_stream_error)) - - self.add_event_handler('session_start', - self._handle_session_start) - self.add_event_handler('disconnected', - self._handle_disconnected) - self.add_event_handler('presence_available', - self._handle_available) - self.add_event_handler('presence_dnd', - self._handle_available) - self.add_event_handler('presence_xa', - self._handle_available) - self.add_event_handler('presence_chat', - self._handle_available) - self.add_event_handler('presence_away', - self._handle_available) - self.add_event_handler('presence_unavailable', - self._handle_unavailable) - self.add_event_handler('presence_subscribe', - self._handle_subscribe) - self.add_event_handler('presence_subscribed', - self._handle_subscribed) - self.add_event_handler('presence_unsubscribe', - self._handle_unsubscribe) - self.add_event_handler('presence_unsubscribed', - self._handle_unsubscribed) - self.add_event_handler('roster_subscription_request', - self._handle_new_subscription) - - # Set up the XML stream with XMPP's root stanzas. - self.register_stanza(Message) - self.register_stanza(Iq) - self.register_stanza(Presence) - self.register_stanza(StreamError) - - # Initialize a few default stanza plugins. - register_stanza_plugin(Iq, Roster) - register_stanza_plugin(Message, Nick) - - def start_stream_handler(self, xml): - """Save the stream ID once the streams have been established. - - :param xml: The incoming stream's root element. - """ - self.stream_id = xml.get('id', '') - self.stream_version = xml.get('version', '') - self.peer_default_lang = xml.get('{%s}lang' % XML_NS, None) - - if not self.is_component and not self.stream_version: - log.warning('Legacy XMPP 0.9 protocol detected.') - self.event('legacy_protocol') - - def process(self, *args, **kwargs): - """Initialize plugins and begin processing the XML stream. - - The number of threads used for processing stream events is determined - by :data:`HANDLER_THREADS`. - - :param bool block: If ``False``, then event dispatcher will run - in a separate thread, allowing for the stream to be - used in the background for another application. - Otherwise, ``process(block=True)`` blocks the current - thread. Defaults to ``False``. - :param bool threaded: **DEPRECATED** - If ``True``, then event dispatcher will run - in a separate thread, allowing for the stream to be - used in the background for another application. - Defaults to ``True``. This does **not** mean that no - threads are used at all if ``threaded=False``. - - Regardless of these threading options, these threads will - always exist: - - - The event queue processor - - The send queue processor - - The scheduler - """ - for name in self.plugin: - if not hasattr(self.plugin[name], 'post_inited'): - if hasattr(self.plugin[name], 'post_init'): - self.plugin[name].post_init() - self.plugin[name].post_inited = True - return XMLStream.process(self, *args, **kwargs) - - def register_plugin(self, plugin, pconfig={}, module=None): - """Register and configure a plugin for use in this stream. - - :param plugin: The name of the plugin class. Plugin names must - be unique. - :param pconfig: A dictionary of configuration data for the plugin. - Defaults to an empty dictionary. - :param module: Optional refence to the module containing the plugin - class if using custom plugins. - """ - - # Use the global plugin config cache, if applicable - if not pconfig: - pconfig = self.plugin_config.get(plugin, {}) - - if not self.plugin.registered(plugin): - load_plugin(plugin, module) - self.plugin.enable(plugin, pconfig) - - def register_plugins(self): - """Register and initialize all built-in plugins. - - Optionally, the list of plugins loaded may be limited to those - contained in :attr:`plugin_whitelist`. - - Plugin configurations stored in :attr:`plugin_config` will be used. - """ - if self.plugin_whitelist: - plugin_list = self.plugin_whitelist - else: - plugin_list = plugins.__all__ - - for plugin in plugin_list: - if plugin in plugins.__all__: - self.register_plugin(plugin) - else: - raise NameError("Plugin %s not in plugins.__all__." % plugin) - - def __getitem__(self, key): - """Return a plugin given its name, if it has been registered.""" - if key in self.plugin: - return self.plugin[key] - else: - log.warning("Plugin '%s' is not loaded.", key) - return False - - def get(self, key, default): - """Return a plugin given its name, if it has been registered.""" - return self.plugin.get(key, default) - - def Message(self, *args, **kwargs): - """Create a Message stanza associated with this stream.""" - msg = Message(self, *args, **kwargs) - msg['lang'] = self.default_lang - return msg - - def Iq(self, *args, **kwargs): - """Create an Iq stanza associated with this stream.""" - return Iq(self, *args, **kwargs) - - def Presence(self, *args, **kwargs): - """Create a Presence stanza associated with this stream.""" - pres = Presence(self, *args, **kwargs) - pres['lang'] = self.default_lang - return pres - - def make_iq(self, id=0, ifrom=None, ito=None, itype=None, iquery=None): - """Create a new Iq stanza with a given Id and from JID. - - :param id: An ideally unique ID value for this stanza thread. - Defaults to 0. - :param ifrom: The from :class:`~sleekxmpp.xmlstream.jid.JID` - to use for this stanza. - :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` - for this stanza. - :param itype: The :class:`~sleekxmpp.stanza.iq.Iq`'s type, - one of: ``'get'``, ``'set'``, ``'result'``, - or ``'error'``. - :param iquery: Optional namespace for adding a query element. - """ - iq = self.Iq() - iq['id'] = str(id) - iq['to'] = ito - iq['from'] = ifrom - iq['type'] = itype - iq['query'] = iquery - return iq - - def make_iq_get(self, queryxmlns=None, ito=None, ifrom=None, iq=None): - """Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type ``'get'``. - - Optionally, a query element may be added. - - :param queryxmlns: The namespace of the query to use. - :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` - for this stanza. - :param ifrom: The ``'from'`` :class:`~sleekxmpp.xmlstream.jid.JID` - to use for this stanza. - :param iq: Optionally use an existing stanza instead - of generating a new one. - """ - if not iq: - iq = self.Iq() - iq['type'] = 'get' - iq['query'] = queryxmlns - if ito: - iq['to'] = ito - if ifrom: - iq['from'] = ifrom - return iq - - def make_iq_result(self, id=None, ito=None, ifrom=None, iq=None): - """ - Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type - ``'result'`` with the given ID value. - - :param id: An ideally unique ID value. May use :meth:`new_id()`. - :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` - for this stanza. - :param ifrom: The ``'from'`` :class:`~sleekxmpp.xmlstream.jid.JID` - to use for this stanza. - :param iq: Optionally use an existing stanza instead - of generating a new one. - """ - if not iq: - iq = self.Iq() - if id is None: - id = self.new_id() - iq['id'] = id - iq['type'] = 'result' - if ito: - iq['to'] = ito - if ifrom: - iq['from'] = ifrom - return iq - - def make_iq_set(self, sub=None, ito=None, ifrom=None, iq=None): - """ - Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type ``'set'``. - - Optionally, a substanza may be given to use as the - stanza's payload. - - :param sub: Either an - :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` - stanza object or an - :class:`~xml.etree.ElementTree.Element` XML object - to use as the :class:`~sleekxmpp.stanza.iq.Iq`'s payload. - :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` - for this stanza. - :param ifrom: The ``'from'`` :class:`~sleekxmpp.xmlstream.jid.JID` - to use for this stanza. - :param iq: Optionally use an existing stanza instead - of generating a new one. - """ - if not iq: - iq = self.Iq() - iq['type'] = 'set' - if sub != None: - iq.append(sub) - if ito: - iq['to'] = ito - if ifrom: - iq['from'] = ifrom - return iq - - def make_iq_error(self, id, type='cancel', - condition='feature-not-implemented', - text=None, ito=None, ifrom=None, iq=None): - """ - Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type ``'error'``. - - :param id: An ideally unique ID value. May use :meth:`new_id()`. - :param type: The type of the error, such as ``'cancel'`` or - ``'modify'``. Defaults to ``'cancel'``. - :param condition: The error condition. Defaults to - ``'feature-not-implemented'``. - :param text: A message describing the cause of the error. - :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` - for this stanza. - :param ifrom: The ``'from'`` :class:`~sleekxmpp.xmlstream.jid.JID` - to use for this stanza. - :param iq: Optionally use an existing stanza instead - of generating a new one. - """ - if not iq: - iq = self.Iq() - iq['id'] = id - iq['error']['type'] = type - iq['error']['condition'] = condition - iq['error']['text'] = text - if ito: - iq['to'] = ito - if ifrom: - iq['from'] = ifrom - return iq - - def make_iq_query(self, iq=None, xmlns='', ito=None, ifrom=None): - """ - Create or modify an :class:`~sleekxmpp.stanza.iq.Iq` stanza - to use the given query namespace. - - :param iq: Optionally use an existing stanza instead - of generating a new one. - :param xmlns: The query's namespace. - :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` - for this stanza. - :param ifrom: The ``'from'`` :class:`~sleekxmpp.xmlstream.jid.JID` - to use for this stanza. - """ - if not iq: - iq = self.Iq() - iq['query'] = xmlns - if ito: - iq['to'] = ito - if ifrom: - iq['from'] = ifrom - return iq - - def make_query_roster(self, iq=None): - """Create a roster query element. - - :param iq: Optionally use an existing stanza instead - of generating a new one. - """ - if iq: - iq['query'] = 'jabber:iq:roster' - return ET.Element("{jabber:iq:roster}query") - - def make_message(self, mto, mbody=None, msubject=None, mtype=None, - mhtml=None, mfrom=None, mnick=None): - """ - Create and initialize a new - :class:`~sleekxmpp.stanza.message.Message` stanza. - - :param mto: The recipient of the message. - :param mbody: The main contents of the message. - :param msubject: Optional subject for the message. - :param mtype: The message's type, such as ``'chat'`` or - ``'groupchat'``. - :param mhtml: Optional HTML body content in the form of a string. - :param mfrom: The sender of the message. if sending from a client, - be aware that some servers require that the full JID - of the sender be used. - :param mnick: Optional nickname of the sender. - """ - message = self.Message(sto=mto, stype=mtype, sfrom=mfrom) - message['body'] = mbody - message['subject'] = msubject - if mnick is not None: - message['nick'] = mnick - if mhtml is not None: - message['html']['body'] = mhtml - return message - - def make_presence(self, pshow=None, pstatus=None, ppriority=None, - pto=None, ptype=None, pfrom=None, pnick=None): - """ - Create and initialize a new - :class:`~sleekxmpp.stanza.presence.Presence` stanza. - - :param pshow: The presence's show value. - :param pstatus: The presence's status message. - :param ppriority: This connection's priority. - :param pto: The recipient of a directed presence. - :param ptype: The type of presence, such as ``'subscribe'``. - :param pfrom: The sender of the presence. - :param pnick: Optional nickname of the presence's sender. - """ - presence = self.Presence(stype=ptype, sfrom=pfrom, sto=pto) - if pshow is not None: - presence['type'] = pshow - if pfrom is None and self.is_component: - presence['from'] = self.boundjid.full - presence['priority'] = ppriority - presence['status'] = pstatus - presence['nick'] = pnick - return presence - - def send_message(self, mto, mbody, msubject=None, mtype=None, - mhtml=None, mfrom=None, mnick=None): - """ - Create, initialize, and send a new - :class:`~sleekxmpp.stanza.message.Message` stanza. - - :param mto: The recipient of the message. - :param mbody: The main contents of the message. - :param msubject: Optional subject for the message. - :param mtype: The message's type, such as ``'chat'`` or - ``'groupchat'``. - :param mhtml: Optional HTML body content in the form of a string. - :param mfrom: The sender of the message. if sending from a client, - be aware that some servers require that the full JID - of the sender be used. - :param mnick: Optional nickname of the sender. - """ - self.make_message(mto, mbody, msubject, mtype, - mhtml, mfrom, mnick).send() - - def send_presence(self, pshow=None, pstatus=None, ppriority=None, - pto=None, pfrom=None, ptype=None, pnick=None): - """ - Create, initialize, and send a new - :class:`~sleekxmpp.stanza.presence.Presence` stanza. - - :param pshow: The presence's show value. - :param pstatus: The presence's status message. - :param ppriority: This connection's priority. - :param pto: The recipient of a directed presence. - :param ptype: The type of presence, such as ``'subscribe'``. - :param pfrom: The sender of the presence. - :param pnick: Optional nickname of the presence's sender. - """ - self.make_presence(pshow, pstatus, ppriority, pto, - ptype, pfrom, pnick).send() - - def send_presence_subscription(self, pto, pfrom=None, - ptype='subscribe', pnick=None): - """ - Create, initialize, and send a new - :class:`~sleekxmpp.stanza.presence.Presence` stanza of - type ``'subscribe'``. - - :param pto: The recipient of a directed presence. - :param pfrom: The sender of the presence. - :param ptype: The type of presence, such as ``'subscribe'``. - :param pnick: Optional nickname of the presence's sender. - """ - self.make_presence(ptype=ptype, - pfrom=pfrom, - pto=JID(pto).bare, - pnick=pnick).send() - - @property - def jid(self): - """Attribute accessor for bare jid""" - log.warning("jid property deprecated. Use boundjid.bare") - return self.boundjid.bare - - @jid.setter - def jid(self, value): - log.warning("jid property deprecated. Use boundjid.bare") - self.boundjid.bare = value - - @property - def fulljid(self): - """Attribute accessor for full jid""" - log.warning("fulljid property deprecated. Use boundjid.full") - return self.boundjid.full - - @fulljid.setter - def fulljid(self, value): - log.warning("fulljid property deprecated. Use boundjid.full") - self.boundjid.full = value - - @property - def resource(self): - """Attribute accessor for jid resource""" - log.warning("resource property deprecated. Use boundjid.resource") - return self.boundjid.resource - - @resource.setter - def resource(self, value): - log.warning("fulljid property deprecated. Use boundjid.resource") - self.boundjid.resource = value - - @property - def username(self): - """Attribute accessor for jid usernode""" - log.warning("username property deprecated. Use boundjid.user") - return self.boundjid.user - - @username.setter - def username(self, value): - log.warning("username property deprecated. Use boundjid.user") - self.boundjid.user = value - - @property - def server(self): - """Attribute accessor for jid host""" - log.warning("server property deprecated. Use boundjid.host") - return self.boundjid.server - - @server.setter - def server(self, value): - log.warning("server property deprecated. Use boundjid.host") - self.boundjid.server = value - - @property - def auto_authorize(self): - """Auto accept or deny subscription requests. - - If ``True``, auto accept subscription requests. - If ``False``, auto deny subscription requests. - If ``None``, don't automatically respond. - """ - return self.roster.auto_authorize - - @auto_authorize.setter - def auto_authorize(self, value): - self.roster.auto_authorize = value - - @property - def auto_subscribe(self): - """Auto send requests for mutual subscriptions. - - If ``True``, auto send mutual subscription requests. - """ - return self.roster.auto_subscribe - - @auto_subscribe.setter - def auto_subscribe(self, value): - self.roster.auto_subscribe = value - - def set_jid(self, jid): - """Rip a JID apart and claim it as our own.""" - log.debug("setting jid to %s", jid) - self.boundjid = JID(jid, cache_lock=True) - - def getjidresource(self, fulljid): - if '/' in fulljid: - return fulljid.split('/', 1)[-1] - else: - return '' - - def getjidbare(self, fulljid): - return fulljid.split('/', 1)[0] - - def _handle_session_start(self, event): - """Reset redirection attempt count.""" - self._redirect_attempts = 0 - - def _handle_disconnected(self, event): - """When disconnected, reset the roster""" - self.roster.reset() - self.session_bind_event.clear() - - def _handle_stream_error(self, error): - self.event('stream_error', error) - - if error['condition'] == 'see-other-host': - other_host = error['see_other_host'] - if not other_host: - log.warning("No other host specified.") - return - - if self._redirect_attempts > self.max_redirects: - log.error("Exceeded maximum number of redirection attempts.") - return - - self._redirect_attempts += 1 - - host = other_host - port = 5222 - - if '[' in other_host and ']' in other_host: - host = other_host.split(']')[0][1:] - elif ':' in other_host: - host = other_host.split(':')[0] - - port_sec = other_host.split(']')[-1] - if ':' in port_sec: - port = int(port_sec.split(':')[1]) - - self.address = (host, port) - self.default_domain = host - self.dns_records = None - self.reconnect_delay = None - self.reconnect() - - def _handle_message(self, msg): - """Process incoming message stanzas.""" - if not self.is_component and not msg['to'].bare: - msg['to'] = self.boundjid - self.event('message', msg) - - def _handle_available(self, pres): - self.roster[pres['to']][pres['from']].handle_available(pres) - - def _handle_unavailable(self, pres): - self.roster[pres['to']][pres['from']].handle_unavailable(pres) - - def _handle_new_subscription(self, pres): - """Attempt to automatically handle subscription requests. - - Subscriptions will be approved if the request is from - a whitelisted JID, of :attr:`auto_authorize` is True. They - will be rejected if :attr:`auto_authorize` is False. Setting - :attr:`auto_authorize` to ``None`` will disable automatic - subscription handling (except for whitelisted JIDs). - - If a subscription is accepted, a request for a mutual - subscription will be sent if :attr:`auto_subscribe` is ``True``. - """ - roster = self.roster[pres['to']] - item = self.roster[pres['to']][pres['from']] - if item['whitelisted']: - item.authorize() - if roster.auto_subscribe: - item.subscribe() - elif roster.auto_authorize: - item.authorize() - if roster.auto_subscribe: - item.subscribe() - elif roster.auto_authorize == False: - item.unauthorize() - - def _handle_removed_subscription(self, pres): - self.roster[pres['to']][pres['from']].handle_unauthorize(pres) - - def _handle_subscribe(self, pres): - self.roster[pres['to']][pres['from']].handle_subscribe(pres) - - def _handle_subscribed(self, pres): - self.roster[pres['to']][pres['from']].handle_subscribed(pres) - - def _handle_unsubscribe(self, pres): - self.roster[pres['to']][pres['from']].handle_unsubscribe(pres) - - def _handle_unsubscribed(self, pres): - self.roster[pres['to']][pres['from']].handle_unsubscribed(pres) - - def _handle_presence(self, presence): - """Process incoming presence stanzas. - - Update the roster with presence information. - """ - if not self.is_component and not presence['to'].bare: - presence['to'] = self.boundjid - - self.event('presence', presence) - self.event('presence_%s' % presence['type'], presence) - - # Check for changes in subscription state. - if presence['type'] in ('subscribe', 'subscribed', - 'unsubscribe', 'unsubscribed'): - self.event('changed_subscription', presence) - return - elif not presence['type'] in ('available', 'unavailable') and \ - not presence['type'] in presence.showtypes: - return - - def exception(self, exception): - """Process any uncaught exceptions, notably - :class:`~sleekxmpp.exceptions.IqError` and - :class:`~sleekxmpp.exceptions.IqTimeout` exceptions. - - :param exception: An unhandled :class:`Exception` object. - """ - if isinstance(exception, IqError): - iq = exception.iq - log.error('%s: %s', iq['error']['condition'], - iq['error']['text']) - log.warning('You should catch IqError exceptions') - elif isinstance(exception, IqTimeout): - iq = exception.iq - log.error('Request timed out: %s', iq) - log.warning('You should catch IqTimeout exceptions') - elif isinstance(exception, SyntaxError): - # Hide stream parsing errors that occur when the - # stream is disconnected (they've been handled, we - # don't need to make a mess in the logs). - pass - else: - log.exception(exception) - - -# Restore the old, lowercased name for backwards compatibility. -basexmpp = BaseXMPP - -# To comply with PEP8, method names now use underscores. -# Deprecated method names are re-mapped for backwards compatibility. -BaseXMPP.registerPlugin = BaseXMPP.register_plugin -BaseXMPP.makeIq = BaseXMPP.make_iq -BaseXMPP.makeIqGet = BaseXMPP.make_iq_get -BaseXMPP.makeIqResult = BaseXMPP.make_iq_result -BaseXMPP.makeIqSet = BaseXMPP.make_iq_set -BaseXMPP.makeIqError = BaseXMPP.make_iq_error -BaseXMPP.makeIqQuery = BaseXMPP.make_iq_query -BaseXMPP.makeQueryRoster = BaseXMPP.make_query_roster -BaseXMPP.makeMessage = BaseXMPP.make_message -BaseXMPP.makePresence = BaseXMPP.make_presence -BaseXMPP.sendMessage = BaseXMPP.send_message -BaseXMPP.sendPresence = BaseXMPP.send_presence -BaseXMPP.sendPresenceSubscription = BaseXMPP.send_presence_subscription diff --git a/sleekxmpp/clientxmpp.py b/sleekxmpp/clientxmpp.py deleted file mode 100644 index f837c0f2..00000000 --- a/sleekxmpp/clientxmpp.py +++ /dev/null @@ -1,333 +0,0 @@ -# -*- coding: utf-8 -*- -""" - sleekxmpp.clientxmpp - ~~~~~~~~~~~~~~~~~~~~ - - This module provides XMPP functionality that - is specific to client connections. - - Part of SleekXMPP: The Sleek XMPP Library - - :copyright: (c) 2011 Nathanael C. Fritz - :license: MIT, see LICENSE for more details -""" - -from __future__ import absolute_import, unicode_literals - -import logging - -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.basexmpp import BaseXMPP -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import XMLStream -from sleekxmpp.xmlstream.matcher import StanzaPath, MatchXPath -from sleekxmpp.xmlstream.handler import Callback - -# Flag indicating if DNS SRV records are available for use. -try: - import dns.resolver -except ImportError: - DNSPYTHON = False -else: - DNSPYTHON = True - - -log = logging.getLogger(__name__) - - -class ClientXMPP(BaseXMPP): - - """ - SleekXMPP's client class. (Use only for good, not for evil.) - - Typical use pattern: - - .. code-block:: python - - xmpp = ClientXMPP('user@server.tld/resource', 'password') - # ... Register plugins and event handlers ... - xmpp.connect() - xmpp.process(block=False) # block=True will block the current - # thread. By default, block=False - - :param jid: The JID of the XMPP user account. - :param password: The password for the XMPP user account. - :param ssl: **Deprecated.** - :param plugin_config: A dictionary of plugin configurations. - :param plugin_whitelist: A list of approved plugins that - will be loaded when calling - :meth:`~sleekxmpp.basexmpp.BaseXMPP.register_plugins()`. - :param escape_quotes: **Deprecated.** - """ - - def __init__(self, jid, password, plugin_config={}, plugin_whitelist=[], - escape_quotes=True, sasl_mech=None, lang='en'): - BaseXMPP.__init__(self, jid, 'jabber:client') - - self.escape_quotes = escape_quotes - self.plugin_config = plugin_config - self.plugin_whitelist = plugin_whitelist - self.default_port = 5222 - self.default_lang = lang - - self.credentials = {} - - self.password = password - - self.stream_header = "" % ( - self.boundjid.host, - "xmlns:stream='%s'" % self.stream_ns, - "xmlns='%s'" % self.default_ns, - "xml:lang='%s'" % self.default_lang, - "version='1.0'") - self.stream_footer = "" - - self.features = set() - self._stream_feature_handlers = {} - self._stream_feature_order = [] - - self.dns_service = 'xmpp-client' - - #TODO: Use stream state here - self.authenticated = False - self.sessionstarted = False - self.bound = False - self.bindfail = False - - self.add_event_handler('connected', self._reset_connection_state) - self.add_event_handler('session_bind', self._handle_session_bind) - self.add_event_handler('roster_update', self._handle_roster) - - self.register_stanza(StreamFeatures) - - self.register_handler( - Callback('Stream Features', - MatchXPath('{%s}features' % self.stream_ns), - self._handle_stream_features)) - self.register_handler( - Callback('Roster Update', - StanzaPath('iq@type=set/roster'), - lambda iq: self.event('roster_update', iq))) - - # Setup default stream features - self.register_plugin('feature_starttls') - self.register_plugin('feature_bind') - self.register_plugin('feature_session') - self.register_plugin('feature_rosterver') - self.register_plugin('feature_preapproval') - self.register_plugin('feature_mechanisms') - - if sasl_mech: - self['feature_mechanisms'].use_mech = sasl_mech - - @property - def password(self): - return self.credentials.get('password', '') - - @password.setter - def password(self, value): - self.credentials['password'] = value - - def connect(self, address=tuple(), reattempt=True, - use_tls=True, use_ssl=False): - """Connect to the XMPP server. - - When no address is given, a SRV lookup for the server will - be attempted. If that fails, the server user in the JID - will be used. - - :param address: A tuple containing the server's host and port. - :param reattempt: If ``True``, repeat attempting to connect if an - error occurs. Defaults to ``True``. - :param use_tls: Indicates if TLS should be used for the - connection. Defaults to ``True``. - :param use_ssl: Indicates if the older SSL connection method - should be used. Defaults to ``False``. - """ - self.session_started_event.clear() - - # If an address was provided, disable using DNS SRV lookup; - # otherwise, use the domain from the client JID with the standard - # XMPP client port and allow SRV lookup. - if address: - self.dns_service = None - else: - address = (self.boundjid.host, 5222) - self.dns_service = 'xmpp-client' - - return XMLStream.connect(self, address[0], address[1], - use_tls=use_tls, use_ssl=use_ssl, - reattempt=reattempt) - - def register_feature(self, name, handler, restart=False, order=5000): - """Register a stream feature handler. - - :param name: The name of the stream feature. - :param handler: The function to execute if the feature is received. - :param restart: Indicates if feature processing should halt with - this feature. Defaults to ``False``. - :param order: The relative ordering in which the feature should - be negotiated. Lower values will be attempted - earlier when available. - """ - self._stream_feature_handlers[name] = (handler, restart) - self._stream_feature_order.append((order, name)) - self._stream_feature_order.sort() - - def unregister_feature(self, name, order): - if name in self._stream_feature_handlers: - del self._stream_feature_handlers[name] - self._stream_feature_order.remove((order, name)) - self._stream_feature_order.sort() - - def update_roster(self, jid, **kwargs): - """Add or change a roster item. - - :param jid: The JID of the entry to modify. - :param name: The user's nickname for this JID. - :param subscription: The subscription status. May be one of - ``'to'``, ``'from'``, ``'both'``, or - ``'none'``. If set to ``'remove'``, - the entry will be deleted. - :param groups: The roster groups that contain this item. - :param block: Specify if the roster request will block - until a response is received, or a timeout - occurs. Defaults to ``True``. - :param timeout: The length of time (in seconds) to wait - for a response before continuing if blocking - is used. Defaults to - :attr:`~sleekxmpp.xmlstream.xmlstream.XMLStream.response_timeout`. - :param callback: Optional reference to a stream handler function. - Will be executed when the roster is received. - Implies ``block=False``. - """ - current = self.client_roster[jid] - - name = kwargs.get('name', current['name']) - subscription = kwargs.get('subscription', current['subscription']) - groups = kwargs.get('groups', current['groups']) - - block = kwargs.get('block', True) - timeout = kwargs.get('timeout', None) - callback = kwargs.get('callback', None) - - return self.client_roster.update(jid, name, subscription, groups, - block, timeout, callback) - - def del_roster_item(self, jid): - """Remove an item from the roster. - - This is done by setting its subscription status to ``'remove'``. - - :param jid: The JID of the item to remove. - """ - return self.client_roster.remove(jid) - - def get_roster(self, block=True, timeout=None, callback=None): - """Request the roster from the server. - - :param block: Specify if the roster request will block until a - response is received, or a timeout occurs. - Defaults to ``True``. - :param timeout: The length of time (in seconds) to wait for a response - before continuing if blocking is used. - Defaults to - :attr:`~sleekxmpp.xmlstream.xmlstream.XMLStream.response_timeout`. - :param callback: Optional reference to a stream handler function. Will - be executed when the roster is received. - Implies ``block=False``. - """ - iq = self.Iq() - iq['type'] = 'get' - iq.enable('roster') - if 'rosterver' in self.features: - iq['roster']['ver'] = self.client_roster.version - - - if not block or callback is not None: - block = False - if callback is None: - callback = lambda resp: self.event('roster_update', resp) - else: - orig_cb = callback - def wrapped(resp): - self.event('roster_update', resp) - orig_cb(resp) - callback = wrapped - - response = iq.send(block, timeout, callback) - - if block: - self.event('roster_update', response) - return response - - def _reset_connection_state(self, event=None): - #TODO: Use stream state here - self.authenticated = False - self.sessionstarted = False - self.bound = False - self.bindfail = False - self.features = set() - - def _handle_stream_features(self, features): - """Process the received stream features. - - :param features: The features stanza. - """ - for order, name in self._stream_feature_order: - if name in features['features']: - handler, restart = self._stream_feature_handlers[name] - if handler(features) and restart: - # Don't continue if the feature requires - # restarting the XML stream. - return True - log.debug('Finished processing stream features.') - self.event('stream_negotiated') - - def _handle_roster(self, iq): - """Update the roster after receiving a roster stanza. - - :param iq: The roster stanza. - """ - if iq['type'] == 'set': - if iq['from'].bare and iq['from'].bare != self.boundjid.bare: - raise XMPPError(condition='service-unavailable') - - roster = self.client_roster - if iq['roster']['ver']: - roster.version = iq['roster']['ver'] - items = iq['roster']['items'] - - valid_subscriptions = ('to', 'from', 'both', 'none', 'remove') - for jid, item in items.items(): - if item['subscription'] in valid_subscriptions: - roster[jid]['name'] = item['name'] - roster[jid]['groups'] = item['groups'] - roster[jid]['from'] = item['subscription'] in ('from', 'both') - roster[jid]['to'] = item['subscription'] in ('to', 'both') - roster[jid]['pending_out'] = (item['ask'] == 'subscribe') - - roster[jid].save(remove=(item['subscription'] == 'remove')) - - if iq['type'] == 'set': - resp = self.Iq(stype='result', - sto=iq['from'], - sid=iq['id']) - resp.enable('roster') - resp.send() - - def _handle_session_bind(self, jid): - """Set the client roster to the JID set by the server. - - :param :class:`sleekxmpp.xmlstream.jid.JID` jid: The bound JID as - dictated by the server. The same as :attr:`boundjid`. - """ - self.client_roster = self.roster[jid] - - -# To comply with PEP8, method names now use underscores. -# Deprecated method names are re-mapped for backwards compatibility. -ClientXMPP.updateRoster = ClientXMPP.update_roster -ClientXMPP.delRosterItem = ClientXMPP.del_roster_item -ClientXMPP.getRoster = ClientXMPP.get_roster -ClientXMPP.registerFeature = ClientXMPP.register_feature diff --git a/sleekxmpp/componentxmpp.py b/sleekxmpp/componentxmpp.py deleted file mode 100644 index bac455e2..00000000 --- a/sleekxmpp/componentxmpp.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- coding: utf-8 -*- -""" - sleekxmpp.clientxmpp - ~~~~~~~~~~~~~~~~~~~~ - - This module provides XMPP functionality that - is specific to external server component connections. - - Part of SleekXMPP: The Sleek XMPP Library - - :copyright: (c) 2011 Nathanael C. Fritz - :license: MIT, see LICENSE for more details -""" - -from __future__ import absolute_import - -import logging -import sys -import hashlib - -from sleekxmpp.basexmpp import BaseXMPP -from sleekxmpp.xmlstream import XMLStream -from sleekxmpp.xmlstream import ET -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.xmlstream.handler import Callback - - -log = logging.getLogger(__name__) - - -class ComponentXMPP(BaseXMPP): - - """ - SleekXMPP's basic XMPP server component. - - Use only for good, not for evil. - - :param jid: The JID of the component. - :param secret: The secret or password for the component. - :param host: The server accepting the component. - :param port: The port used to connect to the server. - :param plugin_config: A dictionary of plugin configurations. - :param plugin_whitelist: A list of approved plugins that - will be loaded when calling - :meth:`~sleekxmpp.basexmpp.BaseXMPP.register_plugins()`. - :param use_jc_ns: Indicates if the ``'jabber:client'`` namespace - should be used instead of the standard - ``'jabber:component:accept'`` namespace. - Defaults to ``False``. - """ - - def __init__(self, jid, secret, host=None, port=None, - plugin_config={}, plugin_whitelist=[], use_jc_ns=False): - if use_jc_ns: - default_ns = 'jabber:client' - else: - default_ns = 'jabber:component:accept' - BaseXMPP.__init__(self, jid, default_ns) - - self.auto_authorize = None - self.stream_header = "" % ( - 'xmlns="jabber:component:accept"', - 'xmlns:stream="%s"' % self.stream_ns, - jid) - self.stream_footer = "" - self.server_host = host - self.server_port = port - self.secret = secret - - self.plugin_config = plugin_config - self.plugin_whitelist = plugin_whitelist - self.is_component = True - - self.register_handler( - Callback('Handshake', - MatchXPath('{jabber:component:accept}handshake'), - self._handle_handshake)) - self.add_event_handler('presence_probe', - self._handle_probe) - - def connect(self, host=None, port=None, use_ssl=False, - use_tls=False, reattempt=True): - """Connect to the server. - - Setting ``reattempt`` to ``True`` will cause connection attempts to - be made every second until a successful connection is established. - - :param host: The name of the desired server for the connection. - Defaults to :attr:`server_host`. - :param port: Port to connect to on the server. - Defauts to :attr:`server_port`. - :param use_ssl: Flag indicating if SSL should be used by connecting - directly to a port using SSL. - :param use_tls: Flag indicating if TLS should be used, allowing for - connecting to a port without using SSL immediately and - later upgrading the connection. - :param reattempt: Flag indicating if the socket should reconnect - after disconnections. - """ - if host is None: - host = self.server_host - if port is None: - port = self.server_port - - self.server_name = self.boundjid.host - - if use_tls: - log.info("XEP-0114 components can not use TLS") - - log.debug("Connecting to %s:%s", host, port) - return XMLStream.connect(self, host=host, port=port, - use_ssl=use_ssl, - use_tls=False, - reattempt=reattempt) - - def incoming_filter(self, xml): - """ - Pre-process incoming XML stanzas by converting any - ``'jabber:client'`` namespaced elements to the component's - default namespace. - - :param xml: The XML stanza to pre-process. - """ - if xml.tag.startswith('{jabber:client}'): - xml.tag = xml.tag.replace('jabber:client', self.default_ns) - return xml - - def start_stream_handler(self, xml): - """ - Once the streams are established, attempt to handshake - with the server to be accepted as a component. - - :param xml: The incoming stream's root element. - """ - BaseXMPP.start_stream_handler(self, xml) - - # Construct a hash of the stream ID and the component secret. - sid = xml.get('id', '') - pre_hash = '%s%s' % (sid, self.secret) - if sys.version_info >= (3, 0): - # Handle Unicode byte encoding in Python 3. - pre_hash = bytes(pre_hash, 'utf-8') - - handshake = ET.Element('{jabber:component:accept}handshake') - handshake.text = hashlib.sha1(pre_hash).hexdigest().lower() - self.send_xml(handshake, now=True) - - def _handle_handshake(self, xml): - """The handshake has been accepted. - - :param xml: The reply handshake stanza. - """ - self.session_bind_event.set() - self.session_started_event.set() - self.event('session_bind', self.boundjid, direct=True) - self.event('session_start') - - def _handle_probe(self, pres): - self.roster[pres['to']][pres['from']].handle_probe(pres) diff --git a/sleekxmpp/exceptions.py b/sleekxmpp/exceptions.py deleted file mode 100644 index 8a2aa75c..00000000 --- a/sleekxmpp/exceptions.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -""" - sleekxmpp.exceptions - ~~~~~~~~~~~~~~~~~~~~ - - Part of SleekXMPP: The Sleek XMPP Library - - :copyright: (c) 2011 Nathanael C. Fritz - :license: MIT, see LICENSE for more details -""" - - -class XMPPError(Exception): - - """ - A generic exception that may be raised while processing an XMPP stanza - to indicate that an error response stanza should be sent. - - The exception method for stanza objects extending - :class:`~sleekxmpp.stanza.rootstanza.RootStanza` will create an error - stanza and initialize any additional substanzas using the extension - information included in the exception. - - Meant for use in SleekXMPP plugins and applications using SleekXMPP. - - Extension information can be included to add additional XML elements - to the generated error stanza. - - :param condition: The XMPP defined error condition. - Defaults to ``'undefined-condition'``. - :param text: Human readable text describing the error. - :param etype: The XMPP error type, such as ``'cancel'`` or ``'modify'``. - Defaults to ``'cancel'``. - :param extension: Tag name of the extension's XML content. - :param extension_ns: XML namespace of the extensions' XML content. - :param extension_args: Content and attributes for the extension - element. Same as the additional arguments to - the :class:`~xml.etree.ElementTree.Element` - constructor. - :param clear: Indicates if the stanza's contents should be - removed before replying with an error. - Defaults to ``True``. - """ - - def __init__(self, condition='undefined-condition', text='', - etype='cancel', extension=None, extension_ns=None, - extension_args=None, clear=True): - if extension_args is None: - extension_args = {} - - self.condition = condition - self.text = text - self.etype = etype - self.clear = clear - self.extension = extension - self.extension_ns = extension_ns - self.extension_args = extension_args - - -class IqTimeout(XMPPError): - - """ - An exception which indicates that an IQ request response has not been - received within the alloted time window. - """ - - def __init__(self, iq): - super(IqTimeout, self).__init__( - condition='remote-server-timeout', - etype='cancel') - - #: The :class:`~sleekxmpp.stanza.iq.Iq` stanza whose response - #: did not arrive before the timeout expired. - self.iq = iq - - -class IqError(XMPPError): - - """ - An exception raised when an Iq stanza of type 'error' is received - after making a blocking send call. - """ - - def __init__(self, iq): - super(IqError, self).__init__( - condition=iq['error']['condition'], - text=iq['error']['text'], - etype=iq['error']['type']) - - #: The :class:`~sleekxmpp.stanza.iq.Iq` error result stanza. - self.iq = iq diff --git a/sleekxmpp/features/__init__.py b/sleekxmpp/features/__init__.py deleted file mode 100644 index 869de7e9..00000000 --- a/sleekxmpp/features/__init__.py +++ /dev/null @@ -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. -""" - -__all__ = [ - 'feature_starttls', - 'feature_mechanisms', - 'feature_bind', - 'feature_session', - 'feature_rosterver', - 'feature_preapproval' -] diff --git a/sleekxmpp/features/feature_bind/__init__.py b/sleekxmpp/features/feature_bind/__init__.py deleted file mode 100644 index 9e0831dd..00000000 --- a/sleekxmpp/features/feature_bind/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/features/feature_bind/bind.py b/sleekxmpp/features/feature_bind/bind.py deleted file mode 100644 index ee4c1e9b..00000000 --- a/sleekxmpp/features/feature_bind/bind.py +++ /dev/null @@ -1,65 +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. -""" - -import logging - -from sleekxmpp.jid import JID -from sleekxmpp.stanza import Iq, StreamFeatures -from sleekxmpp.features.feature_bind import stanza -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin - - -log = logging.getLogger(__name__) - - -class FeatureBind(BasePlugin): - - name = 'feature_bind' - description = 'RFC 6120: Stream Feature: Resource Binding' - dependencies = set() - stanza = stanza - - def plugin_init(self): - self.xmpp.register_feature('bind', - self._handle_bind_resource, - restart=False, - order=10000) - - register_stanza_plugin(Iq, stanza.Bind) - register_stanza_plugin(StreamFeatures, stanza.Bind) - - def _handle_bind_resource(self, features): - """ - Handle requesting a specific resource. - - Arguments: - features -- The stream features stanza. - """ - log.debug("Requesting resource: %s", self.xmpp.requested_jid.resource) - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq.enable('bind') - if self.xmpp.requested_jid.resource: - iq['bind']['resource'] = self.xmpp.requested_jid.resource - response = iq.send(now=True) - - self.xmpp.boundjid = JID(response['bind']['jid'], cache_lock=True) - self.xmpp.bound = True - self.xmpp.event('session_bind', self.xmpp.boundjid, direct=True) - self.xmpp.session_bind_event.set() - - self.xmpp.features.add('bind') - - log.info("JID set to: %s", self.xmpp.boundjid.full) - - if 'session' not in features['features']: - log.debug("Established Session") - self.xmpp.sessionstarted = True - self.xmpp.session_started_event.set() - self.xmpp.event('session_start') diff --git a/sleekxmpp/features/feature_bind/stanza.py b/sleekxmpp/features/feature_bind/stanza.py deleted file mode 100644 index 8ce7536f..00000000 --- a/sleekxmpp/features/feature_bind/stanza.py +++ /dev/null @@ -1,21 +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.xmlstream import ElementBase - - -class Bind(ElementBase): - - """ - """ - - name = 'bind' - namespace = 'urn:ietf:params:xml:ns:xmpp-bind' - interfaces = set(('resource', 'jid')) - sub_interfaces = interfaces - plugin_attrib = 'bind' diff --git a/sleekxmpp/features/feature_mechanisms/__init__.py b/sleekxmpp/features/feature_mechanisms/__init__.py deleted file mode 100644 index 9f7611ed..00000000 --- a/sleekxmpp/features/feature_mechanisms/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/features/feature_mechanisms/mechanisms.py b/sleekxmpp/features/feature_mechanisms/mechanisms.py deleted file mode 100644 index 17ad5ed0..00000000 --- a/sleekxmpp/features/feature_mechanisms/mechanisms.py +++ /dev/null @@ -1,244 +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. -""" - -import ssl -import logging - -from sleekxmpp.util import sasl -from sleekxmpp.util.stringprep_profiles import StringPrepError -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import RestartStream, register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.features.feature_mechanisms import stanza - - -log = logging.getLogger(__name__) - - -class FeatureMechanisms(BasePlugin): - - name = 'feature_mechanisms' - description = 'RFC 6120: Stream Feature: SASL' - dependencies = set() - stanza = stanza - default_config = { - 'use_mech': None, - 'use_mechs': None, - 'min_mech': None, - 'sasl_callback': None, - 'security_callback': None, - 'encrypted_plain': True, - 'unencrypted_plain': False, - 'unencrypted_digest': False, - 'unencrypted_cram': False, - 'unencrypted_scram': True, - 'order': 100 - } - - def plugin_init(self): - if self.sasl_callback is None: - self.sasl_callback = self._default_credentials - - if self.security_callback is None: - self.security_callback = self._default_security - - creds = self.sasl_callback(set(['username']), set()) - if not self.use_mech and not creds['username']: - self.use_mech = 'ANONYMOUS' - - self.mech = None - self.mech_list = set() - self.attempted_mechs = set() - - register_stanza_plugin(StreamFeatures, stanza.Mechanisms) - - self.xmpp.register_stanza(stanza.Success) - self.xmpp.register_stanza(stanza.Failure) - self.xmpp.register_stanza(stanza.Auth) - self.xmpp.register_stanza(stanza.Challenge) - self.xmpp.register_stanza(stanza.Response) - self.xmpp.register_stanza(stanza.Abort) - - self.xmpp.register_handler( - Callback('SASL Success', - MatchXPath(stanza.Success.tag_name()), - self._handle_success, - instream=True)) - self.xmpp.register_handler( - Callback('SASL Failure', - MatchXPath(stanza.Failure.tag_name()), - self._handle_fail, - instream=True)) - self.xmpp.register_handler( - Callback('SASL Challenge', - MatchXPath(stanza.Challenge.tag_name()), - self._handle_challenge)) - - self.xmpp.register_feature('mechanisms', - self._handle_sasl_auth, - restart=True, - order=self.order) - - def _default_credentials(self, required_values, optional_values): - creds = self.xmpp.credentials - result = {} - values = required_values.union(optional_values) - for value in values: - if value == 'username': - result[value] = creds.get('username', self.xmpp.requested_jid.user) - elif value == 'email': - jid = self.xmpp.requested_jid.bare - result[value] = creds.get('email', jid) - elif value == 'channel_binding': - if hasattr(self.xmpp.socket, 'get_channel_binding'): - result[value] = self.xmpp.socket.get_channel_binding() - else: - log.debug("Channel binding not supported.") - log.debug("Use Python 3.3+ for channel binding and " + \ - "SCRAM-SHA-1-PLUS support") - result[value] = None - elif value == 'host': - result[value] = creds.get('host', self.xmpp.requested_jid.domain) - elif value == 'realm': - result[value] = creds.get('realm', self.xmpp.requested_jid.domain) - elif value == 'service-name': - result[value] = creds.get('service-name', self.xmpp._service_name) - elif value == 'service': - result[value] = creds.get('service', 'xmpp') - elif value in creds: - result[value] = creds[value] - return result - - def _default_security(self, values): - result = {} - for value in values: - if value == 'encrypted': - if 'starttls' in self.xmpp.features: - result[value] = True - elif isinstance(self.xmpp.socket, ssl.SSLSocket): - result[value] = True - else: - result[value] = False - else: - result[value] = self.config.get(value, False) - return result - - def _handle_sasl_auth(self, features): - """ - Handle authenticating using SASL. - - Arguments: - features -- The stream features stanza. - """ - if 'mechanisms' in self.xmpp.features: - # SASL authentication has already succeeded, but the - # server has incorrectly offered it again. - return False - - enforce_limit = False - limited_mechs = self.use_mechs - - if limited_mechs is None: - limited_mechs = set() - elif limited_mechs and not isinstance(limited_mechs, set): - limited_mechs = set(limited_mechs) - enforce_limit = True - - if self.use_mech: - limited_mechs.add(self.use_mech) - enforce_limit = True - - if enforce_limit: - self.use_mechs = limited_mechs - - self.mech_list = set(features['mechanisms']) - - return self._send_auth() - - def _send_auth(self): - mech_list = self.mech_list - self.attempted_mechs - try: - self.mech = sasl.choose(mech_list, - self.sasl_callback, - self.security_callback, - limit=self.use_mechs, - min_mech=self.min_mech) - except sasl.SASLNoAppropriateMechanism: - log.error("No appropriate login method.") - self.xmpp.event("no_auth", direct=True) - self.xmpp.event("failed_auth", direct=True) - self.attempted_mechs = set() - return self.xmpp.disconnect() - except StringPrepError: - log.exception("A credential value did not pass SASLprep.") - self.xmpp.disconnect() - - resp = stanza.Auth(self.xmpp) - resp['mechanism'] = self.mech.name - try: - resp['value'] = self.mech.process() - except sasl.SASLCancelled: - self.attempted_mechs.add(self.mech.name) - self._send_auth() - except sasl.SASLFailed: - self.attempted_mechs.add(self.mech.name) - self._send_auth() - except sasl.SASLMutualAuthFailed: - log.error("Mutual authentication failed! " + \ - "A security breach is possible.") - self.attempted_mechs.add(self.mech.name) - self.xmpp.disconnect() - else: - resp.send(now=True) - - return True - - def _handle_challenge(self, stanza): - """SASL challenge received. Process and send response.""" - resp = self.stanza.Response(self.xmpp) - try: - resp['value'] = self.mech.process(stanza['value']) - except sasl.SASLCancelled: - self.stanza.Abort(self.xmpp).send() - except sasl.SASLFailed: - self.stanza.Abort(self.xmpp).send() - except sasl.SASLMutualAuthFailed: - log.error("Mutual authentication failed! " + \ - "A security breach is possible.") - self.attempted_mechs.add(self.mech.name) - self.xmpp.disconnect() - else: - if resp.get_value() == '': - resp.del_value() - resp.send(now=True) - - def _handle_success(self, stanza): - """SASL authentication succeeded. Restart the stream.""" - try: - final = self.mech.process(stanza['value']) - except sasl.SASLMutualAuthFailed: - log.error("Mutual authentication failed! " + \ - "A security breach is possible.") - self.attempted_mechs.add(self.mech.name) - self.xmpp.disconnect() - else: - self.attempted_mechs = set() - self.xmpp.authenticated = True - self.xmpp.features.add('mechanisms') - self.xmpp.event('auth_success', stanza, direct=True) - raise RestartStream() - - def _handle_fail(self, stanza): - """SASL authentication failed. Disconnect and shutdown.""" - self.attempted_mechs.add(self.mech.name) - log.info("Authentication failed: %s", stanza['condition']) - self.xmpp.event("failed_auth", stanza, direct=True) - self._send_auth() - return True diff --git a/sleekxmpp/features/feature_mechanisms/stanza/__init__.py b/sleekxmpp/features/feature_mechanisms/stanza/__init__.py deleted file mode 100644 index 38991d89..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/features/feature_mechanisms/stanza/abort.py b/sleekxmpp/features/feature_mechanisms/stanza/abort.py deleted file mode 100644 index aaca348d..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/abort.py +++ /dev/null @@ -1,24 +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.xmlstream import StanzaBase - - -class Abort(StanzaBase): - - """ - """ - - name = 'abort' - namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' - interfaces = set() - plugin_attrib = name - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() diff --git a/sleekxmpp/features/feature_mechanisms/stanza/auth.py b/sleekxmpp/features/feature_mechanisms/stanza/auth.py deleted file mode 100644 index 6b6f85a3..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/auth.py +++ /dev/null @@ -1,49 +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. -""" - -import base64 - -from sleekxmpp.util import bytes -from sleekxmpp.xmlstream import StanzaBase - - -class Auth(StanzaBase): - - """ - """ - - name = 'auth' - namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' - interfaces = set(('mechanism', 'value')) - plugin_attrib = name - - #: Some SASL mechs require sending values as is, - #: without converting base64. - plain_mechs = set(['X-MESSENGER-OAUTH2']) - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_value(self): - if not self['mechanism'] in self.plain_mechs: - return base64.b64decode(bytes(self.xml.text)) - else: - return self.xml.text - - def set_value(self, values): - if not self['mechanism'] in self.plain_mechs: - if values: - self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') - elif values == b'': - self.xml.text = '=' - else: - self.xml.text = bytes(values).decode('utf-8') - - def del_value(self): - self.xml.text = '' diff --git a/sleekxmpp/features/feature_mechanisms/stanza/challenge.py b/sleekxmpp/features/feature_mechanisms/stanza/challenge.py deleted file mode 100644 index 24290281..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/challenge.py +++ /dev/null @@ -1,39 +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. -""" - -import base64 - -from sleekxmpp.util import bytes -from sleekxmpp.xmlstream import StanzaBase - - -class Challenge(StanzaBase): - - """ - """ - - name = 'challenge' - namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' - interfaces = set(('value',)) - plugin_attrib = name - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_value(self): - return base64.b64decode(bytes(self.xml.text)) - - def set_value(self, values): - if values: - self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') - else: - self.xml.text = '=' - - def del_value(self): - self.xml.text = '' diff --git a/sleekxmpp/features/feature_mechanisms/stanza/failure.py b/sleekxmpp/features/feature_mechanisms/stanza/failure.py deleted file mode 100644 index b9f32605..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/failure.py +++ /dev/null @@ -1,76 +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.xmlstream import StanzaBase, ET - - -class Failure(StanzaBase): - - """ - """ - - name = 'failure' - namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' - interfaces = set(('condition', 'text')) - plugin_attrib = name - sub_interfaces = set(('text',)) - conditions = set(('aborted', 'account-disabled', 'credentials-expired', - 'encryption-required', 'incorrect-encoding', 'invalid-authzid', - 'invalid-mechanism', 'malformed-request', 'mechansism-too-weak', - 'not-authorized', 'temporary-auth-failure')) - - def setup(self, xml=None): - """ - Populate the stanza object using an optional XML object. - - Overrides ElementBase.setup. - - Sets a default error type and condition, and changes the - parent stanza's type to 'error'. - - Arguments: - xml -- Use an existing XML object for the stanza's values. - """ - # StanzaBase overrides self.namespace - self.namespace = Failure.namespace - - if StanzaBase.setup(self, xml): - #If we had to generate XML then set default values. - self['condition'] = 'not-authorized' - - self.xml.tag = self.tag_name() - - def get_condition(self): - """Return the condition element's name.""" - for child in self.xml: - if "{%s}" % self.namespace in child.tag: - cond = child.tag.split('}', 1)[-1] - if cond in self.conditions: - return cond - return 'not-authorized' - - def set_condition(self, value): - """ - Set the tag name of the condition element. - - Arguments: - value -- The tag name of the condition element. - """ - if value in self.conditions: - del self['condition'] - self.xml.append(ET.Element("{%s}%s" % (self.namespace, value))) - return self - - def del_condition(self): - """Remove the condition element.""" - for child in self.xml: - if "{%s}" % self.condition_ns in child.tag: - tag = child.tag.split('}', 1)[-1] - if tag in self.conditions: - self.xml.remove(child) - return self diff --git a/sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py b/sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py deleted file mode 100644 index bbd56813..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py +++ /dev/null @@ -1,53 +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.xmlstream import ElementBase, ET - - -class Mechanisms(ElementBase): - - """ - """ - - name = 'mechanisms' - namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' - interfaces = set(('mechanisms', 'required')) - plugin_attrib = name - is_extension = True - - def get_required(self): - """ - """ - return True - - def get_mechanisms(self): - """ - """ - results = [] - mechs = self.findall('{%s}mechanism' % self.namespace) - if mechs: - for mech in mechs: - results.append(mech.text) - return results - - def set_mechanisms(self, values): - """ - """ - self.del_mechanisms() - for val in values: - mech = ET.Element('{%s}mechanism' % self.namespace) - mech.text = val - self.append(mech) - - def del_mechanisms(self): - """ - """ - mechs = self.findall('{%s}mechanism' % self.namespace) - if mechs: - for mech in mechs: - self.xml.remove(mech) diff --git a/sleekxmpp/features/feature_mechanisms/stanza/response.py b/sleekxmpp/features/feature_mechanisms/stanza/response.py deleted file mode 100644 index ca7624f1..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/response.py +++ /dev/null @@ -1,39 +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. -""" - -import base64 - -from sleekxmpp.util import bytes -from sleekxmpp.xmlstream import StanzaBase - - -class Response(StanzaBase): - - """ - """ - - name = 'response' - namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' - interfaces = set(('value',)) - plugin_attrib = name - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_value(self): - return base64.b64decode(bytes(self.xml.text)) - - def set_value(self, values): - if values: - self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') - else: - self.xml.text = '=' - - def del_value(self): - self.xml.text = '' diff --git a/sleekxmpp/features/feature_mechanisms/stanza/success.py b/sleekxmpp/features/feature_mechanisms/stanza/success.py deleted file mode 100644 index 7a4eab8e..00000000 --- a/sleekxmpp/features/feature_mechanisms/stanza/success.py +++ /dev/null @@ -1,38 +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. -""" - -import base64 - -from sleekxmpp.util import bytes -from sleekxmpp.xmlstream import StanzaBase - -class Success(StanzaBase): - - """ - """ - - name = 'success' - namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' - interfaces = set(['value']) - plugin_attrib = name - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_value(self): - return base64.b64decode(bytes(self.xml.text)) - - def set_value(self, values): - if values: - self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') - else: - self.xml.text = '=' - - def del_value(self): - self.xml.text = '' diff --git a/sleekxmpp/features/feature_preapproval/__init__.py b/sleekxmpp/features/feature_preapproval/__init__.py deleted file mode 100644 index ae8b6b70..00000000 --- a/sleekxmpp/features/feature_preapproval/__init__.py +++ /dev/null @@ -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) diff --git a/sleekxmpp/features/feature_preapproval/preapproval.py b/sleekxmpp/features/feature_preapproval/preapproval.py deleted file mode 100644 index c7106ed3..00000000 --- a/sleekxmpp/features/feature_preapproval/preapproval.py +++ /dev/null @@ -1,42 +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. -""" - -import logging - -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.features.feature_preapproval import stanza -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.base import BasePlugin - - -log = logging.getLogger(__name__) - - -class FeaturePreApproval(BasePlugin): - - name = 'feature_preapproval' - description = 'RFC 6121: Stream Feature: Subscription Pre-Approval' - dependences = set() - stanza = stanza - - def plugin_init(self): - self.xmpp.register_feature('preapproval', - self._handle_preapproval, - restart=False, - order=9001) - - register_stanza_plugin(StreamFeatures, stanza.PreApproval) - - def _handle_preapproval(self, features): - """Save notice that the server support subscription pre-approvals. - - Arguments: - features -- The stream features stanza. - """ - log.debug("Server supports subscription pre-approvals.") - self.xmpp.features.add('preapproval') diff --git a/sleekxmpp/features/feature_preapproval/stanza.py b/sleekxmpp/features/feature_preapproval/stanza.py deleted file mode 100644 index 4a59bd16..00000000 --- a/sleekxmpp/features/feature_preapproval/stanza.py +++ /dev/null @@ -1,17 +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.xmlstream import ElementBase - - -class PreApproval(ElementBase): - - name = 'sub' - namespace = 'urn:xmpp:features:pre-approval' - interfaces = set() - plugin_attrib = 'preapproval' diff --git a/sleekxmpp/features/feature_rosterver/__init__.py b/sleekxmpp/features/feature_rosterver/__init__.py deleted file mode 100644 index 33bbf416..00000000 --- a/sleekxmpp/features/feature_rosterver/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/features/feature_rosterver/rosterver.py b/sleekxmpp/features/feature_rosterver/rosterver.py deleted file mode 100644 index 2991f587..00000000 --- a/sleekxmpp/features/feature_rosterver/rosterver.py +++ /dev/null @@ -1,42 +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. -""" - -import logging - -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.features.feature_rosterver import stanza -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.base import BasePlugin - - -log = logging.getLogger(__name__) - - -class FeatureRosterVer(BasePlugin): - - name = 'feature_rosterver' - description = 'RFC 6121: Stream Feature: Roster Versioning' - dependences = set() - stanza = stanza - - def plugin_init(self): - self.xmpp.register_feature('rosterver', - self._handle_rosterver, - restart=False, - order=9000) - - register_stanza_plugin(StreamFeatures, stanza.RosterVer) - - def _handle_rosterver(self, features): - """Enable using roster versioning. - - Arguments: - features -- The stream features stanza. - """ - log.debug("Enabling roster versioning.") - self.xmpp.features.add('rosterver') diff --git a/sleekxmpp/features/feature_rosterver/stanza.py b/sleekxmpp/features/feature_rosterver/stanza.py deleted file mode 100644 index 025872fa..00000000 --- a/sleekxmpp/features/feature_rosterver/stanza.py +++ /dev/null @@ -1,17 +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.xmlstream import ElementBase - - -class RosterVer(ElementBase): - - name = 'ver' - namespace = 'urn:xmpp:features:rosterver' - interfaces = set() - plugin_attrib = 'rosterver' diff --git a/sleekxmpp/features/feature_session/__init__.py b/sleekxmpp/features/feature_session/__init__.py deleted file mode 100644 index 28bb3f77..00000000 --- a/sleekxmpp/features/feature_session/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/features/feature_session/session.py b/sleekxmpp/features/feature_session/session.py deleted file mode 100644 index ceadd5f3..00000000 --- a/sleekxmpp/features/feature_session/session.py +++ /dev/null @@ -1,54 +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. -""" - -import logging - -from sleekxmpp.stanza import Iq, StreamFeatures -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin - -from sleekxmpp.features.feature_session import stanza - - -log = logging.getLogger(__name__) - - -class FeatureSession(BasePlugin): - - name = 'feature_session' - description = 'RFC 3920: Stream Feature: Start Session' - dependencies = set() - stanza = stanza - - def plugin_init(self): - self.xmpp.register_feature('session', - self._handle_start_session, - restart=False, - order=10001) - - register_stanza_plugin(Iq, stanza.Session) - register_stanza_plugin(StreamFeatures, stanza.Session) - - def _handle_start_session(self, features): - """ - Handle the start of the session. - - Arguments: - feature -- The stream features element. - """ - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq.enable('session') - iq.send(now=True) - - self.xmpp.features.add('session') - - log.debug("Established Session") - self.xmpp.sessionstarted = True - self.xmpp.session_started_event.set() - self.xmpp.event('session_start') diff --git a/sleekxmpp/features/feature_session/stanza.py b/sleekxmpp/features/feature_session/stanza.py deleted file mode 100644 index 94e949ee..00000000 --- a/sleekxmpp/features/feature_session/stanza.py +++ /dev/null @@ -1,20 +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.xmlstream import ElementBase - - -class Session(ElementBase): - - """ - """ - - name = 'session' - namespace = 'urn:ietf:params:xml:ns:xmpp-session' - interfaces = set() - plugin_attrib = 'session' diff --git a/sleekxmpp/features/feature_starttls/__init__.py b/sleekxmpp/features/feature_starttls/__init__.py deleted file mode 100644 index 68697ce5..00000000 --- a/sleekxmpp/features/feature_starttls/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/features/feature_starttls/stanza.py b/sleekxmpp/features/feature_starttls/stanza.py deleted file mode 100644 index b968e134..00000000 --- a/sleekxmpp/features/feature_starttls/stanza.py +++ /dev/null @@ -1,45 +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.xmlstream import StanzaBase, ElementBase - - -class STARTTLS(ElementBase): - - """ - """ - - name = 'starttls' - namespace = 'urn:ietf:params:xml:ns:xmpp-tls' - interfaces = set(('required',)) - plugin_attrib = name - - def get_required(self): - """ - """ - return True - - -class Proceed(StanzaBase): - - """ - """ - - name = 'proceed' - namespace = 'urn:ietf:params:xml:ns:xmpp-tls' - interfaces = set() - - -class Failure(StanzaBase): - - """ - """ - - name = 'failure' - namespace = 'urn:ietf:params:xml:ns:xmpp-tls' - interfaces = set() diff --git a/sleekxmpp/features/feature_starttls/starttls.py b/sleekxmpp/features/feature_starttls/starttls.py deleted file mode 100644 index eb5eee1d..00000000 --- a/sleekxmpp/features/feature_starttls/starttls.py +++ /dev/null @@ -1,66 +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. -""" - -import logging - -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import RestartStream, register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.features.feature_starttls import stanza - - -log = logging.getLogger(__name__) - - -class FeatureSTARTTLS(BasePlugin): - - name = 'feature_starttls' - description = 'RFC 6120: Stream Feature: STARTTLS' - dependencies = set() - stanza = stanza - - def plugin_init(self): - self.xmpp.register_handler( - Callback('STARTTLS Proceed', - MatchXPath(stanza.Proceed.tag_name()), - self._handle_starttls_proceed, - instream=True)) - self.xmpp.register_feature('starttls', - self._handle_starttls, - restart=True, - order=self.config.get('order', 0)) - - self.xmpp.register_stanza(stanza.Proceed) - self.xmpp.register_stanza(stanza.Failure) - register_stanza_plugin(StreamFeatures, stanza.STARTTLS) - - def _handle_starttls(self, features): - """ - Handle notification that the server supports TLS. - - Arguments: - features -- The stream:features element. - """ - if 'starttls' in self.xmpp.features: - # We have already negotiated TLS, but the server is - # offering it again, against spec. - return False - elif not self.xmpp.use_tls: - return False - else: - self.xmpp.send(features['starttls'], now=True) - return True - - def _handle_starttls_proceed(self, proceed): - """Restart the XML stream when TLS is accepted.""" - log.debug("Starting TLS") - if self.xmpp.start_tls(): - self.xmpp.features.add('starttls') - raise RestartStream() diff --git a/sleekxmpp/jid.py b/sleekxmpp/jid.py deleted file mode 100644 index ac5ba30d..00000000 --- a/sleekxmpp/jid.py +++ /dev/null @@ -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)) diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py deleted file mode 100644 index 951f31eb..00000000 --- a/sleekxmpp/plugins/__init__.py +++ /dev/null @@ -1,86 +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. -""" - -from sleekxmpp.plugins.base import PluginManager, PluginNotFound, BasePlugin -from sleekxmpp.plugins.base import register_plugin, load_plugin - - -__all__ = [ - # XEPS - 'xep_0004', # Data Forms - 'xep_0009', # Jabber-RPC - 'xep_0012', # Last Activity - 'xep_0013', # Flexible Offline Message Retrieval - 'xep_0016', # Privacy Lists - 'xep_0020', # Feature Negotiation - 'xep_0027', # Current Jabber OpenPGP Usage - 'xep_0030', # Service Discovery - 'xep_0033', # Extended Stanza Addresses - 'xep_0045', # Multi-User Chat (Client) - 'xep_0047', # In-Band Bytestreams - 'xep_0048', # Bookmarks - 'xep_0049', # Private XML Storage - 'xep_0050', # Ad-hoc Commands - 'xep_0054', # vcard-temp - 'xep_0059', # Result Set Management - 'xep_0060', # Pubsub (Client) - 'xep_0065', # SOCKS5 Bytestreams - 'xep_0066', # Out of Band Data - 'xep_0071', # XHTML-IM - 'xep_0077', # In-Band Registration -# 'xep_0078', # Non-SASL auth. Don't automatically load - 'xep_0079', # Advanced Message Processing - 'xep_0080', # User Location - 'xep_0082', # XMPP Date and Time Profiles - 'xep_0084', # User Avatar - 'xep_0085', # Chat State Notifications - 'xep_0086', # Legacy Error Codes - 'xep_0091', # Legacy Delayed Delivery - 'xep_0092', # Software Version - 'xep_0106', # JID Escaping - 'xep_0107', # User Mood - 'xep_0108', # User Activity - 'xep_0115', # Entity Capabilities - 'xep_0118', # User Tune - 'xep_0128', # Extended Service Discovery - 'xep_0131', # Standard Headers and Internet Metadata - 'xep_0133', # Service Administration - 'xep_0152', # Reachability Addresses - 'xep_0153', # vCard-Based Avatars - 'xep_0163', # Personal Eventing Protocol - 'xep_0172', # User Nickname - 'xep_0184', # Message Receipts - 'xep_0186', # Invisible Command - 'xep_0191', # Blocking Command - 'xep_0196', # User Gaming - 'xep_0198', # Stream Management - 'xep_0199', # Ping - 'xep_0202', # Entity Time - 'xep_0203', # Delayed Delivery - 'xep_0221', # Data Forms Media Element - 'xep_0222', # Persistent Storage of Public Data via Pubsub - 'xep_0223', # Persistent Storage of Private Data via Pubsub - 'xep_0224', # Attention - 'xep_0231', # Bits of Binary - 'xep_0235', # OAuth Over XMPP - 'xep_0242', # XMPP Client Compliance 2009 - 'xep_0249', # Direct MUC Invitations - 'xep_0256', # Last Activity in Presence - 'xep_0257', # Client Certificate Management for SASL EXTERNAL - 'xep_0258', # Security Labels in XMPP - 'xep_0270', # XMPP Compliance Suites 2010 - 'xep_0279', # Server IP Check - 'xep_0280', # Message Carbons - 'xep_0297', # Stanza Forwarding - 'xep_0302', # XMPP Compliance Suites 2012 - 'xep_0308', # Last Message Correction - 'xep_0313', # Message Archive Management - 'xep_0319', # Last User Interaction in Presence - 'xep_0323', # IoT Systems Sensor Data - 'xep_0325', # IoT Systems Control -] diff --git a/sleekxmpp/plugins/base.py b/sleekxmpp/plugins/base.py deleted file mode 100644 index 67675908..00000000 --- a/sleekxmpp/plugins/base.py +++ /dev/null @@ -1,360 +0,0 @@ -# -*- encoding: utf-8 -*- - -""" - sleekxmpp.plugins.base - ~~~~~~~~~~~~~~~~~~~~~~ - - This module provides XMPP functionality that - is specific to client connections. - - Part of SleekXMPP: The Sleek XMPP Library - - :copyright: (c) 2012 Nathanael C. Fritz - :license: MIT, see LICENSE for more details -""" - -import sys -import copy -import logging -import threading - - -if sys.version_info >= (3, 0): - unicode = str - - -log = logging.getLogger(__name__) - - -#: Associate short string names of plugins with implementations. The -#: plugin names are based on the spec used by the plugin, such as -#: `'xep_0030'` for a plugin that implements XEP-0030. -PLUGIN_REGISTRY = {} - -#: In order to do cascading plugin disabling, reverse dependencies -#: must be tracked. -PLUGIN_DEPENDENTS = {} - -#: Only allow one thread to manipulate the plugin registry at a time. -REGISTRY_LOCK = threading.RLock() - - -class PluginNotFound(Exception): - """Raised if an unknown plugin is accessed.""" - - -def register_plugin(impl, name=None): - """Add a new plugin implementation to the registry. - - :param class impl: The plugin class. - - The implementation class must provide a :attr:`~BasePlugin.name` - value that will be used as a short name for enabling and disabling - the plugin. The name should be based on the specification used by - the plugin. For example, a plugin implementing XEP-0030 would be - named `'xep_0030'`. - """ - if name is None: - name = impl.name - with REGISTRY_LOCK: - PLUGIN_REGISTRY[name] = impl - if name not in PLUGIN_DEPENDENTS: - PLUGIN_DEPENDENTS[name] = set() - for dep in impl.dependencies: - if dep not in PLUGIN_DEPENDENTS: - PLUGIN_DEPENDENTS[dep] = set() - PLUGIN_DEPENDENTS[dep].add(name) - - -def load_plugin(name, module=None): - """Find and import a plugin module so that it can be registered. - - This function is called to import plugins that have selected for - enabling, but no matching registered plugin has been found. - - :param str name: The name of the plugin. It is expected that - plugins are in packages matching their name, - even though the plugin class name does not - have to match. - :param str module: The name of the base module to search - for the plugin. - """ - try: - if not module: - try: - module = 'sleekxmpp.plugins.%s' % name - __import__(module) - mod = sys.modules[module] - except ImportError: - module = 'sleekxmpp.features.%s' % name - __import__(module) - mod = sys.modules[module] - elif isinstance(module, (str, unicode)): - __import__(module) - mod = sys.modules[module] - else: - mod = module - - # Add older style plugins to the registry. - if hasattr(mod, name): - plugin = getattr(mod, name) - if hasattr(plugin, 'xep') or hasattr(plugin, 'rfc'): - plugin.name = name - # Mark the plugin as an older style plugin so - # we can work around dependency issues. - plugin.old_style = True - register_plugin(plugin, name) - except ImportError: - log.exception("Unable to load plugin: %s", name) - - -class PluginManager(object): - def __init__(self, xmpp, config=None): - #: We will track all enabled plugins in a set so that we - #: can enable plugins in batches and pull in dependencies - #: without problems. - self._enabled = set() - - #: Maintain references to active plugins. - self._plugins = {} - - self._plugin_lock = threading.RLock() - - #: Globally set default plugin configuration. This will - #: be used for plugins that are auto-enabled through - #: dependency loading. - self.config = config if config else {} - - self.xmpp = xmpp - - def register(self, plugin, enable=True): - """Register a new plugin, and optionally enable it. - - :param class plugin: The implementation class of the plugin - to register. - :param bool enable: If ``True``, immediately enable the - plugin after registration. - """ - register_plugin(plugin) - if enable: - self.enable(plugin.name) - - def enable(self, name, config=None, enabled=None): - """Enable a plugin, including any dependencies. - - :param string name: The short name of the plugin. - :param dict config: Optional settings dictionary for - configuring plugin behaviour. - """ - top_level = False - if enabled is None: - enabled = set() - - with self._plugin_lock: - if name not in self._enabled: - enabled.add(name) - self._enabled.add(name) - if not self.registered(name): - load_plugin(name) - - plugin_class = PLUGIN_REGISTRY.get(name, None) - if not plugin_class: - raise PluginNotFound(name) - - if config is None: - config = self.config.get(name, None) - - plugin = plugin_class(self.xmpp, config) - self._plugins[name] = plugin - for dep in plugin.dependencies: - self.enable(dep, enabled=enabled) - plugin._init() - - if top_level: - for name in enabled: - if hasattr(self.plugins[name], 'old_style'): - # Older style plugins require post_init() - # to run just before stream processing begins, - # so we don't call it here. - pass - self.plugins[name].post_init() - - def enable_all(self, names=None, config=None): - """Enable all registered plugins. - - :param list names: A list of plugin names to enable. If - none are provided, all registered plugins - will be enabled. - :param dict config: A dictionary mapping plugin names to - configuration dictionaries, as used by - :meth:`~PluginManager.enable`. - """ - names = names if names else PLUGIN_REGISTRY.keys() - if config is None: - config = {} - for name in names: - self.enable(name, config.get(name, {})) - - def enabled(self, name): - """Check if a plugin has been enabled. - - :param string name: The name of the plugin to check. - :return: boolean - """ - return name in self._enabled - - def registered(self, name): - """Check if a plugin has been registered. - - :param string name: The name of the plugin to check. - :return: boolean - """ - return name in PLUGIN_REGISTRY - - def disable(self, name, _disabled=None): - """Disable a plugin, including any dependent upon it. - - :param string name: The name of the plugin to disable. - :param set _disabled: Private set used to track the - disabled status of plugins during - the cascading process. - """ - if _disabled is None: - _disabled = set() - with self._plugin_lock: - if name not in _disabled and name in self._enabled: - _disabled.add(name) - plugin = self._plugins.get(name, None) - if plugin is None: - raise PluginNotFound(name) - for dep in PLUGIN_DEPENDENTS[name]: - self.disable(dep, _disabled) - plugin._end() - if name in self._enabled: - self._enabled.remove(name) - del self._plugins[name] - - def __keys__(self): - """Return the set of enabled plugins.""" - return self._plugins.keys() - - def __getitem__(self, name): - """ - Allow plugins to be accessed through the manager as if - it were a dictionary. - """ - plugin = self._plugins.get(name, None) - if plugin is None: - raise PluginNotFound(name) - return plugin - - def __iter__(self): - """Return an iterator over the set of enabled plugins.""" - return self._plugins.__iter__() - - def __len__(self): - """Return the number of enabled plugins.""" - return len(self._plugins) - - -class BasePlugin(object): - - #: A short name for the plugin based on the implemented specification. - #: For example, a plugin for XEP-0030 would use `'xep_0030'`. - name = '' - - #: A longer name for the plugin, describing its purpose. For example, - #: a plugin for XEP-0030 would use `'Service Discovery'` as its - #: description value. - description = '' - - #: Some plugins may depend on others in order to function properly. - #: Any plugin names included in :attr:`~BasePlugin.dependencies` will - #: be initialized as needed if this plugin is enabled. - dependencies = set() - - #: The basic, standard configuration for the plugin, which may - #: be overridden when initializing the plugin. The configuration - #: fields included here may be accessed directly as attributes of - #: the plugin. For example, including the configuration field 'foo' - #: would mean accessing `plugin.foo` returns the current value of - #: `plugin.config['foo']`. - default_config = {} - - def __init__(self, xmpp, config=None): - self.xmpp = xmpp - if self.xmpp: - self.api = self.xmpp.api.wrap(self.name) - - #: A plugin's behaviour may be configurable, in which case those - #: configuration settings will be provided as a dictionary. - self.config = copy.copy(self.default_config) - if config: - self.config.update(config) - - def __getattr__(self, key): - """Provide direct access to configuration fields. - - If the standard configuration includes the option `'foo'`, then - accessing `self.foo` should be the same as `self.config['foo']`. - """ - if key in self.default_config: - return self.config.get(key, None) - else: - return object.__getattribute__(self, key) - - def __setattr__(self, key, value): - """Provide direct assignment to configuration fields. - - If the standard configuration includes the option `'foo'`, then - assigning to `self.foo` should be the same as assigning to - `self.config['foo']`. - """ - if key in self.default_config: - self.config[key] = value - else: - super(BasePlugin, self).__setattr__(key, value) - - def _init(self): - """Initialize plugin state, such as registering event handlers. - - Also sets up required event handlers. - """ - if self.xmpp is not None: - self.xmpp.add_event_handler('session_bind', self.session_bind) - if self.xmpp.session_bind_event.is_set(): - self.session_bind(self.xmpp.boundjid.full) - self.plugin_init() - log.debug('Loaded Plugin: %s', self.description) - - def _end(self): - """Cleanup plugin state, and prepare for plugin removal. - - Also removes required event handlers. - """ - if self.xmpp is not None: - self.xmpp.del_event_handler('session_bind', self.session_bind) - self.plugin_end() - log.debug('Disabled Plugin: %s' % self.description) - - def plugin_init(self): - """Initialize plugin state, such as registering event handlers.""" - pass - - def plugin_end(self): - """Cleanup plugin state, and prepare for plugin removal.""" - pass - - def session_bind(self, jid): - """Initialize plugin state based on the bound JID.""" - pass - - def post_init(self): - """Initialize any cross-plugin state. - - Only needed if the plugin has circular dependencies. - """ - pass - - -base_plugin = BasePlugin diff --git a/sleekxmpp/plugins/gmail_notify.py b/sleekxmpp/plugins/gmail_notify.py deleted file mode 100644 index fc97a2ab..00000000 --- a/sleekxmpp/plugins/gmail_notify.py +++ /dev/null @@ -1,149 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging -from . import base -from .. xmlstream.handler.callback import Callback -from .. xmlstream.matcher.xpath import MatchXPath -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID -from .. stanza.iq import Iq - - -log = logging.getLogger(__name__) - - -class GmailQuery(ElementBase): - namespace = 'google:mail:notify' - name = 'query' - plugin_attrib = 'gmail' - interfaces = set(('newer-than-time', 'newer-than-tid', 'q', 'search')) - - def getSearch(self): - return self['q'] - - def setSearch(self, search): - self['q'] = search - - def delSearch(self): - del self['q'] - - -class MailBox(ElementBase): - namespace = 'google:mail:notify' - name = 'mailbox' - plugin_attrib = 'mailbox' - interfaces = set(('result-time', 'total-matched', 'total-estimate', - 'url', 'threads', 'matched', 'estimate')) - - def getThreads(self): - threads = [] - for threadXML in self.xml.findall('{%s}%s' % (MailThread.namespace, - MailThread.name)): - threads.append(MailThread(xml=threadXML, parent=None)) - return threads - - def getMatched(self): - return self['total-matched'] - - def getEstimate(self): - return self['total-estimate'] == '1' - - -class MailThread(ElementBase): - namespace = 'google:mail:notify' - name = 'mail-thread-info' - plugin_attrib = 'thread' - interfaces = set(('tid', 'participation', 'messages', 'date', - 'senders', 'url', 'labels', 'subject', 'snippet')) - sub_interfaces = set(('labels', 'subject', 'snippet')) - - def getSenders(self): - senders = [] - sendersXML = self.xml.find('{%s}senders' % self.namespace) - if sendersXML is not None: - for senderXML in sendersXML.findall('{%s}sender' % self.namespace): - senders.append(MailSender(xml=senderXML, parent=None)) - return senders - - -class MailSender(ElementBase): - namespace = 'google:mail:notify' - name = 'sender' - plugin_attrib = 'sender' - interfaces = set(('address', 'name', 'originator', 'unread')) - - def getOriginator(self): - return self.xml.attrib.get('originator', '0') == '1' - - def getUnread(self): - return self.xml.attrib.get('unread', '0') == '1' - - -class NewMail(ElementBase): - namespace = 'google:mail:notify' - name = 'new-mail' - plugin_attrib = 'new-mail' - - -class gmail_notify(base.base_plugin): - """ - Google Talk: Gmail Notifications - """ - - def plugin_init(self): - self.description = 'Google Talk: Gmail Notifications' - - self.xmpp.registerHandler( - Callback('Gmail Result', - MatchXPath('{%s}iq/{%s}%s' % (self.xmpp.default_ns, - MailBox.namespace, - MailBox.name)), - self.handle_gmail)) - - self.xmpp.registerHandler( - Callback('Gmail New Mail', - MatchXPath('{%s}iq/{%s}%s' % (self.xmpp.default_ns, - NewMail.namespace, - NewMail.name)), - self.handle_new_mail)) - - registerStanzaPlugin(Iq, GmailQuery) - registerStanzaPlugin(Iq, MailBox) - registerStanzaPlugin(Iq, NewMail) - - self.last_result_time = None - - def handle_gmail(self, iq): - mailbox = iq['mailbox'] - approx = ' approximately' if mailbox['estimated'] else '' - log.info('Gmail: Received%s %s emails', approx, mailbox['total-matched']) - self.last_result_time = mailbox['result-time'] - self.xmpp.event('gmail_messages', iq) - - def handle_new_mail(self, iq): - log.info("Gmail: New emails received!") - self.xmpp.event('gmail_notify') - self.checkEmail() - - def getEmail(self, query=None): - return self.search(query) - - def checkEmail(self): - return self.search(newer=self.last_result_time) - - def search(self, query=None, newer=None): - if query is None: - log.info("Gmail: Checking for new emails") - else: - log.info('Gmail: Searching for emails matching: "%s"', query) - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['to'] = self.xmpp.boundjid.bare - iq['gmail']['q'] = query - iq['gmail']['newer-than-time'] = newer - return iq.send() diff --git a/sleekxmpp/plugins/google/__init__.py b/sleekxmpp/plugins/google/__init__.py deleted file mode 100644 index bd7ca123..00000000 --- a/sleekxmpp/plugins/google/__init__.py +++ /dev/null @@ -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: - """ - - 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) diff --git a/sleekxmpp/plugins/google/auth/__init__.py b/sleekxmpp/plugins/google/auth/__init__.py deleted file mode 100644 index 5a8feb0d..00000000 --- a/sleekxmpp/plugins/google/auth/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/plugins/google/auth/auth.py b/sleekxmpp/plugins/google/auth/auth.py deleted file mode 100644 index 042bd404..00000000 --- a/sleekxmpp/plugins/google/auth/auth.py +++ /dev/null @@ -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: - - - """ - - 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 diff --git a/sleekxmpp/plugins/google/auth/stanza.py b/sleekxmpp/plugins/google/auth/stanza.py deleted file mode 100644 index 49c5cba7..00000000 --- a/sleekxmpp/plugins/google/auth/stanza.py +++ /dev/null @@ -1,49 +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, ET - - -class GoogleAuth(ElementBase): - name = 'auth' - namespace = 'http://www.google.com/talk/protocol/auth' - plugin_attrib = 'google' - interfaces = set(['client_uses_full_bind_result', 'service']) - - discovery_attr= '{%s}client-uses-full-bind-result' % namespace - service_attr= '{%s}service' % namespace - - def setup(self, xml): - """Don't create XML for the plugin.""" - self.xml = ET.Element('') - print('setting up google extension') - - def get_client_uses_full_bind_result(self): - return self.parent()._get_attr(self.disovery_attr) == 'true' - - def set_client_uses_full_bind_result(self, value): - print('>>>', value) - if value in (True, 'true'): - self.parent()._set_attr(self.discovery_attr, 'true') - else: - self.parent()._del_attr(self.discovery_attr) - - def del_client_uses_full_bind_result(self): - self.parent()._del_attr(self.discovery_attr) - - def get_service(self): - return self.parent()._get_attr(self.service_attr, '') - - def set_service(self, value): - if value: - self.parent()._set_attr(self.service_attr, value) - else: - self.parent()._del_attr(self.service_attr) - - def del_service(self): - self.parent()._del_attr(self.service_attr) diff --git a/sleekxmpp/plugins/google/gmail/__init__.py b/sleekxmpp/plugins/google/gmail/__init__.py deleted file mode 100644 index a92e363b..00000000 --- a/sleekxmpp/plugins/google/gmail/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/plugins/google/gmail/notifications.py b/sleekxmpp/plugins/google/gmail/notifications.py deleted file mode 100644 index 509a95fd..00000000 --- a/sleekxmpp/plugins/google/gmail/notifications.py +++ /dev/null @@ -1,96 +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 -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.google.gmail import stanza - - -log = logging.getLogger(__name__) - - -class Gmail(BasePlugin): - - """ - Google: Gmail Notifications - - Also see . - """ - - name = 'gmail' - description = 'Google: Gmail Notifications' - dependencies = set() - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, stanza.GmailQuery) - register_stanza_plugin(Iq, stanza.MailBox) - register_stanza_plugin(Iq, stanza.NewMail) - - self.xmpp.register_handler( - Callback('Gmail New Mail', - MatchXPath('{%s}iq/{%s}%s' % ( - self.xmpp.default_ns, - stanza.NewMail.namespace, - stanza.NewMail.name)), - self._handle_new_mail)) - - self._last_result_time = None - self._last_result_tid = None - - def plugin_end(self): - self.xmpp.remove_handler('Gmail New Mail') - - def _handle_new_mail(self, iq): - log.info('Gmail: New email!') - iq.reply().send() - self.xmpp.event('gmail_notification') - - def check(self, block=True, timeout=None, callback=None): - last_time = self._last_result_time - last_tid = self._last_result_tid - - if not block: - callback = lambda iq: self._update_last_results(iq, callback) - - resp = self.search(newer_time=last_time, - newer_tid=last_tid, - block=block, - timeout=timeout, - callback=callback) - - if block: - self._update_last_results(resp) - return resp - - def _update_last_results(self, iq, callback=None): - self._last_result_time = data['gmail_messages']['result_time'] - threads = data['gmail_messages']['threads'] - if threads: - self._last_result_tid = threads[0]['tid'] - if callback: - callback(iq) - - def search(self, query=None, newer_time=None, newer_tid=None, block=True, - timeout=None, callback=None): - if not query: - log.info('Gmail: Checking for new email') - else: - log.info('Gmail: Searching for emails matching: "%s"', query) - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['to'] = self.xmpp.boundjid.bare - iq['gmail']['search'] = query - iq['gmail']['newer_than_time'] = newer_time - iq['gmail']['newer_than_tid'] = newer_tid - return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/google/gmail/stanza.py b/sleekxmpp/plugins/google/gmail/stanza.py deleted file mode 100644 index e7e308e1..00000000 --- a/sleekxmpp/plugins/google/gmail/stanza.py +++ /dev/null @@ -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) diff --git a/sleekxmpp/plugins/google/nosave/__init__.py b/sleekxmpp/plugins/google/nosave/__init__.py deleted file mode 100644 index 57847af5..00000000 --- a/sleekxmpp/plugins/google/nosave/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/plugins/google/nosave/nosave.py b/sleekxmpp/plugins/google/nosave/nosave.py deleted file mode 100644 index d6bef615..00000000 --- a/sleekxmpp/plugins/google/nosave/nosave.py +++ /dev/null @@ -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 . - """ - - 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) diff --git a/sleekxmpp/plugins/google/nosave/stanza.py b/sleekxmpp/plugins/google/nosave/stanza.py deleted file mode 100644 index d8701322..00000000 --- a/sleekxmpp/plugins/google/nosave/stanza.py +++ /dev/null @@ -1,59 +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.jid import JID -from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin - - -class NoSave(ElementBase): - name = 'x' - namespace = 'google:nosave' - plugin_attrib = 'google_nosave' - interfaces = set(['value']) - - def get_value(self): - return self._get_attr('value', '') == 'enabled' - - def set_value(self, value): - self._set_attr('value', 'enabled' if value else 'disabled') - - -class NoSaveQuery(ElementBase): - name = 'query' - namespace = 'google:nosave' - plugin_attrib = 'google_nosave' - interfaces = set() - - -class Item(ElementBase): - name = 'item' - namespace = 'google:nosave' - plugin_attrib = 'item' - plugin_multi_attrib = 'items' - interfaces = set(['jid', 'source', 'value']) - - def get_value(self): - return self._get_attr('value', '') == 'enabled' - - def set_value(self, value): - self._set_attr('value', 'enabled' if value else 'disabled') - - def get_jid(self): - return JID(self._get_attr('jid', '')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_source(self): - return JID(self._get_attr('source', '')) - - def set_source(self): - self._set_attr('source', str(value)) - - -register_stanza_plugin(NoSaveQuery, Item) diff --git a/sleekxmpp/plugins/google/settings/__init__.py b/sleekxmpp/plugins/google/settings/__init__.py deleted file mode 100644 index c3a0471d..00000000 --- a/sleekxmpp/plugins/google/settings/__init__.py +++ /dev/null @@ -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 diff --git a/sleekxmpp/plugins/google/settings/settings.py b/sleekxmpp/plugins/google/settings/settings.py deleted file mode 100644 index 7122ff56..00000000 --- a/sleekxmpp/plugins/google/settings/settings.py +++ /dev/null @@ -1,65 +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 -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.settings import stanza - - -class GoogleSettings(BasePlugin): - - """ - Google: Gmail Notifications - - Also see . - """ - - name = 'google_settings' - description = 'Google: User Settings' - dependencies = set() - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, stanza.UserSettings) - - self.xmpp.register_handler( - Callback('Google Settings', - StanzaPath('iq@type=set/google_settings'), - self._handle_settings_change)) - - def plugin_end(self): - self.xmpp.remove_handler('Google Settings') - - def get(self, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq.enable('google_settings') - return iq.send(block=block, timeout=timeout, callback=callback) - - def update(self, settings, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq.enable('google_settings') - - for setting, value in settings.items(): - iq['google_settings'][setting] = value - - return iq.send(block=block, timeout=timeout, callback=callback) - - def _handle_settings_change(self, iq): - reply = self.xmpp.Iq() - reply['type'] = 'result' - reply['id'] = iq['id'] - reply['to'] = iq['from'] - reply.send() - self.xmpp.event('google_settings_change', iq) diff --git a/sleekxmpp/plugins/google/settings/stanza.py b/sleekxmpp/plugins/google/settings/stanza.py deleted file mode 100644 index d8161770..00000000 --- a/sleekxmpp/plugins/google/settings/stanza.py +++ /dev/null @@ -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') diff --git a/sleekxmpp/plugins/xep_0004/__init__.py b/sleekxmpp/plugins/xep_0004/__init__.py deleted file mode 100644 index 2cd18ec8..00000000 --- a/sleekxmpp/plugins/xep_0004/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0004.stanza import Form -from sleekxmpp.plugins.xep_0004.stanza import FormField, FieldOption -from sleekxmpp.plugins.xep_0004.dataforms import XEP_0004 - - -register_plugin(XEP_0004) - - -# Retain some backwards compatibility -xep_0004 = XEP_0004 -xep_0004.makeForm = xep_0004.make_form -xep_0004.buildForm = xep_0004.build_form diff --git a/sleekxmpp/plugins/xep_0004/dataforms.py b/sleekxmpp/plugins/xep_0004/dataforms.py deleted file mode 100644 index dde6e6a8..00000000 --- a/sleekxmpp/plugins/xep_0004/dataforms.py +++ /dev/null @@ -1,57 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp import Message -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0004 import stanza -from sleekxmpp.plugins.xep_0004.stanza import Form, FormField, FieldOption - - -class XEP_0004(BasePlugin): - - """ - XEP-0004: Data Forms - """ - - name = 'xep_0004' - description = 'XEP-0004: Data Forms' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - self.xmpp.register_handler( - Callback('Data Form', - StanzaPath('message/form'), - self.handle_form)) - - register_stanza_plugin(FormField, FieldOption, iterable=True) - register_stanza_plugin(Form, FormField, iterable=True) - register_stanza_plugin(Message, Form) - - def plugin_end(self): - self.xmpp.remove_handler('Data Form') - self.xmpp['xep_0030'].del_feature(feature='jabber:x:data') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('jabber:x:data') - - def make_form(self, ftype='form', title='', instructions=''): - f = Form() - f['type'] = ftype - f['title'] = title - f['instructions'] = instructions - return f - - def handle_form(self, message): - self.xmpp.event("message_xform", message) - - def build_form(self, xml): - return Form(xml=xml) diff --git a/sleekxmpp/plugins/xep_0004/stanza/__init__.py b/sleekxmpp/plugins/xep_0004/stanza/__init__.py deleted file mode 100644 index 6ad35298..00000000 --- a/sleekxmpp/plugins/xep_0004/stanza/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.xep_0004.stanza.field import FormField, FieldOption -from sleekxmpp.plugins.xep_0004.stanza.form import Form diff --git a/sleekxmpp/plugins/xep_0004/stanza/field.py b/sleekxmpp/plugins/xep_0004/stanza/field.py deleted file mode 100644 index 51f85995..00000000 --- a/sleekxmpp/plugins/xep_0004/stanza/field.py +++ /dev/null @@ -1,183 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 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, ET - - -class FormField(ElementBase): - namespace = 'jabber:x:data' - name = 'field' - plugin_attrib = 'field' - interfaces = set(('answer', 'desc', 'required', 'value', - 'options', 'label', 'type', 'var')) - sub_interfaces = set(('desc',)) - plugin_tag_map = {} - plugin_attrib_map = {} - - field_types = set(('boolean', 'fixed', 'hidden', 'jid-multi', - 'jid-single', 'list-multi', 'list-single', - 'text-multi', 'text-private', 'text-single')) - - true_values = set((True, '1', 'true')) - option_types = set(('list-multi', 'list-single')) - multi_line_types = set(('hidden', 'text-multi')) - multi_value_types = set(('hidden', 'jid-multi', - 'list-multi', 'text-multi')) - - def setup(self, xml=None): - if ElementBase.setup(self, xml): - self._type = None - else: - self._type = self['type'] - - def set_type(self, value): - self._set_attr('type', value) - if value: - self._type = value - - def add_option(self, label='', value=''): - if self._type is None or self._type in self.option_types: - opt = FieldOption() - opt['label'] = label - opt['value'] = value - self.append(opt) - else: - raise ValueError("Cannot add options to " + \ - "a %s field." % self['type']) - - def del_options(self): - optsXML = self.xml.findall('{%s}option' % self.namespace) - for optXML in optsXML: - self.xml.remove(optXML) - - def del_required(self): - reqXML = self.xml.find('{%s}required' % self.namespace) - if reqXML is not None: - self.xml.remove(reqXML) - - def del_value(self): - valsXML = self.xml.findall('{%s}value' % self.namespace) - for valXML in valsXML: - self.xml.remove(valXML) - - def get_answer(self): - return self['value'] - - def get_options(self): - options = [] - optsXML = self.xml.findall('{%s}option' % self.namespace) - for optXML in optsXML: - opt = FieldOption(xml=optXML) - options.append({'label': opt['label'], 'value': opt['value']}) - return options - - def get_required(self): - reqXML = self.xml.find('{%s}required' % self.namespace) - return reqXML is not None - - def get_value(self, convert=True): - valsXML = self.xml.findall('{%s}value' % self.namespace) - if len(valsXML) == 0: - return None - elif self._type == 'boolean': - if convert: - return valsXML[0].text in self.true_values - return valsXML[0].text - elif self._type in self.multi_value_types or len(valsXML) > 1: - values = [] - for valXML in valsXML: - if valXML.text is None: - valXML.text = '' - values.append(valXML.text) - if self._type == 'text-multi' and convert: - values = "\n".join(values) - return values - else: - if valsXML[0].text is None: - return '' - return valsXML[0].text - - def set_answer(self, answer): - self['value'] = answer - - def set_false(self): - self['value'] = False - - def set_options(self, options): - for value in options: - if isinstance(value, dict): - self.add_option(**value) - else: - self.add_option(value=value) - - def set_required(self, required): - exists = self['required'] - if not exists and required: - self.xml.append(ET.Element('{%s}required' % self.namespace)) - elif exists and not required: - del self['required'] - - def set_true(self): - self['value'] = True - - def set_value(self, value): - del self['value'] - valXMLName = '{%s}value' % self.namespace - - if self._type == 'boolean': - if value in self.true_values: - valXML = ET.Element(valXMLName) - valXML.text = '1' - self.xml.append(valXML) - else: - valXML = ET.Element(valXMLName) - valXML.text = '0' - self.xml.append(valXML) - elif self._type in self.multi_value_types or self._type in ('', None): - if isinstance(value, bool): - value = [value] - if not isinstance(value, list): - value = value.replace('\r', '') - value = value.split('\n') - for val in value: - if self._type in ('', None) and val in self.true_values: - val = '1' - valXML = ET.Element(valXMLName) - valXML.text = val - self.xml.append(valXML) - else: - if isinstance(value, list): - raise ValueError("Cannot add multiple values " + \ - "to a %s field." % self._type) - valXML = ET.Element(valXMLName) - valXML.text = value - self.xml.append(valXML) - - -class FieldOption(ElementBase): - namespace = 'jabber:x:data' - name = 'option' - plugin_attrib = 'option' - interfaces = set(('label', 'value')) - sub_interfaces = set(('value',)) - - -FormField.addOption = FormField.add_option -FormField.delOptions = FormField.del_options -FormField.delRequired = FormField.del_required -FormField.delValue = FormField.del_value -FormField.getAnswer = FormField.get_answer -FormField.getOptions = FormField.get_options -FormField.getRequired = FormField.get_required -FormField.getValue = FormField.get_value -FormField.setAnswer = FormField.set_answer -FormField.setFalse = FormField.set_false -FormField.setOptions = FormField.set_options -FormField.setRequired = FormField.set_required -FormField.setTrue = FormField.set_true -FormField.setValue = FormField.set_value diff --git a/sleekxmpp/plugins/xep_0004/stanza/form.py b/sleekxmpp/plugins/xep_0004/stanza/form.py deleted file mode 100644 index bbd8540f..00000000 --- a/sleekxmpp/plugins/xep_0004/stanza/form.py +++ /dev/null @@ -1,257 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import copy -import logging - -from sleekxmpp.thirdparty import OrderedDict - -from sleekxmpp.xmlstream import ElementBase, ET -from sleekxmpp.plugins.xep_0004.stanza import FormField - - -log = logging.getLogger(__name__) - - -class Form(ElementBase): - namespace = 'jabber:x:data' - name = 'x' - plugin_attrib = 'form' - interfaces = set(('fields', 'instructions', 'items', - 'reported', 'title', 'type', 'values')) - sub_interfaces = set(('title',)) - form_types = set(('cancel', 'form', 'result', 'submit')) - - def __init__(self, *args, **kwargs): - title = None - if 'title' in kwargs: - title = kwargs['title'] - del kwargs['title'] - ElementBase.__init__(self, *args, **kwargs) - if title is not None: - self['title'] = title - - def setup(self, xml=None): - if ElementBase.setup(self, xml): - # If we had to generate xml - self['type'] = 'form' - - @property - def field(self): - return self['fields'] - - def set_type(self, ftype): - self._set_attr('type', ftype) - if ftype == 'submit': - fields = self['fields'] - for var in fields: - field = fields[var] - del field['type'] - del field['label'] - del field['desc'] - del field['required'] - del field['options'] - elif ftype == 'cancel': - del self['fields'] - - def add_field(self, var='', ftype=None, label='', desc='', - required=False, value=None, options=None, **kwargs): - kwtype = kwargs.get('type', None) - if kwtype is None: - kwtype = ftype - - field = FormField() - field['var'] = var - field['type'] = kwtype - field['value'] = value - if self['type'] in ('form', 'result'): - field['label'] = label - field['desc'] = desc - field['required'] = required - if options is not None: - field['options'] = options - else: - del field['type'] - self.append(field) - return field - - def getXML(self, type='submit'): - self['type'] = type - log.warning("Form.getXML() is deprecated API compatibility " + \ - "with plugins/old_0004.py") - return self.xml - - def fromXML(self, xml): - log.warning("Form.fromXML() is deprecated API compatibility " + \ - "with plugins/old_0004.py") - n = Form(xml=xml) - return n - - def add_item(self, values): - itemXML = ET.Element('{%s}item' % self.namespace) - self.xml.append(itemXML) - reported_vars = self['reported'].keys() - for var in reported_vars: - field = FormField() - field._type = self['reported'][var]['type'] - field['var'] = var - field['value'] = values.get(var, None) - itemXML.append(field.xml) - - def add_reported(self, var, ftype=None, label='', desc='', **kwargs): - kwtype = kwargs.get('type', None) - if kwtype is None: - kwtype = ftype - reported = self.xml.find('{%s}reported' % self.namespace) - if reported is None: - reported = ET.Element('{%s}reported' % self.namespace) - self.xml.append(reported) - fieldXML = ET.Element('{%s}field' % FormField.namespace) - reported.append(fieldXML) - field = FormField(xml=fieldXML) - field['var'] = var - field['type'] = kwtype - field['label'] = label - field['desc'] = desc - return field - - def cancel(self): - self['type'] = 'cancel' - - def del_fields(self): - fieldsXML = self.xml.findall('{%s}field' % FormField.namespace) - for fieldXML in fieldsXML: - self.xml.remove(fieldXML) - - def del_instructions(self): - instsXML = self.xml.findall('{%s}instructions') - for instXML in instsXML: - self.xml.remove(instXML) - - def del_items(self): - itemsXML = self.xml.find('{%s}item' % self.namespace) - for itemXML in itemsXML: - self.xml.remove(itemXML) - - def del_reported(self): - reportedXML = self.xml.find('{%s}reported' % self.namespace) - if reportedXML is not None: - self.xml.remove(reportedXML) - - def get_fields(self, use_dict=False): - fields = OrderedDict() - for stanza in self['substanzas']: - if isinstance(stanza, FormField): - fields[stanza['var']] = stanza - return fields - - def get_instructions(self): - instructions = '' - instsXML = self.xml.findall('{%s}instructions' % self.namespace) - return "\n".join([instXML.text for instXML in instsXML]) - - def get_items(self): - items = [] - itemsXML = self.xml.findall('{%s}item' % self.namespace) - for itemXML in itemsXML: - item = OrderedDict() - fieldsXML = itemXML.findall('{%s}field' % FormField.namespace) - for fieldXML in fieldsXML: - field = FormField(xml=fieldXML) - item[field['var']] = field['value'] - items.append(item) - return items - - def get_reported(self): - fields = OrderedDict() - xml = self.xml.findall('{%s}reported/{%s}field' % (self.namespace, - FormField.namespace)) - for field in xml: - field = FormField(xml=field) - fields[field['var']] = field - return fields - - def get_values(self): - values = OrderedDict() - fields = self['fields'] - for var in fields: - values[var] = fields[var]['value'] - return values - - def reply(self): - if self['type'] == 'form': - self['type'] = 'submit' - elif self['type'] == 'submit': - self['type'] = 'result' - - def set_fields(self, fields): - del self['fields'] - if not isinstance(fields, list): - fields = fields.items() - for var, field in fields: - field['var'] = var - self.add_field(**field) - - def set_instructions(self, instructions): - del self['instructions'] - if instructions in [None, '']: - return - if not isinstance(instructions, list): - instructions = instructions.split('\n') - for instruction in instructions: - inst = ET.Element('{%s}instructions' % self.namespace) - inst.text = instruction - self.xml.append(inst) - - def set_items(self, items): - for item in items: - self.add_item(item) - - def set_reported(self, reported): - for var in reported: - field = reported[var] - field['var'] = var - self.add_reported(var, **field) - - def set_values(self, values): - fields = self['fields'] - for field in values: - if field not in fields: - fields[field] = self.add_field(var=field) - fields[field]['value'] = values[field] - - def merge(self, other): - new = copy.copy(self) - if type(other) == dict: - new['values'] = other - return new - nfields = new['fields'] - ofields = other['fields'] - nfields.update(ofields) - new['fields'] = nfields - return new - - -Form.setType = Form.set_type -Form.addField = Form.add_field -Form.addItem = Form.add_item -Form.addReported = Form.add_reported -Form.delFields = Form.del_fields -Form.delInstructions = Form.del_instructions -Form.delItems = Form.del_items -Form.delReported = Form.del_reported -Form.getFields = Form.get_fields -Form.getInstructions = Form.get_instructions -Form.getItems = Form.get_items -Form.getReported = Form.get_reported -Form.getValues = Form.get_values -Form.setFields = Form.set_fields -Form.setInstructions = Form.set_instructions -Form.setItems = Form.set_items -Form.setReported = Form.set_reported -Form.setValues = Form.set_values diff --git a/sleekxmpp/plugins/xep_0009/__init__.py b/sleekxmpp/plugins/xep_0009/__init__.py deleted file mode 100644 index 0ce3cf2c..00000000 --- a/sleekxmpp/plugins/xep_0009/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0009 import stanza -from sleekxmpp.plugins.xep_0009.rpc import XEP_0009 -from sleekxmpp.plugins.xep_0009.stanza import RPCQuery, MethodCall, MethodResponse - - -register_plugin(XEP_0009) - - -# Retain some backwards compatibility -xep_0009 = XEP_0009 diff --git a/sleekxmpp/plugins/xep_0009/binding.py b/sleekxmpp/plugins/xep_0009/binding.py deleted file mode 100644 index a55993ad..00000000 --- a/sleekxmpp/plugins/xep_0009/binding.py +++ /dev/null @@ -1,173 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ET -import base64 -import logging -import time -import sys - -if sys.version_info > (3, 0): - unicode = str - -log = logging.getLogger(__name__) - -_namespace = 'jabber:iq:rpc' - -def fault2xml(fault): - value = dict() - value['faultCode'] = fault['code'] - value['faultString'] = fault['string'] - fault = ET.Element("fault", {'xmlns': _namespace}) - fault.append(_py2xml((value))) - return fault - -def xml2fault(params): - vals = [] - for value in params.findall('{%s}value' % _namespace): - vals.append(_xml2py(value)) - fault = dict() - fault['code'] = vals[0]['faultCode'] - fault['string'] = vals[0]['faultString'] - return fault - -def py2xml(*args): - params = ET.Element("{%s}params" % _namespace) - for x in args: - param = ET.Element("{%s}param" % _namespace) - param.append(_py2xml(x)) - params.append(param) #... - return params - -def _py2xml(*args): - for x in args: - val = ET.Element("{%s}value" % _namespace) - if x is None: - nil = ET.Element("{%s}nil" % _namespace) - val.append(nil) - elif type(x) is int: - i4 = ET.Element("{%s}i4" % _namespace) - i4.text = str(x) - val.append(i4) - elif type(x) is bool: - boolean = ET.Element("{%s}boolean" % _namespace) - boolean.text = str(int(x)) - val.append(boolean) - elif type(x) in (str, unicode): - string = ET.Element("{%s}string" % _namespace) - string.text = x - val.append(string) - elif type(x) is float: - double = ET.Element("{%s}double" % _namespace) - double.text = str(x) - val.append(double) - elif type(x) is rpcbase64: - b64 = ET.Element("{%s}base64" % _namespace) - b64.text = x.encoded() - val.append(b64) - elif type(x) is rpctime: - iso = ET.Element("{%s}dateTime.iso8601" % _namespace) - iso.text = str(x) - val.append(iso) - elif type(x) in (list, tuple): - array = ET.Element("{%s}array" % _namespace) - data = ET.Element("{%s}data" % _namespace) - for y in x: - data.append(_py2xml(y)) - array.append(data) - val.append(array) - elif type(x) is dict: - struct = ET.Element("{%s}struct" % _namespace) - for y in x.keys(): - member = ET.Element("{%s}member" % _namespace) - name = ET.Element("{%s}name" % _namespace) - name.text = y - member.append(name) - member.append(_py2xml(x[y])) - struct.append(member) - val.append(struct) - return val - -def xml2py(params): - namespace = 'jabber:iq:rpc' - vals = [] - for param in params.findall('{%s}param' % namespace): - vals.append(_xml2py(param.find('{%s}value' % namespace))) - return vals - -def _xml2py(value): - namespace = 'jabber:iq:rpc' - if value.find('{%s}nil' % namespace) is not None: - return None - if value.find('{%s}i4' % namespace) is not None: - return int(value.find('{%s}i4' % namespace).text) - if value.find('{%s}int' % namespace) is not None: - return int(value.find('{%s}int' % namespace).text) - if value.find('{%s}boolean' % namespace) is not None: - return bool(int(value.find('{%s}boolean' % namespace).text)) - if value.find('{%s}string' % namespace) is not None: - return value.find('{%s}string' % namespace).text - if value.find('{%s}double' % namespace) is not None: - return float(value.find('{%s}double' % namespace).text) - if value.find('{%s}base64' % namespace) is not None: - return rpcbase64(value.find('{%s}base64' % namespace).text.encode()) - if value.find('{%s}Base64' % namespace) is not None: - # Older versions of XEP-0009 used Base64 - return rpcbase64(value.find('{%s}Base64' % namespace).text.encode()) - if value.find('{%s}dateTime.iso8601' % namespace) is not None: - return rpctime(value.find('{%s}dateTime.iso8601' % namespace).text) - if value.find('{%s}struct' % namespace) is not None: - struct = {} - for member in value.find('{%s}struct' % namespace).findall('{%s}member' % namespace): - struct[member.find('{%s}name' % namespace).text] = _xml2py(member.find('{%s}value' % namespace)) - return struct - if value.find('{%s}array' % namespace) is not None: - array = [] - for val in value.find('{%s}array' % namespace).find('{%s}data' % namespace).findall('{%s}value' % namespace): - array.append(_xml2py(val)) - return array - raise ValueError() - - - -class rpcbase64(object): - - def __init__(self, data): - #base 64 encoded string - self.data = data - - def decode(self): - return base64.b64decode(self.data) - - def __str__(self): - return self.decode().decode() - - def encoded(self): - return self.data.decode() - - - -class rpctime(object): - - def __init__(self,data=None): - #assume string data is in iso format YYYYMMDDTHH:MM:SS - if type(data) in (str, unicode): - self.timestamp = time.strptime(data,"%Y%m%dT%H:%M:%S") - elif type(data) is time.struct_time: - self.timestamp = data - elif data is None: - self.timestamp = time.gmtime() - else: - raise ValueError() - - def iso8601(self): - #return a iso8601 string - return time.strftime("%Y%m%dT%H:%M:%S",self.timestamp) - - def __str__(self): - return self.iso8601() diff --git a/sleekxmpp/plugins/xep_0009/remote.py b/sleekxmpp/plugins/xep_0009/remote.py deleted file mode 100644 index 8c08e8f3..00000000 --- a/sleekxmpp/plugins/xep_0009/remote.py +++ /dev/null @@ -1,742 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from binding import py2xml, xml2py, xml2fault, fault2xml -from threading import RLock -import abc -import inspect -import logging -import sleekxmpp -import sys -import threading -import traceback - -log = logging.getLogger(__name__) - -def _intercept(method, name, public): - def _resolver(instance, *args, **kwargs): - log.debug("Locally calling %s.%s with arguments %s.", instance.FQN(), method.__name__, args) - try: - value = method(instance, *args, **kwargs) - if value == NotImplemented: - raise InvocationException("Local handler does not implement %s.%s!" % (instance.FQN(), method.__name__)) - return value - except InvocationException: - raise - except Exception as e: - raise InvocationException("A problem occured calling %s.%s!" % (instance.FQN(), method.__name__), e) - _resolver._rpc = public - _resolver._rpc_name = method.__name__ if name is None else name - return _resolver - -def remote(function_argument, public = True): - ''' - Decorator for methods which are remotely callable. This decorator - works in conjunction with classes which extend ABC Endpoint. - Example: - - @remote - def remote_method(arg1, arg2) - - Arguments: - function_argument -- a stand-in for either the actual method - OR a new name (string) for the method. In that case the - method is considered mapped: - Example: - - @remote("new_name") - def remote_method(arg1, arg2) - - public -- A flag which indicates if this method should be part - of the known dictionary of remote methods. Defaults to True. - Example: - - @remote(False) - def remote_method(arg1, arg2) - - Note: renaming and revising (public vs. private) can be combined. - Example: - - @remote("new_name", False) - def remote_method(arg1, arg2) - ''' - if hasattr(function_argument, '__call__'): - return _intercept(function_argument, None, public) - else: - if not isinstance(function_argument, basestring): - if not isinstance(function_argument, bool): - raise Exception('Expected an RPC method name or visibility modifier!') - else: - def _wrap_revised(function): - function = _intercept(function, None, function_argument) - return function - return _wrap_revised - def _wrap_remapped(function): - function = _intercept(function, function_argument, public) - return function - return _wrap_remapped - - -class ACL: - ''' - An Access Control List (ACL) is a list of rules, which are evaluated - in order until a match is found. The policy of the matching rule - is then applied. - - Rules are 3-tuples, consisting of a policy enumerated type, a JID - expression and a RCP resource expression. - - Examples: - [ (ACL.ALLOW, '*', '*') ] allow everyone everything, no restrictions - [ (ACL.DENY, '*', '*') ] deny everyone everything, no restrictions - [ (ACL.ALLOW, 'test@xmpp.org/unit', 'test.*'), - (ACL.DENY, '*', '*') ] deny everyone everything, except named - JID, which is allowed access to endpoint 'test' only. - - The use of wildcards is allowed in expressions, as follows: - '*' everyone, or everything (= all endpoints and methods) - 'test@xmpp.org/*' every JID regardless of JID resource - '*@xmpp.org/rpc' every JID from domain xmpp.org with JID res 'rpc' - 'frank@*' every 'frank', regardless of domain or JID res - 'system.*' all methods of endpoint 'system' - '*.reboot' all methods reboot regardless of endpoint - ''' - ALLOW = True - DENY = False - - @classmethod - def check(cls, rules, jid, resource): - if rules is None: - return cls.DENY # No rules means no access! - jid = str(jid) # Check the string representation of the JID. - if not jid: - return cls.DENY # Can't check an empty JID. - for rule in rules: - policy = cls._check(rule, jid, resource) - if policy is not None: - return policy - return cls.DENY # By default if not rule matches, deny access. - - @classmethod - def _check(cls, rule, jid, resource): - if cls._match(jid, rule[1]) and cls._match(resource, rule[2]): - return rule[0] - else: - return None - - @classmethod - def _next_token(cls, expression, index): - new_index = expression.find('*', index) - if new_index == 0: - return '' - else: - if new_index == -1: - return expression[index : ] - else: - return expression[index : new_index] - - @classmethod - def _match(cls, value, expression): - #! print "_match [VALUE] %s [EXPR] %s" % (value, expression) - index = 0 - position = 0 - while index < len(expression): - token = cls._next_token(expression, index) - #! print "[TOKEN] '%s'" % token - size = len(token) - if size > 0: - token_index = value.find(token, position) - if token_index == -1: - return False - else: - #! print "[INDEX-OF] %s" % token_index - position = token_index + len(token) - pass - if size == 0: - index += 1 - else: - index += size - #! print "index %s position %s" % (index, position) - return True - -ANY_ALL = [ (ACL.ALLOW, '*', '*') ] - - -class RemoteException(Exception): - ''' - Base exception for RPC. This exception is raised when a problem - occurs in the network layer. - ''' - - def __init__(self, message="", cause=None): - ''' - Initializes a new RemoteException. - - Arguments: - message -- The message accompanying this exception. - cause -- The underlying cause of this exception. - ''' - self._message = message - self._cause = cause - pass - - def __str__(self): - return repr(self._message) - - def get_message(self): - return self._message - - def get_cause(self): - return self._cause - - - -class InvocationException(RemoteException): - ''' - Exception raised when a problem occurs during the remote invocation - of a method. - ''' - pass - - - -class AuthorizationException(RemoteException): - ''' - Exception raised when the caller is not authorized to invoke the - remote method. - ''' - pass - - -class TimeoutException(Exception): - ''' - Exception raised when the synchronous execution of a method takes - longer than the given threshold because an underlying asynchronous - reply did not arrive in time. - ''' - pass - - -class Callback(object): - ''' - A base class for callback handlers. - ''' - __metaclass__ = abc.ABCMeta - - - @abc.abstractproperty - def set_value(self, value): - return NotImplemented - - @abc.abstractproperty - def cancel_with_error(self, exception): - return NotImplemented - - -class Future(Callback): - ''' - Represents the result of an asynchronous computation. - ''' - - def __init__(self): - ''' - Initializes a new Future. - ''' - self._value = None - self._exception = None - self._event = threading.Event() - pass - - def set_value(self, value): - ''' - Sets the value of this Future. Once the value is set, a caller - blocked on get_value will be able to continue. - ''' - self._value = value - self._event.set() - - def get_value(self, timeout=None): - ''' - Gets the value of this Future. This call will block until - the result is available, or until an optional timeout expires. - When this Future is cancelled with an error, - - Arguments: - timeout -- The maximum waiting time to obtain the value. - ''' - self._event.wait(timeout) - if self._exception: - raise self._exception - if not self._event.is_set(): - raise TimeoutException - return self._value - - def is_done(self): - ''' - Returns true if a value has been returned. - ''' - return self._event.is_set() - - def cancel_with_error(self, exception): - ''' - Cancels the Future because of an error. Once cancelled, a - caller blocked on get_value will be able to continue. - ''' - self._exception = exception - self._event.set() - - - -class Endpoint(object): - ''' - The Endpoint class is an abstract base class for all objects - participating in an RPC-enabled XMPP network. - - A user subclassing this class is required to implement the method: - FQN(self) - where FQN stands for Fully Qualified Name, an unambiguous name - which specifies which object an RPC call refers to. It is the - first part in a RPC method name '.'. - ''' - __metaclass__ = abc.ABCMeta - - - def __init__(self, session, target_jid): - ''' - Initialize a new Endpoint. This constructor should never be - invoked by a user, instead it will be called by the factories - which instantiate the RPC-enabled objects, of which only - the classes are provided by the user. - - Arguments: - session -- An RPC session instance. - target_jid -- the identity of the remote XMPP entity. - ''' - self.session = session - self.target_jid = target_jid - - @abc.abstractproperty - def FQN(self): - return NotImplemented - - def get_methods(self): - ''' - Returns a dictionary of all RPC method names provided by this - class. This method returns the actual method names as found - in the class definition which have been decorated with: - - @remote - def some_rpc_method(arg1, arg2) - - - Unless: - (1) the name has been remapped, in which case the new - name will be returned. - - @remote("new_name") - def some_rpc_method(arg1, arg2) - - (2) the method is set to hidden - - @remote(False) - def some_hidden_method(arg1, arg2) - ''' - result = dict() - for function in dir(self): - test_attr = getattr(self, function, None) - try: - if test_attr._rpc: - result[test_attr._rpc_name] = test_attr - except Exception: - pass - return result - - - -class Proxy(Endpoint): - ''' - Implementation of the Proxy pattern which is intended to wrap - around Endpoints in order to intercept calls, marshall them and - forward them to the remote object. - ''' - - def __init__(self, endpoint, callback = None): - ''' - Initializes a new Proxy. - - Arguments: - endpoint -- The endpoint which is proxified. - ''' - self._endpoint = endpoint - self._callback = callback - - def __getattribute__(self, name, *args): - if name in ('__dict__', '_endpoint', 'async', '_callback'): - return object.__getattribute__(self, name) - else: - attribute = self._endpoint.__getattribute__(name) - if hasattr(attribute, '__call__'): - try: - if attribute._rpc: - def _remote_call(*args, **kwargs): - log.debug("Remotely calling '%s.%s' with arguments %s.", self._endpoint.FQN(), attribute._rpc_name, args) - return self._endpoint.session._call_remote(self._endpoint.target_jid, "%s.%s" % (self._endpoint.FQN(), attribute._rpc_name), self._callback, *args, **kwargs) - return _remote_call - except: - pass # If the attribute doesn't exist, don't care! - return attribute - - def async(self, callback): - return Proxy(self._endpoint, callback) - - def get_endpoint(self): - ''' - Returns the proxified endpoint. - ''' - return self._endpoint - - def FQN(self): - return self._endpoint.FQN() - - -class JabberRPCEntry(object): - - - def __init__(self, endpoint_FQN, call): - self._endpoint_FQN = endpoint_FQN - self._call = call - - def call_method(self, args): - return_value = self._call(*args) - if return_value is None: - return return_value - else: - return self._return(return_value) - - def get_endpoint_FQN(self): - return self._endpoint_FQN - - def _return(self, *args): - return args - - -class RemoteSession(object): - ''' - A context object for a Jabber-RPC session. - ''' - - - def __init__(self, client, session_close_callback): - ''' - Initializes a new RPC session. - - Arguments: - client -- The SleekXMPP client associated with this session. - session_close_callback -- A callback called when the - session is closed. - ''' - self._client = client - self._session_close_callback = session_close_callback - self._event = threading.Event() - self._entries = {} - self._callbacks = {} - self._acls = {} - self._lock = RLock() - - def _wait(self): - self._event.wait() - - def _notify(self, event): - log.debug("RPC Session as %s started.", self._client.boundjid.full) - self._client.sendPresence() - self._event.set() - pass - - def _register_call(self, endpoint, method, name=None): - ''' - Registers a method from an endpoint as remotely callable. - ''' - if name is None: - name = method.__name__ - key = "%s.%s" % (endpoint, name) - log.debug("Registering call handler for %s (%s).", key, method) - with self._lock: - if key in self._entries: - raise KeyError("A handler for %s has already been regisered!" % endpoint) - self._entries[key] = JabberRPCEntry(endpoint, method) - return key - - def _register_acl(self, endpoint, acl): - log.debug("Registering ACL %s for endpoint %s.", repr(acl), endpoint) - with self._lock: - self._acls[endpoint] = acl - - def _register_callback(self, pid, callback): - with self._lock: - self._callbacks[pid] = callback - - def forget_callback(self, callback): - with self._lock: - pid = self._find_key(self._callbacks, callback) - if pid is not None: - del self._callback[pid] - else: - raise ValueError("Unknown callback!") - pass - - def _find_key(self, dict, value): - """return the key of dictionary dic given the value""" - search = [k for k, v in dict.iteritems() if v == value] - if len(search) == 0: - return None - else: - return search[0] - - def _unregister_call(self, key): - #removes the registered call - with self._lock: - if self._entries[key]: - del self._entries[key] - else: - raise ValueError() - - def new_proxy(self, target_jid, endpoint_cls): - ''' - Instantiates a new proxy object, which proxies to a remote - endpoint. This method uses a class reference without - constructor arguments to instantiate the proxy. - - Arguments: - target_jid -- the XMPP entity ID hosting the endpoint. - endpoint_cls -- The remote (duck) type. - ''' - try: - argspec = inspect.getargspec(endpoint_cls.__init__) - args = [None] * (len(argspec[0]) - 1) - result = endpoint_cls(*args) - Endpoint.__init__(result, self, target_jid) - return Proxy(result) - except: - traceback.print_exc(file=sys.stdout) - - def new_handler(self, acl, handler_cls, *args, **kwargs): - ''' - Instantiates a new handler object, which is called remotely - by others. The user can control the effect of the call by - implementing the remote method in the local endpoint class. The - returned reference can be called locally and will behave as a - regular instance. - - Arguments: - acl -- Access control list (see ACL class) - handler_clss -- The local (duck) type. - *args -- Constructor arguments for the local type. - **kwargs -- Constructor keyworded arguments for the local - type. - ''' - argspec = inspect.getargspec(handler_cls.__init__) - base_argspec = inspect.getargspec(Endpoint.__init__) - if(argspec == base_argspec): - result = handler_cls(self, self._client.boundjid.full) - else: - result = handler_cls(*args, **kwargs) - Endpoint.__init__(result, self, self._client.boundjid.full) - method_dict = result.get_methods() - for method_name, method in method_dict.iteritems(): - #!!! self._client.plugin['xep_0009'].register_call(result.FQN(), method, method_name) - self._register_call(result.FQN(), method, method_name) - self._register_acl(result.FQN(), acl) - return result - -# def is_available(self, targetCls, pto): -# return self._client.is_available(pto) - - def _call_remote(self, pto, pmethod, callback, *arguments): - iq = self._client.plugin['xep_0009'].make_iq_method_call(pto, pmethod, py2xml(*arguments)) - pid = iq['id'] - if callback is None: - future = Future() - self._register_callback(pid, future) - iq.send() - return future.get_value(30) - else: - log.debug("[RemoteSession] _call_remote %s", callback) - self._register_callback(pid, callback) - iq.send() - - def close(self): - ''' - Closes this session. - ''' - self._client.disconnect(False) - self._session_close_callback() - - def _on_jabber_rpc_method_call(self, iq): - iq.enable('rpc_query') - params = iq['rpc_query']['method_call']['params'] - args = xml2py(params) - pmethod = iq['rpc_query']['method_call']['method_name'] - try: - with self._lock: - entry = self._entries[pmethod] - rules = self._acls[entry.get_endpoint_FQN()] - if ACL.check(rules, iq['from'], pmethod): - return_value = entry.call_method(args) - else: - raise AuthorizationException("Unauthorized access to %s from %s!" % (pmethod, iq['from'])) - if return_value is None: - return_value = () - response = self._client.plugin['xep_0009'].make_iq_method_response(iq['id'], iq['from'], py2xml(*return_value)) - response.send() - except InvocationException as ie: - fault = dict() - fault['code'] = 500 - fault['string'] = ie.get_message() - self._client.plugin['xep_0009']._send_fault(iq, fault2xml(fault)) - except AuthorizationException as ae: - log.error(ae.get_message()) - error = self._client.plugin['xep_0009']._forbidden(iq) - error.send() - except Exception as e: - if isinstance(e, KeyError): - log.error("No handler available for %s!", pmethod) - error = self._client.plugin['xep_0009']._item_not_found(iq) - else: - traceback.print_exc(file=sys.stderr) - log.error("An unexpected problem occurred invoking method %s!", pmethod) - error = self._client.plugin['xep_0009']._undefined_condition(iq) - #! print "[REMOTE.PY] _handle_remote_procedure_call AN ERROR SHOULD BE SENT NOW %s " % e - error.send() - - def _on_jabber_rpc_method_response(self, iq): - iq.enable('rpc_query') - args = xml2py(iq['rpc_query']['method_response']['params']) - pid = iq['id'] - with self._lock: - callback = self._callbacks[pid] - del self._callbacks[pid] - if(len(args) > 0): - callback.set_value(args[0]) - else: - callback.set_value(None) - pass - - def _on_jabber_rpc_method_response2(self, iq): - iq.enable('rpc_query') - if iq['rpc_query']['method_response']['fault'] is not None: - self._on_jabber_rpc_method_fault(iq) - else: - args = xml2py(iq['rpc_query']['method_response']['params']) - pid = iq['id'] - with self._lock: - callback = self._callbacks[pid] - del self._callbacks[pid] - if(len(args) > 0): - callback.set_value(args[0]) - else: - callback.set_value(None) - pass - - def _on_jabber_rpc_method_fault(self, iq): - iq.enable('rpc_query') - fault = xml2fault(iq['rpc_query']['method_response']['fault']) - pid = iq['id'] - with self._lock: - callback = self._callbacks[pid] - del self._callbacks[pid] - e = { - 500: InvocationException - }[fault['code']](fault['string']) - callback.cancel_with_error(e) - - def _on_jabber_rpc_error(self, iq): - pid = iq['id'] - pmethod = self._client.plugin['xep_0009']._extract_method(iq['rpc_query']) - code = iq['error']['code'] - type = iq['error']['type'] - condition = iq['error']['condition'] - #! print("['REMOTE.PY']._BINDING_handle_remote_procedure_error -> ERROR! ERROR! ERROR! Condition is '%s'" % condition) - with self._lock: - callback = self._callbacks[pid] - del self._callbacks[pid] - e = { - 'item-not-found': RemoteException("No remote handler available for %s at %s!" % (pmethod, iq['from'])), - 'forbidden': AuthorizationException("Forbidden to invoke remote handler for %s at %s!" % (pmethod, iq['from'])), - 'undefined-condition': RemoteException("An unexpected problem occured trying to invoke %s at %s!" % (pmethod, iq['from'])), - }[condition] - if e is None: - RemoteException("An unexpected exception occurred at %s!" % iq['from']) - callback.cancel_with_error(e) - - -class Remote(object): - ''' - Bootstrap class for Jabber-RPC sessions. New sessions are openend - with an existing XMPP client, or one is instantiated on demand. - ''' - _instance = None - _sessions = dict() - _lock = threading.RLock() - - @classmethod - def new_session_with_client(cls, client, callback=None): - ''' - Opens a new session with a given client. - - Arguments: - client -- An XMPP client. - callback -- An optional callback which can be used to track - the starting state of the session. - ''' - with Remote._lock: - if(client.boundjid.bare in cls._sessions): - raise RemoteException("There already is a session associated with these credentials!") - else: - cls._sessions[client.boundjid.bare] = client; - def _session_close_callback(): - with Remote._lock: - del cls._sessions[client.boundjid.bare] - result = RemoteSession(client, _session_close_callback) - client.plugin['xep_0009'].xmpp.add_event_handler('jabber_rpc_method_call', result._on_jabber_rpc_method_call, threaded=True) - client.plugin['xep_0009'].xmpp.add_event_handler('jabber_rpc_method_response', result._on_jabber_rpc_method_response, threaded=True) - client.plugin['xep_0009'].xmpp.add_event_handler('jabber_rpc_method_fault', result._on_jabber_rpc_method_fault, threaded=True) - client.plugin['xep_0009'].xmpp.add_event_handler('jabber_rpc_error', result._on_jabber_rpc_error, threaded=True) - if callback is None: - start_event_handler = result._notify - else: - start_event_handler = callback - client.add_event_handler("session_start", start_event_handler) - if client.connect(): - client.process(threaded=True) - else: - raise RemoteException("Could not connect to XMPP server!") - pass - if callback is None: - result._wait() - return result - - @classmethod - def new_session(cls, jid, password, callback=None): - ''' - Opens a new session and instantiates a new XMPP client. - - Arguments: - jid -- The XMPP JID for logging in. - password -- The password for logging in. - callback -- An optional callback which can be used to track - the starting state of the session. - ''' - client = sleekxmpp.ClientXMPP(jid, password) - #? Register plug-ins. - client.registerPlugin('xep_0004') # Data Forms - client.registerPlugin('xep_0009') # Jabber-RPC - client.registerPlugin('xep_0030') # Service Discovery - client.registerPlugin('xep_0060') # PubSub - client.registerPlugin('xep_0199') # XMPP Ping - return cls.new_session_with_client(client, callback) - diff --git a/sleekxmpp/plugins/xep_0009/rpc.py b/sleekxmpp/plugins/xep_0009/rpc.py deleted file mode 100644 index 3378c650..00000000 --- a/sleekxmpp/plugins/xep_0009/rpc.py +++ /dev/null @@ -1,218 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import Iq -from sleekxmpp.xmlstream import ET, register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0009 import stanza -from sleekxmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse - - -log = logging.getLogger(__name__) - - -class XEP_0009(BasePlugin): - - name = 'xep_0009' - description = 'XEP-0009: Jabber-RPC' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, RPCQuery) - register_stanza_plugin(RPCQuery, MethodCall) - register_stanza_plugin(RPCQuery, MethodResponse) - - self.xmpp.register_handler( - Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), - self._handle_method_call) - ) - self.xmpp.register_handler( - Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), - self._handle_method_response) - ) - self.xmpp.register_handler( - Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)), - self._handle_error) - ) - self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call) - self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response) - self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault) - self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error) - self.xmpp.add_event_handler('error', self._handle_error) - #self.activeCalls = [] - - self.xmpp['xep_0030'].add_feature('jabber:iq:rpc') - self.xmpp['xep_0030'].add_identity('automation','rpc') - - def make_iq_method_call(self, pto, pmethod, params): - iq = self.xmpp.makeIqSet() - iq.attrib['to'] = pto - iq.attrib['from'] = self.xmpp.boundjid.full - iq.enable('rpc_query') - iq['rpc_query']['method_call']['method_name'] = pmethod - iq['rpc_query']['method_call']['params'] = params - return iq; - - def make_iq_method_response(self, pid, pto, params): - iq = self.xmpp.makeIqResult(pid) - iq.attrib['to'] = pto - iq.attrib['from'] = self.xmpp.boundjid.full - iq.enable('rpc_query') - iq['rpc_query']['method_response']['params'] = params - return iq - - def make_iq_method_response_fault(self, pid, pto, params): - iq = self.xmpp.makeIqResult(pid) - iq.attrib['to'] = pto - iq.attrib['from'] = self.xmpp.boundjid.full - iq.enable('rpc_query') - iq['rpc_query']['method_response']['params'] = None - iq['rpc_query']['method_response']['fault'] = params - return iq - -# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition): -# iq = self.xmpp.makeIqError(pid) -# iq.attrib['to'] = pto -# iq.attrib['from'] = self.xmpp.boundjid.full -# iq['error']['code'] = code -# iq['error']['type'] = type -# iq['error']['condition'] = condition -# iq['rpc_query']['method_call']['method_name'] = pmethod -# iq['rpc_query']['method_call']['params'] = params -# return iq - - def _item_not_found(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload); - iq['error']['code'] = '404' - iq['error']['type'] = 'cancel' - iq['error']['condition'] = 'item-not-found' - return iq - - def _undefined_condition(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload) - iq['error']['code'] = '500' - iq['error']['type'] = 'cancel' - iq['error']['condition'] = 'undefined-condition' - return iq - - def _forbidden(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload) - iq['error']['code'] = '403' - iq['error']['type'] = 'auth' - iq['error']['condition'] = 'forbidden' - return iq - - def _recipient_unvailable(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload) - iq['error']['code'] = '404' - iq['error']['type'] = 'wait' - iq['error']['condition'] = 'recipient-unavailable' - return iq - - def _handle_method_call(self, iq): - type = iq['type'] - if type == 'set': - log.debug("Incoming Jabber-RPC call from %s", iq['from']) - self.xmpp.event('jabber_rpc_method_call', iq) - else: - if type == 'error' and ['rpc_query'] is None: - self.handle_error(iq) - else: - log.debug("Incoming Jabber-RPC error from %s", iq['from']) - self.xmpp.event('jabber_rpc_error', iq) - - def _handle_method_response(self, iq): - if iq['rpc_query']['method_response']['fault'] is not None: - log.debug("Incoming Jabber-RPC fault from %s", iq['from']) - #self._on_jabber_rpc_method_fault(iq) - self.xmpp.event('jabber_rpc_method_fault', iq) - else: - log.debug("Incoming Jabber-RPC response from %s", iq['from']) - self.xmpp.event('jabber_rpc_method_response', iq) - - def _handle_error(self, iq): - print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq) - print("#######################") - print("### NOT IMPLEMENTED ###") - print("#######################") - - def _on_jabber_rpc_method_call(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC method call. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1: - return - # Reply with error by default - error = self.client.plugin['xep_0009']._item_not_found(iq) - error.send() - - def _on_jabber_rpc_method_response(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC method response. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1: - return - error = self.client.plugin['xep_0009']._recpient_unavailable(iq) - error.send() - - def _on_jabber_rpc_method_fault(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC fault response. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1: - return - error = self.client.plugin['xep_0009']._recpient_unavailable(iq) - error.send() - - def _on_jabber_rpc_error(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC error response. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1: - return - error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload()) - error.send() - - def _send_fault(self, iq, fault_xml): # - fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml) - fault.send() - - def _send_error(self, iq): - print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq) - print("#######################") - print("### NOT IMPLEMENTED ###") - print("#######################") - - def _extract_method(self, stanza): - xml = ET.fromstring("%s" % stanza) - return xml.find("./methodCall/methodName").text diff --git a/sleekxmpp/plugins/xep_0009/stanza/RPC.py b/sleekxmpp/plugins/xep_0009/stanza/RPC.py deleted file mode 100644 index 3d1c77a2..00000000 --- a/sleekxmpp/plugins/xep_0009/stanza/RPC.py +++ /dev/null @@ -1,64 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream.stanzabase import ElementBase -from xml.etree import cElementTree as ET - - -class RPCQuery(ElementBase): - name = 'query' - namespace = 'jabber:iq:rpc' - plugin_attrib = 'rpc_query' - interfaces = set(()) - subinterfaces = set(()) - plugin_attrib_map = {} - plugin_tag_map = {} - - -class MethodCall(ElementBase): - name = 'methodCall' - namespace = 'jabber:iq:rpc' - plugin_attrib = 'method_call' - interfaces = set(('method_name', 'params')) - subinterfaces = set(()) - plugin_attrib_map = {} - plugin_tag_map = {} - - def get_method_name(self): - return self._get_sub_text('methodName') - - def set_method_name(self, value): - return self._set_sub_text('methodName', value) - - def get_params(self): - return self.xml.find('{%s}params' % self.namespace) - - def set_params(self, params): - self.append(params) - - -class MethodResponse(ElementBase): - name = 'methodResponse' - namespace = 'jabber:iq:rpc' - plugin_attrib = 'method_response' - interfaces = set(('params', 'fault')) - subinterfaces = set(()) - plugin_attrib_map = {} - plugin_tag_map = {} - - def get_params(self): - return self.xml.find('{%s}params' % self.namespace) - - def set_params(self, params): - self.append(params) - - def get_fault(self): - return self.xml.find('{%s}fault' % self.namespace) - - def set_fault(self, fault): - self.append(fault) diff --git a/sleekxmpp/plugins/xep_0009/stanza/__init__.py b/sleekxmpp/plugins/xep_0009/stanza/__init__.py deleted file mode 100644 index 5dcbf330..00000000 --- a/sleekxmpp/plugins/xep_0009/stanza/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse diff --git a/sleekxmpp/plugins/xep_0012/__init__.py b/sleekxmpp/plugins/xep_0012/__init__.py deleted file mode 100644 index 6b778fc1..00000000 --- a/sleekxmpp/plugins/xep_0012/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0012.stanza import LastActivity -from sleekxmpp.plugins.xep_0012.last_activity import XEP_0012 - - -register_plugin(XEP_0012) - - -# Retain some backwards compatibility -xep_0004 = XEP_0012 diff --git a/sleekxmpp/plugins/xep_0012/last_activity.py b/sleekxmpp/plugins/xep_0012/last_activity.py deleted file mode 100644 index 8790b47c..00000000 --- a/sleekxmpp/plugins/xep_0012/last_activity.py +++ /dev/null @@ -1,157 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging -from datetime import datetime, timedelta - -from sleekxmpp.plugins import BasePlugin, register_plugin -from sleekxmpp import Iq -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import JID, register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins.xep_0012 import stanza, LastActivity - - -log = logging.getLogger(__name__) - - -class XEP_0012(BasePlugin): - - """ - XEP-0012 Last Activity - """ - - name = 'xep_0012' - description = 'XEP-0012: Last Activity' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, LastActivity) - - self._last_activities = {} - - self.xmpp.register_handler( - Callback('Last Activity', - StanzaPath('iq@type=get/last_activity'), - self._handle_get_last_activity)) - - self.api.register(self._default_get_last_activity, - 'get_last_activity', - default=True) - self.api.register(self._default_set_last_activity, - 'set_last_activity', - default=True) - self.api.register(self._default_del_last_activity, - 'del_last_activity', - default=True) - - def plugin_end(self): - self.xmpp.remove_handler('Last Activity') - self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('jabber:iq:last') - - def begin_idle(self, jid=None, status=None): - self.set_last_activity(jid, 0, status) - - def end_idle(self, jid=None): - self.del_last_activity(jid) - - def start_uptime(self, status=None): - self.set_last_activity(jid, 0, status) - - def set_last_activity(self, jid=None, seconds=None, status=None): - self.api['set_last_activity'](jid, args={ - 'seconds': seconds, - 'status': status}) - - def del_last_activity(self, jid): - self.api['del_last_activity'](jid) - - def get_last_activity(self, jid, local=False, ifrom=None, block=True, - timeout=None, callback=None): - if jid is not None and not isinstance(jid, JID): - jid = JID(jid) - - if self.xmpp.is_component: - if jid.domain == self.xmpp.boundjid.domain: - local = True - else: - if str(jid) == str(self.xmpp.boundjid): - local = True - jid = jid.full - - if local or jid in (None, ''): - log.debug("Looking up local last activity data for %s", jid) - return self.api['get_last_activity'](jid, None, ifrom, None) - - iq = self.xmpp.Iq() - iq['from'] = ifrom - iq['to'] = jid - iq['type'] = 'get' - iq.enable('last_activity') - return iq.send(timeout=timeout, - block=block, - callback=callback) - - def _handle_get_last_activity(self, iq): - log.debug("Received last activity query from " + \ - "<%s> to <%s>.", iq['from'], iq['to']) - reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq) - reply.send() - - # ================================================================= - # Default in-memory implementations for storing last activity data. - # ================================================================= - - def _default_set_last_activity(self, jid, node, ifrom, data): - seconds = data.get('seconds', None) - if seconds is None: - seconds = 0 - - status = data.get('status', None) - if status is None: - status = '' - - self._last_activities[jid] = { - 'seconds': datetime.now() - timedelta(seconds=seconds), - 'status': status} - - def _default_del_last_activity(self, jid, node, ifrom, data): - if jid in self._last_activities: - del self._last_activities[jid] - - def _default_get_last_activity(self, jid, node, ifrom, iq): - if not isinstance(iq, Iq): - reply = self.xmpp.Iq() - else: - iq.reply() - reply = iq - - if jid not in self._last_activities: - raise XMPPError('service-unavailable') - - bare = JID(jid).bare - - if bare != self.xmpp.boundjid.bare: - if bare in self.xmpp.roster[jid]: - sub = self.xmpp.roster[jid][bare]['subscription'] - if sub not in ('from', 'both'): - raise XMPPError('forbidden') - - td = datetime.now() - self._last_activities[jid]['seconds'] - seconds = td.seconds + td.days * 24 * 3600 - status = self._last_activities[jid]['status'] - - reply['last_activity']['seconds'] = seconds - reply['last_activity']['status'] = status - - return reply diff --git a/sleekxmpp/plugins/xep_0012/stanza.py b/sleekxmpp/plugins/xep_0012/stanza.py deleted file mode 100644 index 079865b9..00000000 --- a/sleekxmpp/plugins/xep_0012/stanza.py +++ /dev/null @@ -1,32 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase - - -class LastActivity(ElementBase): - - name = 'query' - namespace = 'jabber:iq:last' - plugin_attrib = 'last_activity' - interfaces = set(('seconds', 'status')) - - def get_seconds(self): - return int(self._get_attr('seconds')) - - def set_seconds(self, value): - self._set_attr('seconds', str(value)) - - def get_status(self): - return self.xml.text - - def set_status(self, value): - self.xml.text = str(value) - - def del_status(self): - self.xml.text = '' diff --git a/sleekxmpp/plugins/xep_0013/__init__.py b/sleekxmpp/plugins/xep_0013/__init__.py deleted file mode 100644 index ad400949..00000000 --- a/sleekxmpp/plugins/xep_0013/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permissio -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0013.stanza import Offline -from sleekxmpp.plugins.xep_0013.offline import XEP_0013 - - -register_plugin(XEP_0013) diff --git a/sleekxmpp/plugins/xep_0013/offline.py b/sleekxmpp/plugins/xep_0013/offline.py deleted file mode 100644 index a0d992a7..00000000 --- a/sleekxmpp/plugins/xep_0013/offline.py +++ /dev/null @@ -1,134 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permissio -""" - -import logging - -import sleekxmpp -from sleekxmpp.stanza import Message, Iq -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream.handler import Collector -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0013 import stanza - - -log = logging.getLogger(__name__) - - -class XEP_0013(BasePlugin): - - """ - XEP-0013 Flexible Offline Message Retrieval - """ - - name = 'xep_0013' - description = 'XEP-0013: Flexible Offline Message Retrieval' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, stanza.Offline) - register_stanza_plugin(Message, stanza.Offline) - - def get_count(self, **kwargs): - return self.xmpp['xep_0030'].get_info( - node='http://jabber.org/protocol/offline', - local=False, - **kwargs) - - def get_headers(self, **kwargs): - return self.xmpp['xep_0030'].get_items( - node='http://jabber.org/protocol/offline', - local=False, - **kwargs) - - def view(self, nodes, ifrom=None, block=True, timeout=None, callback=None): - if not isinstance(nodes, (list, set)): - nodes = [nodes] - - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['from'] = ifrom - offline = iq['offline'] - for node in nodes: - item = stanza.Item() - item['node'] = node - item['action'] = 'view' - offline.append(item) - - collector = Collector( - 'Offline_Results_%s' % iq['id'], - StanzaPath('message/offline')) - self.xmpp.register_handler(collector) - - if not block and callback is not None: - def wrapped_cb(iq): - results = collector.stop() - if iq['type'] == 'result': - iq['offline']['results'] = results - callback(iq) - return iq.send(block=block, timeout=timeout, callback=wrapped_cb) - else: - try: - resp = iq.send(block=block, timeout=timeout, callback=callback) - resp['offline']['results'] = collector.stop() - return resp - except XMPPError as e: - collector.stop() - raise e - - def remove(self, nodes, ifrom=None, block=True, timeout=None, callback=None): - if not isinstance(nodes, (list, set)): - nodes = [nodes] - - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - offline = iq['offline'] - for node in nodes: - item = stanza.Item() - item['node'] = node - item['action'] = 'remove' - offline.append(item) - - return iq.send(block=block, timeout=timeout, callback=callback) - - def fetch(self, ifrom=None, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - iq['offline']['fetch'] = True - - collector = Collector( - 'Offline_Results_%s' % iq['id'], - StanzaPath('message/offline')) - self.xmpp.register_handler(collector) - - if not block and callback is not None: - def wrapped_cb(iq): - results = collector.stop() - if iq['type'] == 'result': - iq['offline']['results'] = results - callback(iq) - return iq.send(block=block, timeout=timeout, callback=wrapped_cb) - else: - try: - resp = iq.send(block=block, timeout=timeout, callback=callback) - resp['offline']['results'] = collector.stop() - return resp - except XMPPError as e: - collector.stop() - raise e - - def purge(self, ifrom=None, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - iq['offline']['purge'] = True - return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/xep_0013/stanza.py b/sleekxmpp/plugins/xep_0013/stanza.py deleted file mode 100644 index c9c69786..00000000 --- a/sleekxmpp/plugins/xep_0013/stanza.py +++ /dev/null @@ -1,53 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permissio -""" - -from sleekxmpp.jid import JID -from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin - - -class Offline(ElementBase): - name = 'offline' - namespace = 'http://jabber.org/protocol/offline' - plugin_attrib = 'offline' - interfaces = set(['fetch', 'purge', 'results']) - bool_interfaces = interfaces - - def setup(self, xml=None): - ElementBase.setup(self, xml) - self._results = [] - - # The results interface is meant only as an easy - # way to access the set of collected message responses - # from the query. - - def get_results(self): - return self._results - - def set_results(self, values): - self._results = values - - def del_results(self): - self._results = [] - - -class Item(ElementBase): - name = 'item' - namespace = 'http://jabber.org/protocol/offline' - plugin_attrib = 'item' - interfaces = set(['action', 'node', 'jid']) - - actions = set(['view', 'remove']) - - def get_jid(self): - return JID(self._get_attr('jid')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - -register_stanza_plugin(Offline, Item, iterable=True) diff --git a/sleekxmpp/plugins/xep_0016/__init__.py b/sleekxmpp/plugins/xep_0016/__init__.py deleted file mode 100644 index 06704d26..00000000 --- a/sleekxmpp/plugins/xep_0016/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0016 import stanza -from sleekxmpp.plugins.xep_0016.stanza import Privacy -from sleekxmpp.plugins.xep_0016.privacy import XEP_0016 - - -register_plugin(XEP_0016) diff --git a/sleekxmpp/plugins/xep_0016/privacy.py b/sleekxmpp/plugins/xep_0016/privacy.py deleted file mode 100644 index 79fd68f0..00000000 --- a/sleekxmpp/plugins/xep_0016/privacy.py +++ /dev/null @@ -1,110 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp import Iq -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0016 import stanza -from sleekxmpp.plugins.xep_0016.stanza import Privacy, Item - - -class XEP_0016(BasePlugin): - - name = 'xep_0016' - description = 'XEP-0016: Privacy Lists' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, Privacy) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=Privacy.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(Privacy.namespace) - - def get_privacy_lists(self, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq.enable('privacy') - return iq.send(block=block, timeout=timeout, callback=callback) - - def get_list(self, name, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['privacy']['list']['name'] = name - return iq.send(block=block, timeout=timeout, callback=callback) - - def get_active(self, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['privacy'].enable('active') - return iq.send(block=block, timeout=timeout, callback=callback) - - def get_default(self, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['privacy'].enable('default') - return iq.send(block=block, timeout=timeout, callback=callback) - - def activate(self, name, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['privacy']['active']['name'] = name - return iq.send(block=block, timeout=timeout, callback=callback) - - def deactivate(self, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['privacy'].enable('active') - return iq.send(block=block, timeout=timeout, callback=callback) - - def make_default(self, name, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['privacy']['default']['name'] = name - return iq.send(block=block, timeout=timeout, callback=callback) - - def remove_default(self, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['privacy'].enable('default') - return iq.send(block=block, timeout=timeout, callback=callback) - - def edit_list(self, name, rules, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['privacy']['list']['name'] = name - priv_list = iq['privacy']['list'] - - if not rules: - rules = [] - - for rule in rules: - if isinstance(rule, Item): - priv_list.append(rule) - continue - - priv_list.add_item( - rule['value'], - rule['action'], - rule['order'], - itype=rule.get('type', None), - iq=rule.get('iq', None), - message=rule.get('message', None), - presence_in=rule.get('presence_in', - rule.get('presence-in', None)), - presence_out=rule.get('presence_out', - rule.get('presence-out', None))) - - def remove_list(self, name, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['privacy']['list']['name'] = name - return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/xep_0016/stanza.py b/sleekxmpp/plugins/xep_0016/stanza.py deleted file mode 100644 index 3f9977fc..00000000 --- a/sleekxmpp/plugins/xep_0016/stanza.py +++ /dev/null @@ -1,103 +0,0 @@ -from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin - - -class Privacy(ElementBase): - name = 'query' - namespace = 'jabber:iq:privacy' - plugin_attrib = 'privacy' - interfaces = set() - - def add_list(self, name): - priv_list = List() - priv_list['name'] = name - self.append(priv_list) - return priv_list - - -class Active(ElementBase): - name = 'active' - namespace = 'jabber:iq:privacy' - plugin_attrib = name - interfaces = set(['name']) - - -class Default(ElementBase): - name = 'default' - namespace = 'jabber:iq:privacy' - plugin_attrib = name - interfaces = set(['name']) - - -class List(ElementBase): - name = 'list' - namespace = 'jabber:iq:privacy' - plugin_attrib = name - plugin_multi_attrib = 'lists' - interfaces = set(['name']) - - def add_item(self, value, action, order, itype=None, iq=False, - message=False, presence_in=False, presence_out=False): - item = Item() - item.values = {'type': itype, - 'value': value, - 'action': action, - 'order': order, - 'message': message, - 'iq': iq, - 'presence_in': presence_in, - 'presence_out': presence_out} - self.append(item) - return item - - -class Item(ElementBase): - name = 'item' - namespace = 'jabber:iq:privacy' - plugin_attrib = name - plugin_multi_attrib = 'items' - interfaces = set(['type', 'value', 'action', 'order', 'iq', - 'message', 'presence_in', 'presence_out']) - bool_interfaces = set(['message', 'iq', 'presence_in', 'presence_out']) - - type_values = ('', 'jid', 'group', 'subscription') - action_values = ('allow', 'deny') - - def set_type(self, value): - if value and value not in self.type_values: - raise ValueError('Unknown type value: %s' % value) - else: - self._set_attr('type', value) - - def set_action(self, value): - if value not in self.action_values: - raise ValueError('Unknown action value: %s' % value) - else: - self._set_attr('action', value) - - def set_presence_in(self, value): - keep = True if value else False - self._set_sub_text('presence-in', '', keep=keep) - - def get_presence_in(self): - pres = self.xml.find('{%s}presence-in' % self.namespace) - return pres is not None - - def del_presence_in(self): - self._del_sub('{%s}presence-in' % self.namespace) - - def set_presence_out(self, value): - keep = True if value else False - self._set_sub_text('presence-in', '', keep=keep) - - def get_presence_out(self): - pres = self.xml.find('{%s}presence-in' % self.namespace) - return pres is not None - - def del_presence_out(self): - self._del_sub('{%s}presence-in' % self.namespace) - - -register_stanza_plugin(Privacy, Active) -register_stanza_plugin(Privacy, Default) -register_stanza_plugin(Privacy, List, iterable=True) -register_stanza_plugin(List, Item, iterable=True) diff --git a/sleekxmpp/plugins/xep_0020/__init__.py b/sleekxmpp/plugins/xep_0020/__init__.py deleted file mode 100644 index c6aafe97..00000000 --- a/sleekxmpp/plugins/xep_0020/__init__.py +++ /dev/null @@ -1,16 +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 - -from sleekxmpp.plugins.xep_0020 import stanza -from sleekxmpp.plugins.xep_0020.stanza import FeatureNegotiation -from sleekxmpp.plugins.xep_0020.feature_negotiation import XEP_0020 - - -register_plugin(XEP_0020) diff --git a/sleekxmpp/plugins/xep_0020/feature_negotiation.py b/sleekxmpp/plugins/xep_0020/feature_negotiation.py deleted file mode 100644 index 7cb82cd5..00000000 --- a/sleekxmpp/plugins/xep_0020/feature_negotiation.py +++ /dev/null @@ -1,36 +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 import Iq, Message -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.plugins.xep_0020 import stanza, FeatureNegotiation -from sleekxmpp.plugins.xep_0004 import Form - - -log = logging.getLogger(__name__) - - -class XEP_0020(BasePlugin): - - name = 'xep_0020' - description = 'XEP-0020: Feature Negotiation' - dependencies = set(['xep_0004', 'xep_0030']) - stanza = stanza - - def plugin_init(self): - self.xmpp['xep_0030'].add_feature(FeatureNegotiation.namespace) - - register_stanza_plugin(FeatureNegotiation, Form) - - register_stanza_plugin(Iq, FeatureNegotiation) - register_stanza_plugin(Message, FeatureNegotiation) diff --git a/sleekxmpp/plugins/xep_0020/stanza.py b/sleekxmpp/plugins/xep_0020/stanza.py deleted file mode 100644 index 13e4056e..00000000 --- a/sleekxmpp/plugins/xep_0020/stanza.py +++ /dev/null @@ -1,17 +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 - - -class FeatureNegotiation(ElementBase): - - name = 'feature' - namespace = 'http://jabber.org/protocol/feature-neg' - plugin_attrib = 'feature_neg' - interfaces = set() diff --git a/sleekxmpp/plugins/xep_0027/__init__.py b/sleekxmpp/plugins/xep_0027/__init__.py deleted file mode 100644 index b6ed9676..00000000 --- a/sleekxmpp/plugins/xep_0027/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0027.stanza import Signed, Encrypted -from sleekxmpp.plugins.xep_0027.gpg import XEP_0027 - - -register_plugin(XEP_0027) diff --git a/sleekxmpp/plugins/xep_0027/gpg.py b/sleekxmpp/plugins/xep_0027/gpg.py deleted file mode 100644 index 52c1c461..00000000 --- a/sleekxmpp/plugins/xep_0027/gpg.py +++ /dev/null @@ -1,170 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.thirdparty import GPG - -from sleekxmpp.stanza import Presence, Message -from sleekxmpp.plugins.base import BasePlugin, register_plugin -from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins.xep_0027 import stanza, Signed, Encrypted - - -def _extract_data(data, kind): - stripped = [] - begin_headers = False - begin_data = False - for line in data.split('\n'): - if not begin_headers and 'BEGIN PGP %s' % kind in line: - begin_headers = True - continue - if begin_headers and line.strip() == '': - begin_data = True - continue - if 'END PGP %s' % kind in line: - return '\n'.join(stripped) - if begin_data: - stripped.append(line) - return '' - - -class XEP_0027(BasePlugin): - - name = 'xep_0027' - description = 'XEP-0027: Current Jabber OpenPGP Usage' - dependencies = set() - stanza = stanza - default_config = { - 'gpg_binary': 'gpg', - 'gpg_home': '', - 'use_agent': True, - 'keyring': None, - 'key_server': 'pgp.mit.edu' - } - - def plugin_init(self): - self.gpg = GPG(gnupghome=self.gpg_home, - gpgbinary=self.gpg_binary, - use_agent=self.use_agent, - keyring=self.keyring) - - self.xmpp.add_filter('out', self._sign_presence) - - self._keyids = {} - - self.api.register(self._set_keyid, 'set_keyid', default=True) - self.api.register(self._get_keyid, 'get_keyid', default=True) - self.api.register(self._del_keyid, 'del_keyid', default=True) - self.api.register(self._get_keyids, 'get_keyids', default=True) - - register_stanza_plugin(Presence, Signed) - register_stanza_plugin(Message, Encrypted) - - self.xmpp.add_event_handler('unverified_signed_presence', - self._handle_unverified_signed_presence, - threaded=True) - - self.xmpp.register_handler( - Callback('Signed Presence', - StanzaPath('presence/signed'), - self._handle_signed_presence)) - - self.xmpp.register_handler( - Callback('Encrypted Message', - StanzaPath('message/encrypted'), - self._handle_encrypted_message)) - - def plugin_end(self): - self.xmpp.remove_handler('Encrypted Message') - self.xmpp.remove_handler('Signed Presence') - self.xmpp.del_filter('out', self._sign_presence) - self.xmpp.del_event_handler('unverified_signed_presence', - self._handle_unverified_signed_presence) - - def _sign_presence(self, stanza): - if isinstance(stanza, Presence): - if stanza['type'] == 'available' or \ - stanza['type'] in Presence.showtypes: - stanza['signed'] = stanza['status'] - return stanza - - def sign(self, data, jid=None): - keyid = self.get_keyid(jid) - if keyid: - signed = self.gpg.sign(data, keyid=keyid) - return _extract_data(signed.data, 'SIGNATURE') - - def encrypt(self, data, jid=None): - keyid = self.get_keyid(jid) - if keyid: - enc = self.gpg.encrypt(data, keyid) - return _extract_data(enc.data, 'MESSAGE') - - def decrypt(self, data, jid=None): - template = '-----BEGIN PGP MESSAGE-----\n' + \ - '\n' + \ - '%s\n' + \ - '-----END PGP MESSAGE-----\n' - dec = self.gpg.decrypt(template % data) - return dec.data - - def verify(self, data, sig, jid=None): - template = '-----BEGIN PGP SIGNED MESSAGE-----\n' + \ - 'Hash: SHA1\n' + \ - '\n' + \ - '%s\n' + \ - '-----BEGIN PGP SIGNATURE-----\n' + \ - '\n' + \ - '%s\n' + \ - '-----END PGP SIGNATURE-----\n' - v = self.gpg.verify(template % (data, sig)) - return v - - def set_keyid(self, jid=None, keyid=None): - self.api['set_keyid'](jid, args=keyid) - - def get_keyid(self, jid=None): - return self.api['get_keyid'](jid) - - def del_keyid(self, jid=None): - self.api['del_keyid'](jid) - - def get_keyids(self): - return self.api['get_keyids']() - - def _handle_signed_presence(self, pres): - self.xmpp.event('unverified_signed_presence', pres) - - def _handle_unverified_signed_presence(self, pres): - verified = self.verify(pres['status'], pres['signed']) - if verified.key_id: - if not self.get_keyid(pres['from']): - known_keyids = [e['keyid'] for e in self.gpg.list_keys()] - if verified.key_id not in known_keyids: - self.gpg.recv_keys(self.key_server, verified.key_id) - self.set_keyid(jid=pres['from'], keyid=verified.key_id) - self.xmpp.event('signed_presence', pres) - - def _handle_encrypted_message(self, msg): - self.xmpp.event('encrypted_message', msg) - - # ================================================================= - - def _set_keyid(self, jid, node, ifrom, keyid): - self._keyids[jid] = keyid - - def _get_keyid(self, jid, node, ifrom, keyid): - return self._keyids.get(jid, None) - - def _del_keyid(self, jid, node, ifrom, keyid): - if jid in self._keyids: - del self._keyids[jid] - - def _get_keyids(self, jid, node, ifrom, data): - return self._keyids diff --git a/sleekxmpp/plugins/xep_0027/stanza.py b/sleekxmpp/plugins/xep_0027/stanza.py deleted file mode 100644 index 08f2032b..00000000 --- a/sleekxmpp/plugins/xep_0027/stanza.py +++ /dev/null @@ -1,53 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase - - -class Signed(ElementBase): - name = 'x' - namespace = 'jabber:x:signed' - plugin_attrib = 'signed' - interfaces = set(['signed']) - is_extension = True - - def set_signed(self, value): - parent = self.parent() - xmpp = parent.stream - data = xmpp['xep_0027'].sign(value, parent['from']) - if data: - self.xml.text = data - else: - del parent['signed'] - - def get_signed(self): - return self.xml.text - - -class Encrypted(ElementBase): - name = 'x' - namespace = 'jabber:x:encrypted' - plugin_attrib = 'encrypted' - interfaces = set(['encrypted']) - is_extension = True - - def set_encrypted(self, value): - parent = self.parent() - xmpp = parent.stream - data = xmpp['xep_0027'].encrypt(value, parent['to']) - if data: - self.xml.text = data - else: - del parent['encrypted'] - - def get_encrypted(self): - parent = self.parent() - xmpp = parent.stream - if self.xml.text: - return xmpp['xep_0027'].decrypt(self.xml.text, parent['to']) - return None diff --git a/sleekxmpp/plugins/xep_0030/__init__.py b/sleekxmpp/plugins/xep_0030/__init__.py deleted file mode 100644 index 0d1de65b..00000000 --- a/sleekxmpp/plugins/xep_0030/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0030 import stanza -from sleekxmpp.plugins.xep_0030.stanza import DiscoInfo, DiscoItems -from sleekxmpp.plugins.xep_0030.static import StaticDisco -from sleekxmpp.plugins.xep_0030.disco import XEP_0030 - - -register_plugin(XEP_0030) - -# Retain some backwards compatibility -xep_0030 = XEP_0030 -XEP_0030.getInfo = XEP_0030.get_info -XEP_0030.getItems = XEP_0030.get_items -XEP_0030.make_static = XEP_0030.restore_defaults diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py deleted file mode 100644 index 8a397923..00000000 --- a/sleekxmpp/plugins/xep_0030/disco.py +++ /dev/null @@ -1,740 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import Iq -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.plugins.xep_0030 import stanza, DiscoInfo, DiscoItems -from sleekxmpp.plugins.xep_0030 import StaticDisco - - -log = logging.getLogger(__name__) - - -class XEP_0030(BasePlugin): - - """ - XEP-0030: Service Discovery - - Service discovery in XMPP allows entities to discover information about - other agents in the network, such as the feature sets supported by a - client, or signposts to other, related entities. - - Also see . - - The XEP-0030 plugin works using a hierarchy of dynamic - node handlers, ranging from global handlers to specific - JID+node handlers. The default set of handlers operate - in a static manner, storing disco information in memory. - However, custom handlers may use any available backend - storage mechanism desired, such as SQLite or Redis. - - Node handler hierarchy: - JID | Node | Level - --------------------- - None | None | Global - Given | None | All nodes for the JID - None | Given | Node on self.xmpp.boundjid - Given | Given | A single node - - Stream Handlers: - Disco Info -- Any Iq stanze that includes a query with the - namespace http://jabber.org/protocol/disco#info. - Disco Items -- Any Iq stanze that includes a query with the - namespace http://jabber.org/protocol/disco#items. - - Events: - disco_info -- Received a disco#info Iq query result. - disco_items -- Received a disco#items Iq query result. - disco_info_query -- Received a disco#info Iq query request. - disco_items_query -- Received a disco#items Iq query request. - - Attributes: - stanza -- A reference to the module containing the - stanza classes provided by this plugin. - static -- Object containing the default set of - static node handlers. - default_handlers -- A dictionary mapping operations to the default - global handler (by default, the static handlers). - xmpp -- The main SleekXMPP object. - - Methods: - set_node_handler -- Assign a handler to a JID/node combination. - del_node_handler -- Remove a handler from a JID/node combination. - get_info -- Retrieve disco#info data, locally or remote. - get_items -- Retrieve disco#items data, locally or remote. - set_identities -- - set_features -- - set_items -- - del_items -- - del_identity -- - del_feature -- - del_item -- - add_identity -- - add_feature -- - add_item -- - """ - - name = 'xep_0030' - description = 'XEP-0030: Service Discovery' - dependencies = set() - stanza = stanza - default_config = { - 'use_cache': True, - 'wrap_results': False - } - - def plugin_init(self): - """ - Start the XEP-0030 plugin. - """ - self.xmpp.register_handler( - Callback('Disco Info', - StanzaPath('iq/disco_info'), - self._handle_disco_info)) - - self.xmpp.register_handler( - Callback('Disco Items', - StanzaPath('iq/disco_items'), - self._handle_disco_items)) - - register_stanza_plugin(Iq, DiscoInfo) - register_stanza_plugin(Iq, DiscoItems) - - self.static = StaticDisco(self.xmpp, self) - - self._disco_ops = [ - 'get_info', 'set_info', 'set_identities', 'set_features', - 'get_items', 'set_items', 'del_items', 'add_identity', - 'del_identity', 'add_feature', 'del_feature', 'add_item', - 'del_item', 'del_identities', 'del_features', 'cache_info', - 'get_cached_info', 'supports', 'has_identity'] - - for op in self._disco_ops: - self.api.register(getattr(self.static, op), op, default=True) - - def _add_disco_op(self, op, default_handler): - self.api.register(default_handler, op) - self.api.register_default(default_handler, op) - - def set_node_handler(self, htype, jid=None, node=None, handler=None): - """ - Add a node handler for the given hierarchy level and - handler type. - - Node handlers are ordered in a hierarchy where the - most specific handler is executed. Thus, a fallback, - global handler can be used for the majority of cases - with a few node specific handler that override the - global behavior. - - Node handler hierarchy: - JID | Node | Level - --------------------- - None | None | Global - Given | None | All nodes for the JID - None | Given | Node on self.xmpp.boundjid - Given | Given | A single node - - Handler types: - get_info - get_items - set_identities - set_features - set_items - del_items - del_identities - del_identity - del_feature - del_features - del_item - add_identity - add_feature - add_item - - Arguments: - htype -- The operation provided by the handler. - jid -- The JID the handler applies to. May be narrowed - further if a node is given. - node -- The particular node the handler is for. If no JID - is given, then the self.xmpp.boundjid.full is - assumed. - handler -- The handler function to use. - """ - self.api.register(handler, htype, jid, node) - - def del_node_handler(self, htype, jid, node): - """ - Remove a handler type for a JID and node combination. - - The next handler in the hierarchy will be used if one - exists. If removing the global handler, make sure that - other handlers exist to process existing nodes. - - Node handler hierarchy: - JID | Node | Level - --------------------- - None | None | Global - Given | None | All nodes for the JID - None | Given | Node on self.xmpp.boundjid - Given | Given | A single node - - Arguments: - htype -- The type of handler to remove. - jid -- The JID from which to remove the handler. - node -- The node from which to remove the handler. - """ - self.api.unregister(htype, jid, node) - - def restore_defaults(self, jid=None, node=None, handlers=None): - """ - Change all or some of a node's handlers to the default - handlers. Useful for manually overriding the contents - of a node that would otherwise be handled by a JID level - or global level dynamic handler. - - The default is to use the built-in static handlers, but that - may be changed by modifying self.default_handlers. - - Arguments: - jid -- The JID owning the node to modify. - node -- The node to change to using static handlers. - handlers -- Optional list of handlers to change to the - default version. If provided, only these - handlers will be changed. Otherwise, all - handlers will use the default version. - """ - if handlers is None: - handlers = self._disco_ops - for op in handlers: - self.api.restore_default(op, jid, node) - - def supports(self, jid=None, node=None, feature=None, local=False, - cached=True, ifrom=None): - """ - Check if a JID supports a given feature. - - Return values: - True -- The feature is supported - False -- The feature is not listed as supported - None -- Nothing could be found due to a timeout - - Arguments: - jid -- Request info from this JID. - node -- The particular node to query. - feature -- The name of the feature to check. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the info. - cached -- If true, then look for the disco info data from - the local cache system. If no results are found, - send the query as usual. The self.use_cache - setting must be set to true for this option to - be useful. If set to false, then the cache will - be skipped, even if a result has already been - cached. Defaults to false. - ifrom -- Specifiy the sender's JID. - """ - data = {'feature': feature, - 'local': local, - 'cached': cached} - return self.api['supports'](jid, node, ifrom, data) - - def has_identity(self, jid=None, node=None, category=None, itype=None, - lang=None, local=False, cached=True, ifrom=None): - """ - Check if a JID provides a given identity. - - Return values: - True -- The identity is provided - False -- The identity is not listed - None -- Nothing could be found due to a timeout - - Arguments: - jid -- Request info from this JID. - node -- The particular node to query. - category -- The category of the identity to check. - itype -- The type of the identity to check. - lang -- The language of the identity to check. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the info. - cached -- If true, then look for the disco info data from - the local cache system. If no results are found, - send the query as usual. The self.use_cache - setting must be set to true for this option to - be useful. If set to false, then the cache will - be skipped, even if a result has already been - cached. Defaults to false. - ifrom -- Specifiy the sender's JID. - """ - data = {'category': category, - 'itype': itype, - 'lang': lang, - 'local': local, - 'cached': cached} - return self.api['has_identity'](jid, node, ifrom, data) - - def get_info(self, jid=None, node=None, local=None, - cached=None, **kwargs): - """ - Retrieve the disco#info results from a given JID/node combination. - - Info may be retrieved from both local resources and remote agents; - the local parameter indicates if the information should be gathered - by executing the local node handlers, or if a disco#info stanza - must be generated and sent. - - If requesting items from a local JID/node, then only a DiscoInfo - stanza will be returned. Otherwise, an Iq stanza will be returned. - - Arguments: - jid -- Request info from this JID. - node -- The particular node to query. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the info. - cached -- If true, then look for the disco info data from - the local cache system. If no results are found, - send the query as usual. The self.use_cache - setting must be set to true for this option to - be useful. If set to false, then the cache will - be skipped, even if a result has already been - cached. Defaults to false. - ifrom -- Specifiy the sender's JID. - block -- If true, block and wait for the stanzas' reply. - timeout -- The time in seconds to block while waiting for - a reply. If None, then wait indefinitely. The - timeout value is only used when block=True. - callback -- Optional callback to execute when a reply is - received instead of blocking and waiting for - the reply. - timeout_callback -- Optional callback to execute when no result - has been received in timeout seconds. - """ - if local is None: - if jid is not None and not isinstance(jid, JID): - jid = JID(jid) - if self.xmpp.is_component: - if jid.domain == self.xmpp.boundjid.domain: - local = True - else: - if str(jid) == str(self.xmpp.boundjid): - local = True - jid = jid.full - elif jid in (None, ''): - local = True - - if local: - log.debug("Looking up local disco#info data " + \ - "for %s, node %s.", jid, node) - info = self.api['get_info'](jid, node, - kwargs.get('ifrom', None), - kwargs) - info = self._fix_default_info(info) - return self._wrap(kwargs.get('ifrom', None), jid, info) - - if cached: - log.debug("Looking up cached disco#info data " + \ - "for %s, node %s.", jid, node) - info = self.api['get_cached_info'](jid, node, - kwargs.get('ifrom', None), - kwargs) - if info is not None: - return self._wrap(kwargs.get('ifrom', None), jid, info) - - iq = self.xmpp.Iq() - # Check dfrom parameter for backwards compatibility - iq['from'] = kwargs.get('ifrom', kwargs.get('dfrom', '')) - iq['to'] = jid - iq['type'] = 'get' - iq['disco_info']['node'] = node if node else '' - return iq.send(timeout=kwargs.get('timeout', None), - block=kwargs.get('block', True), - callback=kwargs.get('callback', None), - timeout_callback=kwargs.get('timeout_callback', None)) - - def set_info(self, jid=None, node=None, info=None): - """ - Set the disco#info data for a JID/node based on an existing - disco#info stanza. - """ - if isinstance(info, Iq): - info = info['disco_info'] - self.api['set_info'](jid, node, None, info) - - def get_items(self, jid=None, node=None, local=False, **kwargs): - """ - Retrieve the disco#items results from a given JID/node combination. - - Items may be retrieved from both local resources and remote agents; - the local parameter indicates if the items should be gathered by - executing the local node handlers, or if a disco#items stanza must - be generated and sent. - - If requesting items from a local JID/node, then only a DiscoItems - stanza will be returned. Otherwise, an Iq stanza will be returned. - - Arguments: - jid -- Request info from this JID. - node -- The particular node to query. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the items. - ifrom -- Specifiy the sender's JID. - block -- If true, block and wait for the stanzas' reply. - timeout -- The time in seconds to block while waiting for - a reply. If None, then wait indefinitely. - callback -- Optional callback to execute when a reply is - received instead of blocking and waiting for - the reply. - iterator -- If True, return a result set iterator using - the XEP-0059 plugin, if the plugin is loaded. - Otherwise the parameter is ignored. - timeout_callback -- Optional callback to execute when no result - has been received in timeout seconds. - """ - if local or local is None and jid is None: - items = self.api['get_items'](jid, node, - kwargs.get('ifrom', None), - kwargs) - return self._wrap(kwargs.get('ifrom', None), jid, items) - - iq = self.xmpp.Iq() - # Check dfrom parameter for backwards compatibility - iq['from'] = kwargs.get('ifrom', kwargs.get('dfrom', '')) - iq['to'] = jid - iq['type'] = 'get' - iq['disco_items']['node'] = node if node else '' - if kwargs.get('iterator', False) and self.xmpp['xep_0059']: - return self.xmpp['xep_0059'].iterate(iq, 'disco_items') - else: - return iq.send(timeout=kwargs.get('timeout', None), - block=kwargs.get('block', True), - callback=kwargs.get('callback', None), - timeout_callback=kwargs.get('timeout_callback', None)) - - def set_items(self, jid=None, node=None, **kwargs): - """ - Set or replace all items for the specified JID/node combination. - - The given items must be in a list or set where each item is a - tuple of the form: (jid, node, name). - - Arguments: - jid -- The JID to modify. - node -- Optional node to modify. - items -- A series of items in tuple format. - """ - self.api['set_items'](jid, node, None, kwargs) - - def del_items(self, jid=None, node=None, **kwargs): - """ - Remove all items from the given JID/node combination. - - Arguments: - jid -- The JID to modify. - node -- Optional node to modify. - """ - self.api['del_items'](jid, node, None, kwargs) - - def add_item(self, jid='', name='', node=None, subnode='', ijid=None): - """ - Add a new item element to the given JID/node combination. - - Each item is required to have a JID, but may also specify - a node value to reference non-addressable entities. - - Arguments: - jid -- The JID for the item. - name -- Optional name for the item. - node -- The node to modify. - subnode -- Optional node for the item. - ijid -- The JID to modify. - """ - if not jid: - jid = self.xmpp.boundjid.full - kwargs = {'ijid': jid, - 'name': name, - 'inode': subnode} - self.api['add_item'](ijid, node, None, kwargs) - - def del_item(self, jid=None, node=None, **kwargs): - """ - Remove a single item from the given JID/node combination. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - ijid -- The item's JID. - inode -- The item's node. - """ - self.api['del_item'](jid, node, None, kwargs) - - def add_identity(self, category='', itype='', name='', - node=None, jid=None, lang=None): - """ - Add a new identity to the given JID/node combination. - - Each identity must be unique in terms of all four identity - components: category, type, name, and language. - - Multiple, identical category/type pairs are allowed only - if the xml:lang values are different. Likewise, multiple - category/type/xml:lang pairs are allowed so long as the - names are different. A category and type is always required. - - Arguments: - category -- The identity's category. - itype -- The identity's type. - name -- Optional name for the identity. - lang -- Optional two-letter language code. - node -- The node to modify. - jid -- The JID to modify. - """ - kwargs = {'category': category, - 'itype': itype, - 'name': name, - 'lang': lang} - self.api['add_identity'](jid, node, None, kwargs) - - def add_feature(self, feature, node=None, jid=None): - """ - Add a feature to a JID/node combination. - - Arguments: - feature -- The namespace of the supported feature. - node -- The node to modify. - jid -- The JID to modify. - """ - kwargs = {'feature': feature} - self.api['add_feature'](jid, node, None, kwargs) - - def del_identity(self, jid=None, node=None, **kwargs): - """ - Remove an identity from the given JID/node combination. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - category -- The identity's category. - itype -- The identity's type value. - name -- Optional, human readable name for the identity. - lang -- Optional, the identity's xml:lang value. - """ - self.api['del_identity'](jid, node, None, kwargs) - - def del_feature(self, jid=None, node=None, **kwargs): - """ - Remove a feature from a given JID/node combination. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - feature -- The feature's namespace. - """ - self.api['del_feature'](jid, node, None, kwargs) - - def set_identities(self, jid=None, node=None, **kwargs): - """ - Add or replace all identities for the given JID/node combination. - - The identities must be in a set where each identity is a tuple - of the form: (category, type, lang, name) - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - identities -- A set of identities in tuple form. - lang -- Optional, xml:lang value. - """ - self.api['set_identities'](jid, node, None, kwargs) - - def del_identities(self, jid=None, node=None, **kwargs): - """ - Remove all identities for a JID/node combination. - - If a language is specified, only identities using that - language will be removed. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - lang -- Optional. If given, only remove identities - using this xml:lang value. - """ - self.api['del_identities'](jid, node, None, kwargs) - - def set_features(self, jid=None, node=None, **kwargs): - """ - Add or replace the set of supported features - for a JID/node combination. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - features -- The new set of supported features. - """ - self.api['set_features'](jid, node, None, kwargs) - - def del_features(self, jid=None, node=None, **kwargs): - """ - Remove all features from a JID/node combination. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - """ - self.api['del_features'](jid, node, None, kwargs) - - def _run_node_handler(self, htype, jid, node=None, ifrom=None, data={}): - """ - Execute the most specific node handler for the given - JID/node combination. - - Arguments: - htype -- The handler type to execute. - jid -- The JID requested. - node -- The node requested. - data -- Optional, custom data to pass to the handler. - """ - return self.api[htype](jid, node, ifrom, data) - - def _handle_disco_info(self, iq): - """ - Process an incoming disco#info stanza. If it is a get - request, find and return the appropriate identities - and features. If it is an info result, fire the - disco_info event. - - Arguments: - iq -- The incoming disco#items stanza. - """ - if iq['type'] == 'get': - log.debug("Received disco info query from " + \ - "<%s> to <%s>.", iq['from'], iq['to']) - info = self.api['get_info'](iq['to'], - iq['disco_info']['node'], - iq['from'], - iq) - if isinstance(info, Iq): - info['id'] = iq['id'] - info.send() - else: - iq.reply() - if info: - info = self._fix_default_info(info) - iq.set_payload(info.xml) - iq.send() - elif iq['type'] == 'result': - log.debug("Received disco info result from " + \ - "<%s> to <%s>.", iq['from'], iq['to']) - if self.use_cache: - log.debug("Caching disco info result from " \ - "<%s> to <%s>.", iq['from'], iq['to']) - if self.xmpp.is_component: - ito = iq['to'].full - else: - ito = None - self.api['cache_info'](iq['from'], - iq['disco_info']['node'], - ito, - iq) - self.xmpp.event('disco_info', iq) - - def _handle_disco_items(self, iq): - """ - Process an incoming disco#items stanza. If it is a get - request, find and return the appropriate items. If it - is an items result, fire the disco_items event. - - Arguments: - iq -- The incoming disco#items stanza. - """ - if iq['type'] == 'get': - log.debug("Received disco items query from " + \ - "<%s> to <%s>.", iq['from'], iq['to']) - items = self.api['get_items'](iq['to'], - iq['disco_items']['node'], - iq['from'], - iq) - if isinstance(items, Iq): - items.send() - else: - iq.reply() - if items: - iq.set_payload(items.xml) - iq.send() - elif iq['type'] == 'result': - log.debug("Received disco items result from " + \ - "%s to %s.", iq['from'], iq['to']) - self.xmpp.event('disco_items', iq) - - def _fix_default_info(self, info): - """ - Disco#info results for a JID are required to include at least - one identity and feature. As a default, if no other identity is - provided, SleekXMPP will use either the generic component or the - bot client identity. A the standard disco#info feature will also be - added if no features are provided. - - Arguments: - info -- The disco#info quest (not the full Iq stanza) to modify. - """ - result = info - if isinstance(info, Iq): - info = info['disco_info'] - if not info['node']: - if not info['identities']: - if self.xmpp.is_component: - log.debug("No identity found for this entity. " + \ - "Using default component identity.") - info.add_identity('component', 'generic') - else: - log.debug("No identity found for this entity. " + \ - "Using default client identity.") - info.add_identity('client', 'bot') - if not info['features']: - log.debug("No features found for this entity. " + \ - "Using default disco#info feature.") - info.add_feature(info.namespace) - return result - - def _wrap(self, ito, ifrom, payload, force=False): - """ - Ensure that results are wrapped in an Iq stanza - if self.wrap_results has been set to True. - - Arguments: - ito -- The JID to use as the 'to' value - ifrom -- The JID to use as the 'from' value - payload -- The disco data to wrap - force -- Force wrapping, regardless of self.wrap_results - """ - if (force or self.wrap_results) and not isinstance(payload, Iq): - iq = self.xmpp.Iq() - # Since we're simulating a result, we have to treat - # the 'from' and 'to' values opposite the normal way. - iq['to'] = self.xmpp.boundjid if ito is None else ito - iq['from'] = self.xmpp.boundjid if ifrom is None else ifrom - iq['type'] = 'result' - iq.append(payload) - return iq - return payload diff --git a/sleekxmpp/plugins/xep_0030/stanza/__init__.py b/sleekxmpp/plugins/xep_0030/stanza/__init__.py deleted file mode 100644 index 0d97cf3d..00000000 --- a/sleekxmpp/plugins/xep_0030/stanza/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.xep_0030.stanza.info import DiscoInfo -from sleekxmpp.plugins.xep_0030.stanza.items import DiscoItems diff --git a/sleekxmpp/plugins/xep_0030/stanza/info.py b/sleekxmpp/plugins/xep_0030/stanza/info.py deleted file mode 100644 index 25d1d07f..00000000 --- a/sleekxmpp/plugins/xep_0030/stanza/info.py +++ /dev/null @@ -1,276 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 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, ET - - -class DiscoInfo(ElementBase): - - """ - XMPP allows for users and agents to find the identities and features - supported by other entities in the XMPP network through service discovery, - or "disco". In particular, the "disco#info" query type for stanzas is - used to request the list of identities and features offered by a JID. - - An identity is a combination of a category and type, such as the 'client' - category with a type of 'pc' to indicate the agent is a human operated - client with a GUI, or a category of 'gateway' with a type of 'aim' to - identify the agent as a gateway for the legacy AIM protocol. See - for a full list of - accepted category and type combinations. - - Features are simply a set of the namespaces that identify the supported - features. For example, a client that supports service discovery will - include the feature 'http://jabber.org/protocol/disco#info'. - - Since clients and components may operate in several roles at once, identity - and feature information may be grouped into "nodes". If one were to write - all of the identities and features used by a client, then node names would - be like section headings. - - Example disco#info stanzas: - - - - - - - - - - - - - - Stanza Interface: - node -- The name of the node to either - query or return info from. - identities -- A set of 4-tuples, where each tuple contains - the category, type, xml:lang, and name - of an identity. - features -- A set of namespaces for features. - - Methods: - add_identity -- Add a new, single identity. - del_identity -- Remove a single identity. - get_identities -- Return all identities in tuple form. - set_identities -- Use multiple identities, each given in tuple form. - del_identities -- Remove all identities. - add_feature -- Add a single feature. - del_feature -- Remove a single feature. - get_features -- Return a list of all features. - set_features -- Use a given list of features. - del_features -- Remove all features. - """ - - name = 'query' - namespace = 'http://jabber.org/protocol/disco#info' - plugin_attrib = 'disco_info' - interfaces = set(('node', 'features', 'identities')) - lang_interfaces = set(('identities',)) - - # Cache identities and features - _identities = set() - _features = set() - - def setup(self, xml=None): - """ - Populate the stanza object using an optional XML object. - - Overrides ElementBase.setup - - Caches identity and feature information. - - Arguments: - xml -- Use an existing XML object for the stanza's values. - """ - ElementBase.setup(self, xml) - - self._identities = set([id[0:3] for id in self['identities']]) - self._features = self['features'] - - def add_identity(self, category, itype, name=None, lang=None): - """ - Add a new identity element. Each identity must be unique - in terms of all four identity components. - - Multiple, identical category/type pairs are allowed only - if the xml:lang values are different. Likewise, multiple - category/type/xml:lang pairs are allowed so long as the names - are different. In any case, a category and type are required. - - Arguments: - category -- The general category to which the agent belongs. - itype -- A more specific designation with the category. - name -- Optional human readable name for this identity. - lang -- Optional standard xml:lang value. - """ - identity = (category, itype, lang) - if identity not in self._identities: - self._identities.add(identity) - id_xml = ET.Element('{%s}identity' % self.namespace) - id_xml.attrib['category'] = category - id_xml.attrib['type'] = itype - if lang: - id_xml.attrib['{%s}lang' % self.xml_ns] = lang - if name: - id_xml.attrib['name'] = name - self.xml.append(id_xml) - return True - return False - - def del_identity(self, category, itype, name=None, lang=None): - """ - Remove a given identity. - - Arguments: - category -- The general category to which the agent belonged. - itype -- A more specific designation with the category. - name -- Optional human readable name for this identity. - lang -- Optional, standard xml:lang value. - """ - identity = (category, itype, lang) - if identity in self._identities: - self._identities.remove(identity) - for id_xml in self.findall('{%s}identity' % self.namespace): - id = (id_xml.attrib['category'], - id_xml.attrib['type'], - id_xml.attrib.get('{%s}lang' % self.xml_ns, None)) - if id == identity: - self.xml.remove(id_xml) - return True - return False - - def get_identities(self, lang=None, dedupe=True): - """ - Return a set of all identities in tuple form as so: - (category, type, lang, name) - - If a language was specified, only return identities using - that language. - - Arguments: - lang -- Optional, standard xml:lang value. - dedupe -- If True, de-duplicate identities, otherwise - return a list of all identities. - """ - if dedupe: - identities = set() - else: - identities = [] - for id_xml in self.findall('{%s}identity' % self.namespace): - xml_lang = id_xml.attrib.get('{%s}lang' % self.xml_ns, None) - if lang is None or xml_lang == lang: - id = (id_xml.attrib['category'], - id_xml.attrib['type'], - id_xml.attrib.get('{%s}lang' % self.xml_ns, None), - id_xml.attrib.get('name', None)) - if dedupe: - identities.add(id) - else: - identities.append(id) - return identities - - def set_identities(self, identities, lang=None): - """ - Add or replace all identities. The identities must be a in set - where each identity is a tuple of the form: - (category, type, lang, name) - - If a language is specifified, any identities using that language - will be removed to be replaced with the given identities. - - NOTE: An identity's language will not be changed regardless of - the value of lang. - - Arguments: - identities -- A set of identities in tuple form. - lang -- Optional, standard xml:lang value. - """ - self.del_identities(lang) - for identity in identities: - category, itype, lang, name = identity - self.add_identity(category, itype, name, lang) - - def del_identities(self, lang=None): - """ - Remove all identities. If a language was specified, only - remove identities using that language. - - Arguments: - lang -- Optional, standard xml:lang value. - """ - for id_xml in self.findall('{%s}identity' % self.namespace): - if lang is None: - self.xml.remove(id_xml) - elif id_xml.attrib.get('{%s}lang' % self.xml_ns, None) == lang: - self._identities.remove(( - id_xml.attrib['category'], - id_xml.attrib['type'], - id_xml.attrib.get('{%s}lang' % self.xml_ns, None))) - self.xml.remove(id_xml) - - def add_feature(self, feature): - """ - Add a single, new feature. - - Arguments: - feature -- The namespace of the supported feature. - """ - if feature not in self._features: - self._features.add(feature) - feature_xml = ET.Element('{%s}feature' % self.namespace) - feature_xml.attrib['var'] = feature - self.xml.append(feature_xml) - return True - return False - - def del_feature(self, feature): - """ - Remove a single feature. - - Arguments: - feature -- The namespace of the removed feature. - """ - if feature in self._features: - self._features.remove(feature) - for feature_xml in self.findall('{%s}feature' % self.namespace): - if feature_xml.attrib['var'] == feature: - self.xml.remove(feature_xml) - return True - return False - - def get_features(self, dedupe=True): - """Return the set of all supported features.""" - if dedupe: - features = set() - else: - features = [] - for feature_xml in self.findall('{%s}feature' % self.namespace): - if dedupe: - features.add(feature_xml.attrib['var']) - else: - features.append(feature_xml.attrib['var']) - return features - - def set_features(self, features): - """ - Add or replace the set of supported features. - - Arguments: - features -- The new set of supported features. - """ - self.del_features() - for feature in features: - self.add_feature(feature) - - def del_features(self): - """Remove all features.""" - self._features = set() - for feature_xml in self.findall('{%s}feature' % self.namespace): - self.xml.remove(feature_xml) diff --git a/sleekxmpp/plugins/xep_0030/stanza/items.py b/sleekxmpp/plugins/xep_0030/stanza/items.py deleted file mode 100644 index 10458614..00000000 --- a/sleekxmpp/plugins/xep_0030/stanza/items.py +++ /dev/null @@ -1,152 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 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 DiscoItems(ElementBase): - - """ - Example disco#items stanzas: - - - - - - - - - - - - Stanza Interface: - node -- The name of the node to either - query or return info from. - items -- A list of 3-tuples, where each tuple contains - the JID, node, and name of an item. - - Methods: - add_item -- Add a single new item. - del_item -- Remove a single item. - get_items -- Return all items. - set_items -- Set or replace all items. - del_items -- Remove all items. - """ - - name = 'query' - namespace = 'http://jabber.org/protocol/disco#items' - plugin_attrib = 'disco_items' - interfaces = set(('node', 'items')) - - # Cache items - _items = set() - - def setup(self, xml=None): - """ - Populate the stanza object using an optional XML object. - - Overrides ElementBase.setup - - Caches item information. - - Arguments: - xml -- Use an existing XML object for the stanza's values. - """ - ElementBase.setup(self, xml) - self._items = set([item[0:2] for item in self['items']]) - - def add_item(self, jid, node=None, name=None): - """ - Add a new item element. Each item is required to have a - JID, but may also specify a node value to reference - non-addressable entitities. - - Arguments: - jid -- The JID for the item. - node -- Optional additional information to reference - non-addressable items. - name -- Optional human readable name for the item. - """ - if (jid, node) not in self._items: - self._items.add((jid, node)) - item = DiscoItem(parent=self) - item['jid'] = jid - item['node'] = node - item['name'] = name - self.iterables.append(item) - return True - return False - - def del_item(self, jid, node=None): - """ - Remove a single item. - - Arguments: - jid -- JID of the item to remove. - node -- Optional extra identifying information. - """ - if (jid, node) in self._items: - for item_xml in self.findall('{%s}item' % self.namespace): - item = (item_xml.attrib['jid'], - item_xml.attrib.get('node', None)) - if item == (jid, node): - self.xml.remove(item_xml) - return True - return False - - def get_items(self): - """Return all items.""" - items = set() - for item in self['substanzas']: - if isinstance(item, DiscoItem): - items.add((item['jid'], item['node'], item['name'])) - return items - - def set_items(self, items): - """ - Set or replace all items. The given items must be in a - list or set where each item is a tuple of the form: - (jid, node, name) - - Arguments: - items -- A series of items in tuple format. - """ - self.del_items() - for item in items: - jid, node, name = item - self.add_item(jid, node, name) - - def del_items(self): - """Remove all items.""" - self._items = set() - items = [i for i in self.iterables if isinstance(i, DiscoItem)] - for item in items: - self.xml.remove(item.xml) - self.iterables.remove(item) - - -class DiscoItem(ElementBase): - name = 'item' - namespace = 'http://jabber.org/protocol/disco#items' - plugin_attrib = name - interfaces = set(('jid', 'node', 'name')) - - def get_node(self): - """Return the item's node name or ``None``.""" - return self._get_attr('node', None) - - def get_name(self): - """Return the item's human readable name, or ``None``.""" - return self._get_attr('name', None) - - -register_stanza_plugin(DiscoItems, DiscoItem, iterable=True) diff --git a/sleekxmpp/plugins/xep_0030/static.py b/sleekxmpp/plugins/xep_0030/static.py deleted file mode 100644 index dd5317d1..00000000 --- a/sleekxmpp/plugins/xep_0030/static.py +++ /dev/null @@ -1,430 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging -import threading - -from sleekxmpp import Iq -from sleekxmpp.exceptions import XMPPError, IqError, IqTimeout -from sleekxmpp.xmlstream import JID -from sleekxmpp.plugins.xep_0030 import DiscoInfo, DiscoItems - - -log = logging.getLogger(__name__) - - -class StaticDisco(object): - - """ - While components will likely require fully dynamic handling - of service discovery information, most clients and simple bots - only need to manage a few disco nodes that will remain mostly - static. - - StaticDisco provides a set of node handlers that will store - static sets of disco info and items in memory. - - Attributes: - nodes -- A dictionary mapping (JID, node) tuples to a dict - containing a disco#info and a disco#items stanza. - xmpp -- The main SleekXMPP object. - """ - - def __init__(self, xmpp, disco): - """ - Create a static disco interface. Sets of disco#info and - disco#items are maintained for every given JID and node - combination. These stanzas are used to store disco - information in memory without any additional processing. - - Arguments: - xmpp -- The main SleekXMPP object. - """ - self.nodes = {} - self.xmpp = xmpp - self.disco = disco - self.lock = threading.RLock() - - def add_node(self, jid=None, node=None, ifrom=None): - """ - Create a new set of stanzas for the provided - JID and node combination. - - Arguments: - jid -- The JID that will own the new stanzas. - node -- The node that will own the new stanzas. - """ - with self.lock: - if jid is None: - jid = self.xmpp.boundjid.full - if node is None: - node = '' - if ifrom is None: - ifrom = '' - if isinstance(ifrom, JID): - ifrom = ifrom.full - if (jid, node, ifrom) not in self.nodes: - self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(), - 'items': DiscoItems()} - self.nodes[(jid, node, ifrom)]['info']['node'] = node - self.nodes[(jid, node, ifrom)]['items']['node'] = node - - def get_node(self, jid=None, node=None, ifrom=None): - with self.lock: - if jid is None: - jid = self.xmpp.boundjid.full - if node is None: - node = '' - if ifrom is None: - ifrom = '' - if isinstance(ifrom, JID): - ifrom = ifrom.full - if (jid, node, ifrom) not in self.nodes: - self.add_node(jid, node, ifrom) - return self.nodes[(jid, node, ifrom)] - - def node_exists(self, jid=None, node=None, ifrom=None): - with self.lock: - if jid is None: - jid = self.xmpp.boundjid.full - if node is None: - node = '' - if ifrom is None: - ifrom = '' - if isinstance(ifrom, JID): - ifrom = ifrom.full - if (jid, node, ifrom) not in self.nodes: - return False - return True - - # ================================================================= - # Node Handlers - # - # Each handler accepts four arguments: jid, node, ifrom, and data. - # The jid and node parameters together determine the set of info - # and items stanzas that will be retrieved or added. Additionally, - # the ifrom value allows for cached results when results vary based - # on the requester's JID. The data parameter is a dictionary with - # additional parameters that will be passed to other calls. - # - # This implementation does not allow different responses based on - # the requester's JID, except for cached results. To do that, - # register a custom node handler. - - def supports(self, jid, node, ifrom, data): - """ - Check if a JID supports a given feature. - - The data parameter may provide: - feature -- The feature to check for support. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the info. - cached -- If true, then look for the disco info data from - the local cache system. If no results are found, - send the query as usual. The self.use_cache - setting must be set to true for this option to - be useful. If set to false, then the cache will - be skipped, even if a result has already been - cached. Defaults to false. - """ - feature = data.get('feature', None) - - data = {'local': data.get('local', False), - 'cached': data.get('cached', True)} - - if not feature: - return False - - try: - info = self.disco.get_info(jid=jid, node=node, - ifrom=ifrom, **data) - info = self.disco._wrap(ifrom, jid, info, True) - features = info['disco_info']['features'] - return feature in features - except IqError: - return False - except IqTimeout: - return None - - def has_identity(self, jid, node, ifrom, data): - """ - Check if a JID has a given identity. - - The data parameter may provide: - category -- The category of the identity to check. - itype -- The type of the identity to check. - lang -- The language of the identity to check. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the info. - cached -- If true, then look for the disco info data from - the local cache system. If no results are found, - send the query as usual. The self.use_cache - setting must be set to true for this option to - be useful. If set to false, then the cache will - be skipped, even if a result has already been - cached. Defaults to false. - """ - identity = (data.get('category', None), - data.get('itype', None), - data.get('lang', None)) - - data = {'local': data.get('local', False), - 'cached': data.get('cached', True)} - - try: - info = self.disco.get_info(jid=jid, node=node, - ifrom=ifrom, **data) - info = self.disco._wrap(ifrom, jid, info, True) - trunc = lambda i: (i[0], i[1], i[2]) - return identity in map(trunc, info['disco_info']['identities']) - except IqError: - return False - except IqTimeout: - return None - - def get_info(self, jid, node, ifrom, data): - """ - Return the stored info data for the requested JID/node combination. - - The data parameter is not used. - """ - with self.lock: - if not self.node_exists(jid, node): - if not node: - return DiscoInfo() - else: - raise XMPPError(condition='item-not-found') - else: - return self.get_node(jid, node)['info'] - - def set_info(self, jid, node, ifrom, data): - """ - Set the entire info stanza for a JID/node at once. - - The data parameter is a disco#info substanza. - """ - with self.lock: - self.add_node(jid, node) - self.get_node(jid, node)['info'] = data - - def del_info(self, jid, node, ifrom, data): - """ - Reset the info stanza for a given JID/node combination. - - The data parameter is not used. - """ - with self.lock: - if self.node_exists(jid, node): - self.get_node(jid, node)['info'] = DiscoInfo() - - def get_items(self, jid, node, ifrom, data): - """ - Return the stored items data for the requested JID/node combination. - - The data parameter is not used. - """ - with self.lock: - if not self.node_exists(jid, node): - if not node: - return DiscoItems() - else: - raise XMPPError(condition='item-not-found') - else: - return self.get_node(jid, node)['items'] - - def set_items(self, jid, node, ifrom, data): - """ - Replace the stored items data for a JID/node combination. - - The data parameter may provide: - items -- A set of items in tuple format. - """ - with self.lock: - items = data.get('items', set()) - self.add_node(jid, node) - self.get_node(jid, node)['items']['items'] = items - - def del_items(self, jid, node, ifrom, data): - """ - Reset the items stanza for a given JID/node combination. - - The data parameter is not used. - """ - with self.lock: - if self.node_exists(jid, node): - self.get_node(jid, node)['items'] = DiscoItems() - - def add_identity(self, jid, node, ifrom, data): - """ - Add a new identity to te JID/node combination. - - The data parameter may provide: - category -- The general category to which the agent belongs. - itype -- A more specific designation with the category. - name -- Optional human readable name for this identity. - lang -- Optional standard xml:lang value. - """ - with self.lock: - self.add_node(jid, node) - self.get_node(jid, node)['info'].add_identity( - data.get('category', ''), - data.get('itype', ''), - data.get('name', None), - data.get('lang', None)) - - def set_identities(self, jid, node, ifrom, data): - """ - Add or replace all identities for a JID/node combination. - - The data parameter should include: - identities -- A list of identities in tuple form: - (category, type, name, lang) - """ - with self.lock: - identities = data.get('identities', set()) - self.add_node(jid, node) - self.get_node(jid, node)['info']['identities'] = identities - - def del_identity(self, jid, node, ifrom, data): - """ - Remove an identity from a JID/node combination. - - The data parameter may provide: - category -- The general category to which the agent belonged. - itype -- A more specific designation with the category. - name -- Optional human readable name for this identity. - lang -- Optional, standard xml:lang value. - """ - with self.lock: - if self.node_exists(jid, node): - self.get_node(jid, node)['info'].del_identity( - data.get('category', ''), - data.get('itype', ''), - data.get('name', None), - data.get('lang', None)) - - def del_identities(self, jid, node, ifrom, data): - """ - Remove all identities from a JID/node combination. - - The data parameter is not used. - """ - with self.lock: - if self.node_exists(jid, node): - del self.get_node(jid, node)['info']['identities'] - - def add_feature(self, jid, node, ifrom, data): - """ - Add a feature to a JID/node combination. - - The data parameter should include: - feature -- The namespace of the supported feature. - """ - with self.lock: - self.add_node(jid, node) - self.get_node(jid, node)['info'].add_feature( - data.get('feature', '')) - - def set_features(self, jid, node, ifrom, data): - """ - Add or replace all features for a JID/node combination. - - The data parameter should include: - features -- The new set of supported features. - """ - with self.lock: - features = data.get('features', set()) - self.add_node(jid, node) - self.get_node(jid, node)['info']['features'] = features - - def del_feature(self, jid, node, ifrom, data): - """ - Remove a feature from a JID/node combination. - - The data parameter should include: - feature -- The namespace of the removed feature. - """ - with self.lock: - if self.node_exists(jid, node): - self.get_node(jid, node)['info'].del_feature( - data.get('feature', '')) - - def del_features(self, jid, node, ifrom, data): - """ - Remove all features from a JID/node combination. - - The data parameter is not used. - """ - with self.lock: - if not self.node_exists(jid, node): - return - del self.get_node(jid, node)['info']['features'] - - def add_item(self, jid, node, ifrom, data): - """ - Add an item to a JID/node combination. - - The data parameter may include: - ijid -- The JID for the item. - inode -- Optional additional information to reference - non-addressable items. - name -- Optional human readable name for the item. - """ - with self.lock: - self.add_node(jid, node) - self.get_node(jid, node)['items'].add_item( - data.get('ijid', ''), - node=data.get('inode', ''), - name=data.get('name', '')) - - def del_item(self, jid, node, ifrom, data): - """ - Remove an item from a JID/node combination. - - The data parameter may include: - ijid -- JID of the item to remove. - inode -- Optional extra identifying information. - """ - with self.lock: - if self.node_exists(jid, node): - self.get_node(jid, node)['items'].del_item( - data.get('ijid', ''), - node=data.get('inode', None)) - - def cache_info(self, jid, node, ifrom, data): - """ - Cache disco information for an external JID. - - The data parameter is the Iq result stanza - containing the disco info to cache, or - the disco#info substanza itself. - """ - with self.lock: - if isinstance(data, Iq): - data = data['disco_info'] - - self.add_node(jid, node, ifrom) - self.get_node(jid, node, ifrom)['info'] = data - - def get_cached_info(self, jid, node, ifrom, data): - """ - Retrieve cached disco info data. - - The data parameter is not used. - """ - with self.lock: - if not self.node_exists(jid, node, ifrom): - return None - else: - return self.get_node(jid, node, ifrom)['info'] diff --git a/sleekxmpp/plugins/xep_0033/__init__.py b/sleekxmpp/plugins/xep_0033/__init__.py deleted file mode 100644 index ba8152c4..00000000 --- a/sleekxmpp/plugins/xep_0033/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0033 import stanza -from sleekxmpp.plugins.xep_0033.stanza import Addresses, Address -from sleekxmpp.plugins.xep_0033.addresses import XEP_0033 - - -register_plugin(XEP_0033) - -# Retain some backwards compatibility -xep_0033 = XEP_0033 -Addresses.addAddress = Addresses.add_address diff --git a/sleekxmpp/plugins/xep_0033/addresses.py b/sleekxmpp/plugins/xep_0033/addresses.py deleted file mode 100644 index 13cb7267..00000000 --- a/sleekxmpp/plugins/xep_0033/addresses.py +++ /dev/null @@ -1,37 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import Message, Presence -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0033 import stanza, Addresses - - -class XEP_0033(BasePlugin): - - """ - XEP-0033: Extended Stanza Addressing - """ - - name = 'xep_0033' - description = 'XEP-0033: Extended Stanza Addressing' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Message, Addresses) - register_stanza_plugin(Presence, Addresses) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=Addresses.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(Addresses.namespace) - diff --git a/sleekxmpp/plugins/xep_0033/stanza.py b/sleekxmpp/plugins/xep_0033/stanza.py deleted file mode 100644 index 1ff9fb20..00000000 --- a/sleekxmpp/plugins/xep_0033/stanza.py +++ /dev/null @@ -1,131 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import JID, ElementBase, ET, register_stanza_plugin - - -class Addresses(ElementBase): - - name = 'addresses' - namespace = 'http://jabber.org/protocol/address' - plugin_attrib = 'addresses' - interfaces = set() - - def add_address(self, atype='to', jid='', node='', uri='', - desc='', delivered=False): - addr = Address(parent=self) - addr['type'] = atype - addr['jid'] = jid - addr['node'] = node - addr['uri'] = uri - addr['desc'] = desc - addr['delivered'] = delivered - - return addr - - # Additional methods for manipulating sets of addresses - # based on type are generated below. - - -class Address(ElementBase): - - name = 'address' - namespace = 'http://jabber.org/protocol/address' - plugin_attrib = 'address' - interfaces = set(['type', 'jid', 'node', 'uri', 'desc', 'delivered']) - - address_types = set(('bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to')) - - def get_jid(self): - return JID(self._get_attr('jid')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_delivered(self): - value = self._get_attr('delivered', False) - return value and value.lower() in ('true', '1') - - def set_delivered(self, delivered): - if delivered: - self._set_attr('delivered', 'true') - else: - del self['delivered'] - - def set_uri(self, uri): - if uri: - del self['jid'] - del self['node'] - self._set_attr('uri', uri) - else: - self._del_attr('uri') - - -# ===================================================================== -# Auto-generate address type filters for the Addresses class. - -def _addr_filter(atype): - def _type_filter(addr): - if isinstance(addr, Address): - if atype == 'all' or addr['type'] == atype: - return True - return False - return _type_filter - - -def _build_methods(atype): - - def get_multi(self): - return list(filter(_addr_filter(atype), self)) - - def set_multi(self, value): - del self[atype] - for addr in value: - - # Support assigning dictionary versions of addresses - # instead of full Address objects. - if not isinstance(addr, Address): - if atype != 'all': - addr['type'] = atype - elif 'atype' in addr and 'type' not in addr: - addr['type'] = addr['atype'] - addrObj = Address() - addrObj.values = addr - addr = addrObj - - self.append(addr) - - def del_multi(self): - res = list(filter(_addr_filter(atype), self)) - for addr in res: - self.iterables.remove(addr) - self.xml.remove(addr.xml) - - return get_multi, set_multi, del_multi - - -for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'): - get_multi, set_multi, del_multi = _build_methods(atype) - - Addresses.interfaces.add(atype) - setattr(Addresses, "get_%s" % atype, get_multi) - setattr(Addresses, "set_%s" % atype, set_multi) - setattr(Addresses, "del_%s" % atype, del_multi) - - # To retain backwards compatibility: - setattr(Addresses, "get%s" % atype.title(), get_multi) - setattr(Addresses, "set%s" % atype.title(), set_multi) - setattr(Addresses, "del%s" % atype.title(), del_multi) - if atype == 'all': - Addresses.interfaces.add('addresses') - setattr(Addresses, "getAddresses", get_multi) - setattr(Addresses, "setAddresses", set_multi) - setattr(Addresses, "delAddresses", del_multi) - - -register_stanza_plugin(Addresses, Address, iterable=True) diff --git a/sleekxmpp/plugins/xep_0045.py b/sleekxmpp/plugins/xep_0045.py deleted file mode 100644 index ca5ed1ef..00000000 --- a/sleekxmpp/plugins/xep_0045.py +++ /dev/null @@ -1,402 +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. -""" -from __future__ import with_statement - -import logging - -from sleekxmpp import Presence -from sleekxmpp.plugins import BasePlugin, register_plugin -from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, JID, ET -from sleekxmpp.xmlstream.handler.callback import Callback -from sleekxmpp.xmlstream.matcher.xpath import MatchXPath -from sleekxmpp.xmlstream.matcher.xmlmask import MatchXMLMask -from sleekxmpp.exceptions import IqError, IqTimeout - - -log = logging.getLogger(__name__) - - -class MUCPresence(ElementBase): - name = 'x' - namespace = 'http://jabber.org/protocol/muc#user' - plugin_attrib = 'muc' - interfaces = set(('affiliation', 'role', 'jid', 'nick', 'room')) - affiliations = set(('', )) - roles = set(('', )) - - def getXMLItem(self): - item = self.xml.find('{http://jabber.org/protocol/muc#user}item') - if item is None: - item = ET.Element('{http://jabber.org/protocol/muc#user}item') - self.xml.append(item) - return item - - def getAffiliation(self): - #TODO if no affilation, set it to the default and return default - item = self.getXMLItem() - return item.get('affiliation', '') - - def setAffiliation(self, value): - item = self.getXMLItem() - #TODO check for valid affiliation - item.attrib['affiliation'] = value - return self - - def delAffiliation(self): - item = self.getXMLItem() - #TODO set default affiliation - if 'affiliation' in item.attrib: del item.attrib['affiliation'] - return self - - def getJid(self): - item = self.getXMLItem() - return JID(item.get('jid', '')) - - def setJid(self, value): - item = self.getXMLItem() - if not isinstance(value, str): - value = str(value) - item.attrib['jid'] = value - return self - - def delJid(self): - item = self.getXMLItem() - if 'jid' in item.attrib: del item.attrib['jid'] - return self - - def getRole(self): - item = self.getXMLItem() - #TODO get default role, set default role if none - return item.get('role', '') - - def setRole(self, value): - item = self.getXMLItem() - #TODO check for valid role - item.attrib['role'] = value - return self - - def delRole(self): - item = self.getXMLItem() - #TODO set default role - if 'role' in item.attrib: del item.attrib['role'] - return self - - def getNick(self): - return self.parent()['from'].resource - - def getRoom(self): - return self.parent()['from'].bare - - def setNick(self, value): - log.warning("Cannot set nick through mucpresence plugin.") - return self - - def setRoom(self, value): - log.warning("Cannot set room through mucpresence plugin.") - return self - - def delNick(self): - log.warning("Cannot delete nick through mucpresence plugin.") - return self - - def delRoom(self): - log.warning("Cannot delete room through mucpresence plugin.") - return self - - -class XEP_0045(BasePlugin): - - """ - Implements XEP-0045 Multi-User Chat - """ - - name = 'xep_0045' - description = 'XEP-0045: Multi-User Chat' - dependencies = set(['xep_0030', 'xep_0004']) - - def plugin_init(self): - self.rooms = {} - self.ourNicks = {} - self.xep = '0045' - # load MUC support in presence stanzas - register_stanza_plugin(Presence, MUCPresence) - self.xmpp.register_handler(Callback('MUCPresence', MatchXMLMask("" % self.xmpp.default_ns), self.handle_groupchat_presence)) - self.xmpp.register_handler(Callback('MUCError', MatchXMLMask("" % self.xmpp.default_ns), self.handle_groupchat_error_message)) - self.xmpp.register_handler(Callback('MUCMessage', MatchXMLMask("" % self.xmpp.default_ns), self.handle_groupchat_message)) - self.xmpp.register_handler(Callback('MUCSubject', MatchXMLMask("" % self.xmpp.default_ns), self.handle_groupchat_subject)) - self.xmpp.register_handler(Callback('MUCConfig', MatchXMLMask("" % self.xmpp.default_ns), self.handle_config_change)) - self.xmpp.register_handler(Callback('MUCInvite', MatchXPath("{%s}message/{%s}x/{%s}invite" % ( - self.xmpp.default_ns, - 'http://jabber.org/protocol/muc#user', - 'http://jabber.org/protocol/muc#user')), self.handle_groupchat_invite)) - - def handle_groupchat_invite(self, inv): - """ Handle an invite into a muc. - """ - logging.debug("MUC invite to %s from %s: %s", inv['to'], inv["from"], inv) - if inv['from'] not in self.rooms.keys(): - self.xmpp.event("groupchat_invite", inv) - - def handle_config_change(self, msg): - """Handle a MUC configuration change (with status code).""" - self.xmpp.event('groupchat_config_status', msg) - self.xmpp.event('muc::%s::config_status' % msg['from'].bare , msg) - - def handle_groupchat_presence(self, pr): - """ Handle a presence in a muc. - """ - got_offline = False - got_online = False - if pr['muc']['room'] not in self.rooms.keys(): - return - entry = pr['muc'].getStanzaValues() - entry['show'] = pr['show'] - entry['status'] = pr['status'] - entry['alt_nick'] = pr['nick'] - if pr['type'] == 'unavailable': - if entry['nick'] in self.rooms[entry['room']]: - del self.rooms[entry['room']][entry['nick']] - got_offline = True - else: - if entry['nick'] not in self.rooms[entry['room']]: - got_online = True - self.rooms[entry['room']][entry['nick']] = entry - log.debug("MUC presence from %s/%s : %s", entry['room'],entry['nick'], entry) - self.xmpp.event("groupchat_presence", pr) - self.xmpp.event("muc::%s::presence" % entry['room'], pr) - if got_offline: - self.xmpp.event("muc::%s::got_offline" % entry['room'], pr) - if got_online: - self.xmpp.event("muc::%s::got_online" % entry['room'], pr) - - def handle_groupchat_message(self, msg): - """ Handle a message event in a muc. - """ - self.xmpp.event('groupchat_message', msg) - self.xmpp.event("muc::%s::message" % msg['from'].bare, msg) - - def handle_groupchat_error_message(self, msg): - """ Handle a message error event in a muc. - """ - self.xmpp.event('groupchat_message_error', msg) - self.xmpp.event("muc::%s::message_error" % msg['from'].bare, msg) - - - - def handle_groupchat_subject(self, msg): - """ Handle a message coming from a muc indicating - a change of subject (or announcing it when joining the room) - """ - self.xmpp.event('groupchat_subject', msg) - - def jidInRoom(self, room, jid): - for nick in self.rooms[room]: - entry = self.rooms[room][nick] - if entry is not None and entry['jid'].full == jid: - return True - return False - - def getNick(self, room, jid): - for nick in self.rooms[room]: - entry = self.rooms[room][nick] - if entry is not None and entry['jid'].full == jid: - return nick - - def configureRoom(self, room, form=None, ifrom=None): - if form is None: - form = self.getRoomConfig(room, ifrom=ifrom) - iq = self.xmpp.makeIqSet() - iq['to'] = room - if ifrom is not None: - iq['from'] = ifrom - query = ET.Element('{http://jabber.org/protocol/muc#owner}query') - form = form.getXML('submit') - query.append(form) - iq.append(query) - # For now, swallow errors to preserve existing API - try: - result = iq.send() - except IqError: - return False - except IqTimeout: - return False - return True - - def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None, pfrom=None): - """ Join the specified room, requesting 'maxhistory' lines of history. - """ - stanza = self.xmpp.makePresence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow, pfrom=pfrom) - x = ET.Element('{http://jabber.org/protocol/muc}x') - if password: - passelement = ET.Element('{http://jabber.org/protocol/muc}password') - passelement.text = password - x.append(passelement) - if maxhistory: - history = ET.Element('{http://jabber.org/protocol/muc}history') - if maxhistory == "0": - history.attrib['maxchars'] = maxhistory - else: - history.attrib['maxstanzas'] = maxhistory - x.append(history) - stanza.append(x) - if not wait: - self.xmpp.send(stanza) - else: - #wait for our own room presence back - expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)}) - self.xmpp.send(stanza, expect) - self.rooms[room] = {} - self.ourNicks[room] = nick - - def destroy(self, room, reason='', altroom = '', ifrom=None): - iq = self.xmpp.makeIqSet() - if ifrom is not None: - iq['from'] = ifrom - iq['to'] = room - query = ET.Element('{http://jabber.org/protocol/muc#owner}query') - destroy = ET.Element('{http://jabber.org/protocol/muc#owner}destroy') - if altroom: - destroy.attrib['jid'] = altroom - xreason = ET.Element('{http://jabber.org/protocol/muc#owner}reason') - xreason.text = reason - destroy.append(xreason) - query.append(destroy) - iq.append(query) - # For now, swallow errors to preserve existing API - try: - r = iq.send() - except IqError: - return False - except IqTimeout: - return False - return True - - def setAffiliation(self, room, jid=None, nick=None, affiliation='member', ifrom=None): - """ Change room affiliation.""" - if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'): - raise TypeError - query = ET.Element('{http://jabber.org/protocol/muc#admin}query') - if nick is not None: - item = ET.Element('{http://jabber.org/protocol/muc#admin}item', {'affiliation':affiliation, 'nick':nick}) - else: - item = ET.Element('{http://jabber.org/protocol/muc#admin}item', {'affiliation':affiliation, 'jid':jid}) - query.append(item) - iq = self.xmpp.makeIqSet(query) - iq['to'] = room - iq['from'] = ifrom - # For now, swallow errors to preserve existing API - try: - result = iq.send() - except IqError: - return False - except IqTimeout: - return False - return True - - def setRole(self, room, nick, role): - """ Change role property of a nick in a room. - Typically, roles are temporary (they last only as long as you are in the - room), whereas affiliations are permanent (they last across groupchat - sessions). - """ - if role not in ('moderator', 'participant', 'visitor', 'none'): - raise TypeError - query = ET.Element('{http://jabber.org/protocol/muc#admin}query') - item = ET.Element('item', {'role':role, 'nick':nick}) - query.append(item) - iq = self.xmpp.makeIqSet(query) - iq['to'] = room - result = iq.send() - if result is False or result['type'] != 'result': - raise ValueError - return True - - def invite(self, room, jid, reason='', mfrom=''): - """ Invite a jid to a room.""" - msg = self.xmpp.makeMessage(room) - msg['from'] = mfrom - x = ET.Element('{http://jabber.org/protocol/muc#user}x') - invite = ET.Element('{http://jabber.org/protocol/muc#user}invite', {'to': jid}) - if reason: - rxml = ET.Element('{http://jabber.org/protocol/muc#user}reason') - rxml.text = reason - invite.append(rxml) - x.append(invite) - msg.append(x) - self.xmpp.send(msg) - - def leaveMUC(self, room, nick, msg='', pfrom=None): - """ Leave the specified room. - """ - if msg: - self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick), pstatus=msg, pfrom=pfrom) - else: - self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick), pfrom=pfrom) - del self.rooms[room] - - def getRoomConfig(self, room, ifrom=''): - iq = self.xmpp.makeIqGet('http://jabber.org/protocol/muc#owner') - iq['to'] = room - iq['from'] = ifrom - # For now, swallow errors to preserve existing API - try: - result = iq.send() - except IqError: - raise ValueError - except IqTimeout: - raise ValueError - form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x') - if form is None: - raise ValueError - return self.xmpp.plugin['xep_0004'].buildForm(form) - - def cancelConfig(self, room, ifrom=None): - query = ET.Element('{http://jabber.org/protocol/muc#owner}query') - x = ET.Element('{jabber:x:data}x', type='cancel') - query.append(x) - iq = self.xmpp.makeIqSet(query) - iq['to'] = room - iq['from'] = ifrom - iq.send() - - def setRoomConfig(self, room, config, ifrom=''): - query = ET.Element('{http://jabber.org/protocol/muc#owner}query') - x = config.getXML('submit') - query.append(x) - iq = self.xmpp.makeIqSet(query) - iq['to'] = room - iq['from'] = ifrom - iq.send() - - def getJoinedRooms(self): - return self.rooms.keys() - - def getOurJidInRoom(self, roomJid): - """ Return the jid we're using in a room. - """ - return "%s/%s" % (roomJid, self.ourNicks[roomJid]) - - def getJidProperty(self, room, nick, jidProperty): - """ Get the property of a nick in a room, such as its 'jid' or 'affiliation' - If not found, return None. - """ - if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]: - return self.rooms[room][nick][jidProperty] - else: - return None - - def getRoster(self, room): - """ Get the list of nicks in a room. - """ - if room not in self.rooms.keys(): - return None - return self.rooms[room].keys() - - -xep_0045 = XEP_0045 -register_plugin(XEP_0045) diff --git a/sleekxmpp/plugins/xep_0047/__init__.py b/sleekxmpp/plugins/xep_0047/__init__.py deleted file mode 100644 index 5cd7df2e..00000000 --- a/sleekxmpp/plugins/xep_0047/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0047 import stanza -from sleekxmpp.plugins.xep_0047.stanza import Open, Close, Data -from sleekxmpp.plugins.xep_0047.stream import IBBytestream -from sleekxmpp.plugins.xep_0047.ibb import XEP_0047 - - -register_plugin(XEP_0047) - - -# Retain some backwards compatibility -xep_0047 = XEP_0047 diff --git a/sleekxmpp/plugins/xep_0047/ibb.py b/sleekxmpp/plugins/xep_0047/ibb.py deleted file mode 100644 index 62dddac2..00000000 --- a/sleekxmpp/plugins/xep_0047/ibb.py +++ /dev/null @@ -1,215 +0,0 @@ -import uuid -import logging -import threading - -from sleekxmpp import Message, Iq -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0047 import stanza, Open, Close, Data, IBBytestream - - -log = logging.getLogger(__name__) - - -class XEP_0047(BasePlugin): - - name = 'xep_0047' - description = 'XEP-0047: In-band Bytestreams' - dependencies = set(['xep_0030']) - stanza = stanza - default_config = { - 'block_size': 4096, - 'max_block_size': 8192, - 'window_size': 1, - 'auto_accept': False, - } - - def plugin_init(self): - self._streams = {} - self._pending_streams = {} - self._pending_lock = threading.Lock() - self._stream_lock = threading.Lock() - - self._preauthed_sids_lock = threading.Lock() - self._preauthed_sids = {} - - register_stanza_plugin(Iq, Open) - register_stanza_plugin(Iq, Close) - register_stanza_plugin(Iq, Data) - register_stanza_plugin(Message, Data) - - self.xmpp.register_handler(Callback( - 'IBB Open', - StanzaPath('iq@type=set/ibb_open'), - self._handle_open_request)) - - self.xmpp.register_handler(Callback( - 'IBB Close', - StanzaPath('iq@type=set/ibb_close'), - self._handle_close)) - - self.xmpp.register_handler(Callback( - 'IBB Data', - StanzaPath('iq@type=set/ibb_data'), - self._handle_data)) - - self.xmpp.register_handler(Callback( - 'IBB Message Data', - StanzaPath('message/ibb_data'), - self._handle_data)) - - self.api.register(self._authorized, 'authorized', default=True) - self.api.register(self._authorized_sid, 'authorized_sid', default=True) - self.api.register(self._preauthorize_sid, 'preauthorize_sid', default=True) - self.api.register(self._get_stream, 'get_stream', default=True) - self.api.register(self._set_stream, 'set_stream', default=True) - self.api.register(self._del_stream, 'del_stream', default=True) - - def plugin_end(self): - self.xmpp.remove_handler('IBB Open') - self.xmpp.remove_handler('IBB Close') - self.xmpp.remove_handler('IBB Data') - self.xmpp.remove_handler('IBB Message Data') - self.xmpp['xep_0030'].del_feature(feature='http://jabber.org/protocol/ibb') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('http://jabber.org/protocol/ibb') - - def _get_stream(self, jid, sid, peer_jid, data): - return self._streams.get((jid, sid, peer_jid), None) - - def _set_stream(self, jid, sid, peer_jid, stream): - self._streams[(jid, sid, peer_jid)] = stream - - def _del_stream(self, jid, sid, peer_jid, data): - with self._stream_lock: - if (jid, sid, peer_jid) in self._streams: - del self._streams[(jid, sid, peer_jid)] - - def _accept_stream(self, iq): - receiver = iq['to'] - sender = iq['from'] - sid = iq['ibb_open']['sid'] - - if self.api['authorized_sid'](receiver, sid, sender, iq): - return True - return self.api['authorized'](receiver, sid, sender, iq) - - def _authorized(self, jid, sid, ifrom, iq): - if self.auto_accept: - if iq['ibb_open']['block_size'] <= self.max_block_size: - return True - return False - - def _authorized_sid(self, jid, sid, ifrom, iq): - with self._preauthed_sids_lock: - if (jid, sid, ifrom) in self._preauthed_sids: - del self._preauthed_sids[(jid, sid, ifrom)] - return True - return False - - def _preauthorize_sid(self, jid, sid, ifrom, data): - with self._preauthed_sids_lock: - self._preauthed_sids[(jid, sid, ifrom)] = True - - def open_stream(self, jid, block_size=None, sid=None, window=1, use_messages=False, - ifrom=None, block=True, timeout=None, callback=None): - if sid is None: - sid = str(uuid.uuid4()) - if block_size is None: - block_size = self.block_size - - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = jid - iq['from'] = ifrom - iq['ibb_open']['block_size'] = block_size - iq['ibb_open']['sid'] = sid - iq['ibb_open']['stanza'] = 'iq' - - stream = IBBytestream(self.xmpp, sid, block_size, - iq['from'], iq['to'], window, - use_messages) - - with self._stream_lock: - self._pending_streams[iq['id']] = stream - - self._pending_streams[iq['id']] = stream - - if block: - resp = iq.send(timeout=timeout) - self._handle_opened_stream(resp) - return stream - else: - cb = None - if callback is not None: - def chained(resp): - self._handle_opened_stream(resp) - callback(resp) - cb = chained - else: - cb = self._handle_opened_stream - return iq.send(block=block, timeout=timeout, callback=cb) - - def _handle_opened_stream(self, iq): - if iq['type'] == 'result': - with self._stream_lock: - stream = self._pending_streams.get(iq['id'], None) - if stream is not None: - log.debug('IBB stream (%s) accepted by %s', stream.sid, iq['from']) - stream.self_jid = iq['to'] - stream.peer_jid = iq['from'] - stream.stream_started.set() - self.api['set_stream'](stream.self_jid, stream.sid, stream.peer_jid, stream) - self.xmpp.event('ibb_stream_start', stream) - self.xmpp.event('stream:%s:%s' % (stream.sid, stream.peer_jid), stream) - - with self._stream_lock: - if iq['id'] in self._pending_streams: - del self._pending_streams[iq['id']] - - def _handle_open_request(self, iq): - sid = iq['ibb_open']['sid'] - size = iq['ibb_open']['block_size'] or self.block_size - - log.debug('Received IBB stream request from %s', iq['from']) - - if not sid: - raise XMPPError(etype='modify', condition='bad-request') - - if not self._accept_stream(iq): - raise XMPPError(etype='modify', condition='not-acceptable') - - if size > self.max_block_size: - raise XMPPError('resource-constraint') - - stream = IBBytestream(self.xmpp, sid, size, - iq['to'], iq['from'], - self.window_size) - stream.stream_started.set() - self.api['set_stream'](stream.self_jid, stream.sid, stream.peer_jid, stream) - iq.reply() - iq.send() - - self.xmpp.event('ibb_stream_start', stream) - self.xmpp.event('stream:%s:%s' % (sid, stream.peer_jid), stream) - - def _handle_data(self, stanza): - sid = stanza['ibb_data']['sid'] - stream = self.api['get_stream'](stanza['to'], sid, stanza['from']) - if stream is not None and stanza['from'] == stream.peer_jid: - stream._recv_data(stanza) - else: - raise XMPPError('item-not-found') - - def _handle_close(self, iq): - sid = iq['ibb_close']['sid'] - stream = self.api['get_stream'](iq['to'], sid, iq['from']) - if stream is not None and iq['from'] == stream.peer_jid: - stream._closed(iq) - self.api['del_stream'](stream.self_jid, stream.sid, stream.peer_jid) - else: - raise XMPPError('item-not-found') diff --git a/sleekxmpp/plugins/xep_0047/stanza.py b/sleekxmpp/plugins/xep_0047/stanza.py deleted file mode 100644 index 7e5d2fed..00000000 --- a/sleekxmpp/plugins/xep_0047/stanza.py +++ /dev/null @@ -1,67 +0,0 @@ -import re -import base64 - -from sleekxmpp.util import bytes -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import ElementBase - - -VALID_B64 = re.compile(r'[A-Za-z0-9\+\/]*=*') - - -def to_b64(data): - return bytes(base64.b64encode(bytes(data))).decode('utf-8') - - -def from_b64(data): - return bytes(base64.b64decode(bytes(data))) - - -class Open(ElementBase): - name = 'open' - namespace = 'http://jabber.org/protocol/ibb' - plugin_attrib = 'ibb_open' - interfaces = set(('block_size', 'sid', 'stanza')) - - def get_block_size(self): - return int(self._get_attr('block-size')) - - def set_block_size(self, value): - self._set_attr('block-size', str(value)) - - def del_block_size(self): - self._del_attr('block-size') - - -class Data(ElementBase): - name = 'data' - namespace = 'http://jabber.org/protocol/ibb' - plugin_attrib = 'ibb_data' - interfaces = set(('seq', 'sid', 'data')) - sub_interfaces = set(['data']) - - def get_seq(self): - return int(self._get_attr('seq', '0')) - - def set_seq(self, value): - self._set_attr('seq', str(value)) - - def get_data(self): - b64_data = self.xml.text.strip() - if VALID_B64.match(b64_data).group() == b64_data: - return from_b64(b64_data) - else: - raise XMPPError('not-acceptable') - - def set_data(self, value): - self.xml.text = to_b64(value) - - def del_data(self): - self.xml.text = '' - - -class Close(ElementBase): - name = 'close' - namespace = 'http://jabber.org/protocol/ibb' - plugin_attrib = 'ibb_close' - interfaces = set(['sid']) diff --git a/sleekxmpp/plugins/xep_0047/stream.py b/sleekxmpp/plugins/xep_0047/stream.py deleted file mode 100644 index 9651edf8..00000000 --- a/sleekxmpp/plugins/xep_0047/stream.py +++ /dev/null @@ -1,148 +0,0 @@ -import socket -import threading -import logging - -from sleekxmpp.stanza import Iq -from sleekxmpp.util import Queue -from sleekxmpp.exceptions import XMPPError - - -log = logging.getLogger(__name__) - - -class IBBytestream(object): - - def __init__(self, xmpp, sid, block_size, jid, peer, window_size=1, use_messages=False): - self.xmpp = xmpp - self.sid = sid - self.block_size = block_size - self.window_size = window_size - self.use_messages = use_messages - - if jid is None: - jid = xmpp.boundjid - self.self_jid = jid - self.peer_jid = peer - - self.send_seq = -1 - self.recv_seq = -1 - - self._send_seq_lock = threading.Lock() - self._recv_seq_lock = threading.Lock() - - self.stream_started = threading.Event() - self.stream_in_closed = threading.Event() - self.stream_out_closed = threading.Event() - - self.recv_queue = Queue() - - self.send_window = threading.BoundedSemaphore(value=self.window_size) - self.window_ids = set() - self.window_empty = threading.Event() - self.window_empty.set() - - def send(self, data): - if not self.stream_started.is_set() or \ - self.stream_out_closed.is_set(): - raise socket.error - data = data[0:self.block_size] - self.send_window.acquire() - with self._send_seq_lock: - self.send_seq = (self.send_seq + 1) % 65535 - seq = self.send_seq - if self.use_messages: - msg = self.xmpp.Message() - msg['to'] = self.peer_jid - msg['from'] = self.self_jid - msg['id'] = self.xmpp.new_id() - msg['ibb_data']['sid'] = self.sid - msg['ibb_data']['seq'] = seq - msg['ibb_data']['data'] = data - msg.send() - self.send_window.release() - else: - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = self.peer_jid - iq['from'] = self.self_jid - iq['ibb_data']['sid'] = self.sid - iq['ibb_data']['seq'] = seq - iq['ibb_data']['data'] = data - self.window_empty.clear() - self.window_ids.add(iq['id']) - iq.send(block=False, callback=self._recv_ack) - return len(data) - - def sendall(self, data): - sent_len = 0 - while sent_len < len(data): - sent_len += self.send(data[sent_len:]) - - def _recv_ack(self, iq): - self.window_ids.remove(iq['id']) - if not self.window_ids: - self.window_empty.set() - self.send_window.release() - if iq['type'] == 'error': - self.close() - - def _recv_data(self, stanza): - with self._recv_seq_lock: - new_seq = stanza['ibb_data']['seq'] - if new_seq != (self.recv_seq + 1) % 65535: - self.close() - raise XMPPError('unexpected-request') - self.recv_seq = new_seq - - data = stanza['ibb_data']['data'] - if len(data) > self.block_size: - self.close() - raise XMPPError('not-acceptable') - - self.recv_queue.put(data) - self.xmpp.event('ibb_stream_data', {'stream': self, 'data': data}) - - if isinstance(stanza, Iq): - stanza.reply() - stanza.send() - - def recv(self, *args, **kwargs): - return self.read(block=True) - - def read(self, block=True, timeout=None, **kwargs): - if not self.stream_started.is_set() or \ - self.stream_in_closed.is_set(): - raise socket.error - if timeout is not None: - block = True - try: - return self.recv_queue.get(block, timeout) - except: - return None - - def close(self): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = self.peer_jid - iq['from'] = self.self_jid - iq['ibb_close']['sid'] = self.sid - self.stream_out_closed.set() - iq.send(block=False, - callback=lambda x: self.stream_in_closed.set()) - self.xmpp.event('ibb_stream_end', self) - - def _closed(self, iq): - self.stream_in_closed.set() - self.stream_out_closed.set() - iq.reply() - iq.send() - self.xmpp.event('ibb_stream_end', self) - - def makefile(self, *args, **kwargs): - return self - - def connect(*args, **kwargs): - return None - - def shutdown(self, *args, **kwargs): - return None diff --git a/sleekxmpp/plugins/xep_0048/__init__.py b/sleekxmpp/plugins/xep_0048/__init__.py deleted file mode 100644 index 2c98d061..00000000 --- a/sleekxmpp/plugins/xep_0048/__init__.py +++ /dev/null @@ -1,15 +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 - -from sleekxmpp.plugins.xep_0048.stanza import Bookmarks, Conference, URL -from sleekxmpp.plugins.xep_0048.bookmarks import XEP_0048 - - -register_plugin(XEP_0048) diff --git a/sleekxmpp/plugins/xep_0048/bookmarks.py b/sleekxmpp/plugins/xep_0048/bookmarks.py deleted file mode 100644 index 0bb5ae38..00000000 --- a/sleekxmpp/plugins/xep_0048/bookmarks.py +++ /dev/null @@ -1,76 +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 import Iq -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.xep_0048 import stanza, Bookmarks, Conference, URL - - -log = logging.getLogger(__name__) - - -class XEP_0048(BasePlugin): - - name = 'xep_0048' - description = 'XEP-0048: Bookmarks' - dependencies = set(['xep_0045', 'xep_0049', 'xep_0060', 'xep_0163', 'xep_0223']) - stanza = stanza - default_config = { - 'auto_join': False, - 'storage_method': 'xep_0049' - } - - def plugin_init(self): - register_stanza_plugin(self.xmpp['xep_0060'].stanza.Item, Bookmarks) - - self.xmpp['xep_0049'].register(Bookmarks) - self.xmpp['xep_0163'].register_pep('bookmarks', Bookmarks) - - self.xmpp.add_event_handler('session_start', self._autojoin) - - def plugin_end(self): - self.xmpp.del_event_handler('session_start', self._autojoin) - - def _autojoin(self, __): - if not self.auto_join: - return - - try: - result = self.get_bookmarks(method=self.storage_method) - except XMPPError: - return - - if self.storage_method == 'xep_0223': - bookmarks = result['pubsub']['items']['item']['bookmarks'] - else: - bookmarks = result['private']['bookmarks'] - - for conf in bookmarks['conferences']: - if conf['autojoin']: - log.debug('Auto joining %s as %s', conf['jid'], conf['nick']) - self.xmpp['xep_0045'].joinMUC(conf['jid'], conf['nick'], - password=conf['password']) - - def set_bookmarks(self, bookmarks, method=None, **iqargs): - if not method: - method = self.storage_method - return self.xmpp[method].store(bookmarks, **iqargs) - - def get_bookmarks(self, method=None, **iqargs): - if not method: - method = self.storage_method - - loc = 'storage:bookmarks' if method == 'xep_0223' else 'bookmarks' - - return self.xmpp[method].retrieve(loc, **iqargs) diff --git a/sleekxmpp/plugins/xep_0048/stanza.py b/sleekxmpp/plugins/xep_0048/stanza.py deleted file mode 100644 index 21829392..00000000 --- a/sleekxmpp/plugins/xep_0048/stanza.py +++ /dev/null @@ -1,65 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin - - -class Bookmarks(ElementBase): - name = 'storage' - namespace = 'storage:bookmarks' - plugin_attrib = 'bookmarks' - interfaces = set() - - def add_conference(self, jid, nick, name=None, autojoin=None, password=None): - conf = Conference() - conf['jid'] = jid - conf['nick'] = nick - if name is None: - name = jid - conf['name'] = name - conf['autojoin'] = autojoin - conf['password'] = password - self.append(conf) - - def add_url(self, url, name=None): - saved_url = URL() - saved_url['url'] = url - if name is None: - name = url - saved_url['name'] = name - self.append(saved_url) - - -class Conference(ElementBase): - name = 'conference' - namespace = 'storage:bookmarks' - plugin_attrib = 'conference' - plugin_multi_attrib = 'conferences' - interfaces = set(['nick', 'password', 'autojoin', 'jid', 'name']) - sub_interfaces = set(['nick', 'password']) - - def get_autojoin(self): - value = self._get_attr('autojoin') - return value in ('1', 'true') - - def set_autojoin(self, value): - del self['autojoin'] - if value in ('1', 'true', True): - self._set_attr('autojoin', 'true') - - -class URL(ElementBase): - name = 'url' - namespace = 'storage:bookmarks' - plugin_attrib = 'url' - plugin_multi_attrib = 'urls' - interfaces = set(['url', 'name']) - - -register_stanza_plugin(Bookmarks, Conference, iterable=True) -register_stanza_plugin(Bookmarks, URL, iterable=True) diff --git a/sleekxmpp/plugins/xep_0049/__init__.py b/sleekxmpp/plugins/xep_0049/__init__.py deleted file mode 100644 index b0c4f904..00000000 --- a/sleekxmpp/plugins/xep_0049/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0049.stanza import PrivateXML -from sleekxmpp.plugins.xep_0049.private_storage import XEP_0049 - - -register_plugin(XEP_0049) diff --git a/sleekxmpp/plugins/xep_0049/private_storage.py b/sleekxmpp/plugins/xep_0049/private_storage.py deleted file mode 100644 index ef6cbdde..00000000 --- a/sleekxmpp/plugins/xep_0049/private_storage.py +++ /dev/null @@ -1,53 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import Iq -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.xep_0049 import stanza, PrivateXML - - -log = logging.getLogger(__name__) - - -class XEP_0049(BasePlugin): - - name = 'xep_0049' - description = 'XEP-0049: Private XML Storage' - dependencies = set([]) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, PrivateXML) - - def register(self, stanza): - register_stanza_plugin(PrivateXML, stanza, iterable=True) - - def store(self, data, ifrom=None, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - - if not isinstance(data, list): - data = [data] - - for elem in data: - iq['private'].append(elem) - - return iq.send(block=block, timeout=timeout, callback=callback) - - def retrieve(self, name, ifrom=None, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['from'] = ifrom - iq['private'].enable(name) - return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/xep_0049/stanza.py b/sleekxmpp/plugins/xep_0049/stanza.py deleted file mode 100644 index d424e2f0..00000000 --- a/sleekxmpp/plugins/xep_0049/stanza.py +++ /dev/null @@ -1,17 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ET, ElementBase - - -class PrivateXML(ElementBase): - - name = 'query' - namespace = 'jabber:iq:private' - plugin_attrib = 'private' - interfaces = set() diff --git a/sleekxmpp/plugins/xep_0050/__init__.py b/sleekxmpp/plugins/xep_0050/__init__.py deleted file mode 100644 index 640b182d..00000000 --- a/sleekxmpp/plugins/xep_0050/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0050.stanza import Command -from sleekxmpp.plugins.xep_0050.adhoc import XEP_0050 - - -register_plugin(XEP_0050) - - -# Retain some backwards compatibility -xep_0050 = XEP_0050 diff --git a/sleekxmpp/plugins/xep_0050/adhoc.py b/sleekxmpp/plugins/xep_0050/adhoc.py deleted file mode 100644 index e5594c3f..00000000 --- a/sleekxmpp/plugins/xep_0050/adhoc.py +++ /dev/null @@ -1,688 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging -import time - -from sleekxmpp import Iq -from sleekxmpp.exceptions import IqError -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0050 import stanza -from sleekxmpp.plugins.xep_0050 import Command -from sleekxmpp.plugins.xep_0004 import Form - - -log = logging.getLogger(__name__) - - -class XEP_0050(BasePlugin): - - """ - XEP-0050: Ad-Hoc Commands - - XMPP's Adhoc Commands provides a generic workflow mechanism for - interacting with applications. The result is similar to menu selections - and multi-step dialogs in normal desktop applications. Clients do not - need to know in advance what commands are provided by any particular - application or agent. While adhoc commands provide similar functionality - to Jabber-RPC, adhoc commands are used primarily for human interaction. - - Also see - - Configuration Values: - threaded -- Indicates if command events should be threaded. - Defaults to True. - - Events: - command_execute -- Received a command with action="execute" - command_next -- Received a command with action="next" - command_complete -- Received a command with action="complete" - command_cancel -- Received a command with action="cancel" - - Attributes: - threaded -- Indicates if command events should be threaded. - Defaults to True. - commands -- A dictionary mapping JID/node pairs to command - names and handlers. - sessions -- A dictionary or equivalent backend mapping - session IDs to dictionaries containing data - relevant to a command's session. - - Methods: - plugin_init -- Overrides base_plugin.plugin_init - post_init -- Overrides base_plugin.post_init - new_session -- Return a new session ID. - prep_handlers -- Placeholder. May call with a list of handlers - to prepare them for use with the session storage - backend, if needed. - set_backend -- Replace the default session storage with some - external storage mechanism, such as a database. - The provided backend wrapper must be able to - act using the same syntax as a dictionary. - add_command -- Add a command for use by external entitites. - get_commands -- Retrieve a list of commands provided by a - remote agent. - send_command -- Send a command request to a remote agent. - start_command -- Command user API: initiate a command session - continue_command -- Command user API: proceed to the next step - cancel_command -- Command user API: cancel a command - complete_command -- Command user API: finish a command - terminate_command -- Command user API: delete a command's session - """ - - name = 'xep_0050' - description = 'XEP-0050: Ad-Hoc Commands' - dependencies = set(['xep_0030', 'xep_0004']) - stanza = stanza - default_config = { - 'threaded': True, - 'session_db': None - } - - def plugin_init(self): - """Start the XEP-0050 plugin.""" - self.sessions = self.session_db - if self.sessions is None: - self.sessions = {} - - self.commands = {} - - self.xmpp.register_handler( - Callback("Ad-Hoc Execute", - StanzaPath('iq@type=set/command'), - self._handle_command)) - - register_stanza_plugin(Iq, Command) - register_stanza_plugin(Command, Form) - - self.xmpp.add_event_handler('command_execute', - self._handle_command_start, - threaded=self.threaded) - self.xmpp.add_event_handler('command_next', - self._handle_command_next, - threaded=self.threaded) - self.xmpp.add_event_handler('command_cancel', - self._handle_command_cancel, - threaded=self.threaded) - self.xmpp.add_event_handler('command_complete', - self._handle_command_complete, - threaded=self.threaded) - - def plugin_end(self): - self.xmpp.del_event_handler('command_execute', - self._handle_command_start) - self.xmpp.del_event_handler('command_next', - self._handle_command_next) - self.xmpp.del_event_handler('command_cancel', - self._handle_command_cancel) - self.xmpp.del_event_handler('command_complete', - self._handle_command_complete) - self.xmpp.remove_handler('Ad-Hoc Execute') - self.xmpp['xep_0030'].del_feature(feature=Command.namespace) - self.xmpp['xep_0030'].set_items(node=Command.namespace, items=tuple()) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(Command.namespace) - self.xmpp['xep_0030'].set_items(node=Command.namespace, items=tuple()) - - def set_backend(self, db): - """ - Replace the default session storage dictionary with - a generic, external data storage mechanism. - - The replacement backend must be able to interact through - the same syntax and interfaces as a normal dictionary. - - Arguments: - db -- The new session storage mechanism. - """ - self.sessions = db - - def prep_handlers(self, handlers, **kwargs): - """ - Prepare a list of functions for use by the backend service. - - Intended to be replaced by the backend service as needed. - - Arguments: - handlers -- A list of function pointers - **kwargs -- Any additional parameters required by the backend. - """ - pass - - # ================================================================= - # Server side (command provider) API - - def add_command(self, jid=None, node=None, name='', handler=None): - """ - Make a new command available to external entities. - - Access control may be implemented in the provided handler. - - Command workflow is done across a sequence of command handlers. The - first handler is given the initial Iq stanza of the request in order - to support access control. Subsequent handlers are given only the - payload items of the command. All handlers will receive the command's - session data. - - Arguments: - jid -- The JID that will expose the command. - node -- The node associated with the command. - name -- A human readable name for the command. - handler -- A function that will generate the response to the - initial command request, as well as enforcing any - access control policies. - """ - if jid is None: - jid = self.xmpp.boundjid - elif not isinstance(jid, JID): - jid = JID(jid) - item_jid = jid.full - - self.xmpp['xep_0030'].add_identity(category='automation', - itype='command-list', - name='Ad-Hoc commands', - node=Command.namespace, - jid=jid) - self.xmpp['xep_0030'].add_item(jid=item_jid, - name=name, - node=Command.namespace, - subnode=node, - ijid=jid) - self.xmpp['xep_0030'].add_identity(category='automation', - itype='command-node', - name=name, - node=node, - jid=jid) - self.xmpp['xep_0030'].add_feature(Command.namespace, None, jid) - - self.commands[(item_jid, node)] = (name, handler) - - def new_session(self): - """Return a new session ID.""" - return str(time.time()) + '-' + self.xmpp.new_id() - - def _handle_command(self, iq): - """Raise command events based on the command action.""" - self.xmpp.event('command_%s' % iq['command']['action'], iq) - - def _handle_command_start(self, iq): - """ - Process an initial request to execute a command. - - Arguments: - iq -- The command execution request. - """ - sessionid = self.new_session() - node = iq['command']['node'] - key = (iq['to'].full, node) - name, handler = self.commands.get(key, ('Not found', None)) - if not handler: - log.debug('Command not found: %s, %s', key, self.commands) - - payload = [] - for stanza in iq['command']['substanzas']: - payload.append(stanza) - - if len(payload) == 1: - payload = payload[0] - - interfaces = set([item.plugin_attrib for item in payload]) - payload_classes = set([item.__class__ for item in payload]) - - initial_session = {'id': sessionid, - 'from': iq['from'], - 'to': iq['to'], - 'node': node, - 'payload': payload, - 'interfaces': interfaces, - 'payload_classes': payload_classes, - 'notes': None, - 'has_next': False, - 'allow_complete': False, - 'allow_prev': False, - 'past': [], - 'next': None, - 'prev': None, - 'cancel': None} - - session = handler(iq, initial_session) - - self._process_command_response(iq, session) - - def _handle_command_next(self, iq): - """ - Process a request for the next step in the workflow - for a command with multiple steps. - - Arguments: - iq -- The command continuation request. - """ - sessionid = iq['command']['sessionid'] - session = self.sessions.get(sessionid) - - if session: - handler = session['next'] - interfaces = session['interfaces'] - results = [] - for stanza in iq['command']['substanzas']: - if stanza.plugin_attrib in interfaces: - results.append(stanza) - if len(results) == 1: - results = results[0] - - session = handler(results, session) - - self._process_command_response(iq, session) - else: - raise XMPPError('item-not-found') - - def _handle_command_prev(self, iq): - """ - Process a request for the prev step in the workflow - for a command with multiple steps. - - Arguments: - iq -- The command continuation request. - """ - sessionid = iq['command']['sessionid'] - session = self.sessions.get(sessionid) - - if session: - handler = session['prev'] - interfaces = session['interfaces'] - results = [] - for stanza in iq['command']['substanzas']: - if stanza.plugin_attrib in interfaces: - results.append(stanza) - if len(results) == 1: - results = results[0] - - session = handler(results, session) - - self._process_command_response(iq, session) - else: - raise XMPPError('item-not-found') - - def _process_command_response(self, iq, session): - """ - Generate a command reply stanza based on the - provided session data. - - Arguments: - iq -- The command request stanza. - session -- A dictionary of relevant session data. - """ - sessionid = session['id'] - - payload = session['payload'] - if payload is None: - payload = [] - if not isinstance(payload, list): - payload = [payload] - - interfaces = session.get('interfaces', set()) - payload_classes = session.get('payload_classes', set()) - - interfaces.update(set([item.plugin_attrib for item in payload])) - payload_classes.update(set([item.__class__ for item in payload])) - - session['interfaces'] = interfaces - session['payload_classes'] = payload_classes - - self.sessions[sessionid] = session - - for item in payload: - register_stanza_plugin(Command, item.__class__, iterable=True) - - iq.reply() - iq['command']['node'] = session['node'] - iq['command']['sessionid'] = session['id'] - - if session['next'] is None: - iq['command']['actions'] = [] - iq['command']['status'] = 'completed' - elif session['has_next']: - actions = ['next'] - if session['allow_complete']: - actions.append('complete') - if session['allow_prev']: - actions.append('prev') - iq['command']['actions'] = actions - iq['command']['status'] = 'executing' - else: - iq['command']['actions'] = ['complete'] - iq['command']['status'] = 'executing' - - iq['command']['notes'] = session['notes'] - - for item in payload: - iq['command'].append(item) - - iq.send() - - def _handle_command_cancel(self, iq): - """ - Process a request to cancel a command's execution. - - Arguments: - iq -- The command cancellation request. - """ - node = iq['command']['node'] - sessionid = iq['command']['sessionid'] - - session = self.sessions.get(sessionid) - - if session: - handler = session['cancel'] - if handler: - handler(iq, session) - del self.sessions[sessionid] - iq.reply() - iq['command']['node'] = node - iq['command']['sessionid'] = sessionid - iq['command']['status'] = 'canceled' - iq['command']['notes'] = session['notes'] - iq.send() - else: - raise XMPPError('item-not-found') - - - def _handle_command_complete(self, iq): - """ - Process a request to finish the execution of command - and terminate the workflow. - - All data related to the command session will be removed. - - Arguments: - iq -- The command completion request. - """ - node = iq['command']['node'] - sessionid = iq['command']['sessionid'] - session = self.sessions.get(sessionid) - - if session: - handler = session['next'] - interfaces = session['interfaces'] - results = [] - for stanza in iq['command']['substanzas']: - if stanza.plugin_attrib in interfaces: - results.append(stanza) - if len(results) == 1: - results = results[0] - - if handler: - handler(results, session) - - del self.sessions[sessionid] - - iq.reply() - iq['command']['node'] = node - iq['command']['sessionid'] = sessionid - iq['command']['actions'] = [] - iq['command']['status'] = 'completed' - iq['command']['notes'] = session['notes'] - iq.send() - else: - raise XMPPError('item-not-found') - - # ================================================================= - # Client side (command user) API - - def get_commands(self, jid, **kwargs): - """ - Return a list of commands provided by a given JID. - - Arguments: - jid -- The JID to query for commands. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the items. - ifrom -- Specifiy the sender's JID. - block -- If true, block and wait for the stanzas' reply. - timeout -- The time in seconds to block while waiting for - a reply. If None, then wait indefinitely. - callback -- Optional callback to execute when a reply is - received instead of blocking and waiting for - the reply. - iterator -- If True, return a result set iterator using - the XEP-0059 plugin, if the plugin is loaded. - Otherwise the parameter is ignored. - """ - return self.xmpp['xep_0030'].get_items(jid=jid, - node=Command.namespace, - **kwargs) - - def send_command(self, jid, node, ifrom=None, action='execute', - payload=None, sessionid=None, flow=False, **kwargs): - """ - Create and send a command stanza, without using the provided - workflow management APIs. - - Arguments: - jid -- The JID to send the command request or result. - node -- The node for the command. - ifrom -- Specify the sender's JID. - action -- May be one of: execute, cancel, complete, - or cancel. - payload -- Either a list of payload items, or a single - payload item such as a data form. - sessionid -- The current session's ID value. - flow -- If True, process the Iq result using the - command workflow methods contained in the - session instead of returning the response - stanza itself. Defaults to False. - block -- Specify if the send call will block until a - response is received, or a timeout occurs. - Defaults to True. - timeout -- The length of time (in seconds) to wait for a - response before exiting the send call - if blocking is used. Defaults to - sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler - function. Will be executed when a reply - stanza is received if flow=False. - """ - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = jid - iq['from'] = ifrom - iq['command']['node'] = node - iq['command']['action'] = action - if sessionid is not None: - iq['command']['sessionid'] = sessionid - if payload is not None: - if not isinstance(payload, list): - payload = [payload] - for item in payload: - iq['command'].append(item) - if not flow: - return iq.send(**kwargs) - else: - if kwargs.get('block', True): - try: - result = iq.send(**kwargs) - except IqError as err: - result = err.iq - self._handle_command_result(result) - else: - iq.send(block=False, callback=self._handle_command_result) - - def start_command(self, jid, node, session, ifrom=None, block=False): - """ - Initiate executing a command provided by a remote agent. - - The default workflow provided is non-blocking, but a blocking - version may be used with block=True. - - The provided session dictionary should contain: - next -- A handler for processing the command result. - error -- A handler for processing any error stanzas - generated by the request. - - Arguments: - jid -- The JID to send the command request. - node -- The node for the desired command. - session -- A dictionary of relevant session data. - ifrom -- Optionally specify the sender's JID. - block -- If True, block execution until a result - is received. Defaults to False. - """ - session['jid'] = jid - session['node'] = node - session['timestamp'] = time.time() - session['block'] = block - if 'payload' not in session: - session['payload'] = None - - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = jid - iq['from'] = ifrom - session['from'] = ifrom - iq['command']['node'] = node - iq['command']['action'] = 'execute' - if session['payload'] is not None: - payload = session['payload'] - if not isinstance(payload, list): - payload = list(payload) - for stanza in payload: - iq['command'].append(stanza) - sessionid = 'client:pending_' + iq['id'] - session['id'] = sessionid - self.sessions[sessionid] = session - if session['block']: - try: - result = iq.send(block=True) - except IqError as err: - result = err.iq - self._handle_command_result(result) - else: - iq.send(block=False, callback=self._handle_command_result) - - def continue_command(self, session, direction='next'): - """ - Execute the next action of the command. - - Arguments: - session -- All stored data relevant to the current - command session. - """ - sessionid = 'client:' + session['id'] - self.sessions[sessionid] = session - - self.send_command(session['jid'], - session['node'], - ifrom=session.get('from', None), - action=direction, - payload=session.get('payload', None), - sessionid=session['id'], - flow=True, - block=session['block']) - - def cancel_command(self, session): - """ - Cancel the execution of a command. - - Arguments: - session -- All stored data relevant to the current - command session. - """ - sessionid = 'client:' + session['id'] - self.sessions[sessionid] = session - - self.send_command(session['jid'], - session['node'], - ifrom=session.get('from', None), - action='cancel', - payload=session.get('payload', None), - sessionid=session['id'], - flow=True, - block=session['block']) - - def complete_command(self, session): - """ - Finish the execution of a command workflow. - - Arguments: - session -- All stored data relevant to the current - command session. - """ - sessionid = 'client:' + session['id'] - self.sessions[sessionid] = session - - self.send_command(session['jid'], - session['node'], - ifrom=session.get('from', None), - action='complete', - payload=session.get('payload', None), - sessionid=session['id'], - flow=True, - block=session['block']) - - def terminate_command(self, session): - """ - Delete a command's session after a command has completed - or an error has occured. - - Arguments: - session -- All stored data relevant to the current - command session. - """ - sessionid = 'client:' + session['id'] - try: - del self.sessions[sessionid] - except Exception as e: - log.error("Error deleting adhoc command session: %s" % e.message) - - def _handle_command_result(self, iq): - """ - Process the results of a command request. - - Will execute the 'next' handler stored in the session - data, or the 'error' handler depending on the Iq's type. - - Arguments: - iq -- The command response. - """ - sessionid = 'client:' + iq['command']['sessionid'] - pending = False - - if sessionid not in self.sessions: - pending = True - pendingid = 'client:pending_' + iq['id'] - if pendingid not in self.sessions: - return - sessionid = pendingid - - session = self.sessions[sessionid] - sessionid = 'client:' + iq['command']['sessionid'] - session['id'] = iq['command']['sessionid'] - - self.sessions[sessionid] = session - - if pending: - del self.sessions[pendingid] - - handler_type = 'next' - if iq['type'] == 'error': - handler_type = 'error' - handler = session.get(handler_type, None) - if handler: - handler(iq, session) - elif iq['type'] == 'error': - self.terminate_command(session) - - if iq['command']['status'] == 'completed': - self.terminate_command(session) diff --git a/sleekxmpp/plugins/xep_0050/stanza.py b/sleekxmpp/plugins/xep_0050/stanza.py deleted file mode 100644 index 2367c77b..00000000 --- a/sleekxmpp/plugins/xep_0050/stanza.py +++ /dev/null @@ -1,185 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 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, ET - - -class Command(ElementBase): - - """ - XMPP's Adhoc Commands provides a generic workflow mechanism for - interacting with applications. The result is similar to menu selections - and multi-step dialogs in normal desktop applications. Clients do not - need to know in advance what commands are provided by any particular - application or agent. While adhoc commands provide similar functionality - to Jabber-RPC, adhoc commands are used primarily for human interaction. - - Also see - - Example command stanzas: - - - - - - - - - - Information! - - - - - - - Stanza Interface: - action -- The action to perform. - actions -- The set of allowable next actions. - node -- The node associated with the command. - notes -- A list of tuples for informative notes. - sessionid -- A unique identifier for a command session. - status -- May be one of: canceled, completed, or executing. - - Attributes: - actions -- A set of allowed action values. - statuses -- A set of allowed status values. - next_actions -- A set of allowed next action names. - - Methods: - get_action -- Return the requested action. - get_actions -- Return the allowable next actions. - set_actions -- Set the allowable next actions. - del_actions -- Remove the current set of next actions. - get_notes -- Return a list of informative note data. - set_notes -- Set informative notes. - del_notes -- Remove any note data. - add_note -- Add a single note. - """ - - name = 'command' - namespace = 'http://jabber.org/protocol/commands' - plugin_attrib = 'command' - interfaces = set(('action', 'sessionid', 'node', - 'status', 'actions', 'notes')) - actions = set(('cancel', 'complete', 'execute', 'next', 'prev')) - statuses = set(('canceled', 'completed', 'executing')) - next_actions = set(('prev', 'next', 'complete')) - - def get_action(self): - """ - Return the value of the action attribute. - - If the Iq stanza's type is "set" then use a default - value of "execute". - """ - if self.parent()['type'] == 'set': - return self._get_attr('action', default='execute') - return self._get_attr('action') - - def set_actions(self, values): - """ - Assign the set of allowable next actions. - - Arguments: - values -- A list containing any combination of: - 'prev', 'next', and 'complete' - """ - self.del_actions() - if values: - self._set_sub_text('{%s}actions' % self.namespace, '', True) - actions = self.find('{%s}actions' % self.namespace) - for val in values: - if val in self.next_actions: - action = ET.Element('{%s}%s' % (self.namespace, val)) - actions.append(action) - - def get_actions(self): - """ - Return the set of allowable next actions. - """ - actions = set() - actions_xml = self.find('{%s}actions' % self.namespace) - if actions_xml is not None: - for action in self.next_actions: - action_xml = actions_xml.find('{%s}%s' % (self.namespace, - action)) - if action_xml is not None: - actions.add(action) - return actions - - def del_actions(self): - """ - Remove all allowable next actions. - """ - self._del_sub('{%s}actions' % self.namespace) - - def get_notes(self): - """ - Return a list of note information. - - Example: - [('info', 'Some informative data'), - ('warning', 'Use caution'), - ('error', 'The command ran, but had errors')] - """ - notes = [] - notes_xml = self.findall('{%s}note' % self.namespace) - for note in notes_xml: - notes.append((note.attrib.get('type', 'info'), - note.text)) - return notes - - def set_notes(self, notes): - """ - Add multiple notes to the command result. - - Each note is a tuple, with the first item being one of: - 'info', 'warning', or 'error', and the second item being - any human readable message. - - Example: - [('info', 'Some informative data'), - ('warning', 'Use caution'), - ('error', 'The command ran, but had errors')] - - - Arguments: - notes -- A list of tuples of note information. - """ - self.del_notes() - for note in notes: - self.add_note(note[1], note[0]) - - def del_notes(self): - """ - Remove all notes associated with the command result. - """ - notes_xml = self.findall('{%s}note' % self.namespace) - for note in notes_xml: - self.xml.remove(note) - - def add_note(self, msg='', ntype='info'): - """ - Add a single note annotation to the command. - - Arguments: - msg -- A human readable message. - ntype -- One of: 'info', 'warning', 'error' - """ - xml = ET.Element('{%s}note' % self.namespace) - xml.attrib['type'] = ntype - xml.text = msg - self.xml.append(xml) diff --git a/sleekxmpp/plugins/xep_0054/__init__.py b/sleekxmpp/plugins/xep_0054/__init__.py deleted file mode 100644 index d460cc8a..00000000 --- a/sleekxmpp/plugins/xep_0054/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0054.stanza import VCardTemp -from sleekxmpp.plugins.xep_0054.vcard_temp import XEP_0054 - - -register_plugin(XEP_0054) diff --git a/sleekxmpp/plugins/xep_0054/stanza.py b/sleekxmpp/plugins/xep_0054/stanza.py deleted file mode 100644 index 72da0b51..00000000 --- a/sleekxmpp/plugins/xep_0054/stanza.py +++ /dev/null @@ -1,561 +0,0 @@ -import base64 -import datetime as dt - -from sleekxmpp.util import bytes -from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin, JID -from sleekxmpp.plugins import xep_0082 - - -class VCardTemp(ElementBase): - name = 'vCard' - namespace = 'vcard-temp' - plugin_attrib = 'vcard_temp' - interfaces = set(['FN', 'VERSION']) - sub_interfaces = set(['FN', 'VERSION']) - - -class Name(ElementBase): - name = 'N' - namespace = 'vcard-temp' - plugin_attrib = name - interfaces = set(['FAMILY', 'GIVEN', 'MIDDLE', 'PREFIX', 'SUFFIX']) - sub_interfaces = interfaces - - def _set_component(self, name, value): - if isinstance(value, list): - value = ','.join(value) - if value is not None: - self._set_sub_text(name, value, keep=True) - else: - self._del_sub(name) - - def _get_component(self, name): - value = self._get_sub_text(name, '') - if ',' in value: - value = [v.strip() for v in value.split(',')] - return value - - def set_family(self, value): - self._set_component('FAMILY', value) - - def get_family(self): - return self._get_component('FAMILY') - - def set_given(self, value): - self._set_component('GIVEN', value) - - def get_given(self): - return self._get_component('GIVEN') - - def set_middle(self, value): - print(value) - self._set_component('MIDDLE', value) - - def get_middle(self): - return self._get_component('MIDDLE') - - def set_prefix(self, value): - self._set_component('PREFIX', value) - - def get_prefix(self): - return self._get_component('PREFIX') - - def set_suffix(self, value): - self._set_component('SUFFIX', value) - - def get_suffix(self): - return self._get_component('SUFFIX') - - -class Nickname(ElementBase): - name = 'NICKNAME' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'nicknames' - interfaces = set([name]) - is_extension = True - - def set_nickname(self, value): - if not value: - self.xml.text = '' - return - - if not isinstance(value, list): - value = [value] - - self.xml.text = ','.join(value) - - def get_nickname(self): - if self.xml.text: - return self.xml.text.split(',') - - -class Email(ElementBase): - name = 'EMAIL' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'emails' - interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID']) - sub_interfaces = set(['USERID']) - bool_interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400']) - - -class Address(ElementBase): - name = 'ADR' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'addresses' - interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL', - 'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY', - 'REGION', 'PCODE', 'CTRY']) - sub_interfaces = set(['POBOX', 'EXTADD', 'STREET', 'LOCALITY', - 'REGION', 'PCODE', 'CTRY']) - bool_interfaces = set(['HOME', 'WORK', 'DOM', 'INTL', 'PREF']) - - -class Telephone(ElementBase): - name = 'TEL' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'telephone_numbers' - interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG', - 'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS', - 'PREF', 'NUMBER']) - sub_interfaces = set(['NUMBER']) - bool_interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', - 'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM', - 'ISDN', 'PCS', 'PREF']) - - def setup(self, xml=None): - super(Telephone, self).setup(xml=xml) - self._set_sub_text('NUMBER', '', keep=True) - - def set_number(self, value): - self._set_sub_text('NUMBER', value, keep=True) - - def del_number(self): - self._set_sub_text('NUMBER', '', keep=True) - - -class Label(ElementBase): - name = 'LABEL' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'labels' - interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT', - 'PREF', 'lines']) - bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', - 'INT', 'PREF']) - - def add_line(self, value): - line = ET.Element('{%s}LINE' % self.namespace) - line.text = value - self.xml.append(line) - - def get_lines(self): - lines = self.xml.find('{%s}LINE' % self.namespace) - if lines is None: - return [] - return [line.text for line in lines] - - def set_lines(self, values): - self.del_lines() - for line in values: - self.add_line(line) - - def del_lines(self): - lines = self.xml.find('{%s}LINE' % self.namespace) - if lines is None: - return - for line in lines: - self.xml.remove(line) - - -class Geo(ElementBase): - name = 'GEO' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'geolocations' - interfaces = set(['LAT', 'LON']) - sub_interfaces = interfaces - - -class Org(ElementBase): - name = 'ORG' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'organizations' - interfaces = set(['ORGNAME', 'ORGUNIT', 'orgunits']) - sub_interfaces = set(['ORGNAME', 'ORGUNIT']) - - def add_orgunit(self, value): - orgunit = ET.Element('{%s}ORGUNIT' % self.namespace) - orgunit.text = value - self.xml.append(orgunit) - - def get_orgunits(self): - orgunits = self.xml.find('{%s}ORGUNIT' % self.namespace) - if orgunits is None: - return [] - return [orgunit.text for orgunit in orgunits] - - def set_orgunits(self, values): - self.del_orgunits() - for orgunit in values: - self.add_orgunit(orgunit) - - def del_orgunits(self): - orgunits = self.xml.find('{%s}ORGUNIT' % self.namespace) - if orgunits is None: - return - for orgunit in orgunits: - self.xml.remove(orgunit) - - -class Photo(ElementBase): - name = 'PHOTO' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'photos' - interfaces = set(['TYPE', 'EXTVAL']) - sub_interfaces = interfaces - - -class Logo(ElementBase): - name = 'LOGO' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'logos' - interfaces = set(['TYPE', 'EXTVAL']) - sub_interfaces = interfaces - - -class Sound(ElementBase): - name = 'SOUND' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'sounds' - interfaces = set(['PHONETC', 'EXTVAL']) - sub_interfaces = interfaces - - -class BinVal(ElementBase): - name = 'BINVAL' - namespace = 'vcard-temp' - plugin_attrib = name - interfaces = set(['BINVAL']) - is_extension = True - - def setup(self, xml=None): - self.xml = ET.Element('') - return True - - def set_binval(self, value): - self.del_binval() - parent = self.parent() - if value: - xml = ET.Element('{%s}BINVAL' % self.namespace) - xml.text = bytes(base64.b64encode(value)).decode('utf-8') - parent.append(xml) - - def get_binval(self): - parent = self.parent() - xml = parent.find('{%s}BINVAL' % self.namespace) - if xml is not None: - return base64.b64decode(bytes(xml.text)) - return b'' - - def del_binval(self): - self.parent()._del_sub('{%s}BINVAL' % self.namespace) - - -class Classification(ElementBase): - name = 'CLASS' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'classifications' - interfaces = set(['PUBLIC', 'PRIVATE', 'CONFIDENTIAL']) - bool_interfaces = interfaces - - -class Categories(ElementBase): - name = 'CATEGORIES' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'categories' - interfaces = set([name]) - is_extension = True - - def set_categories(self, values): - self.del_categories() - for keyword in values: - item = ET.Element('{%s}KEYWORD' % self.namespace) - item.text = keyword - self.xml.append(item) - - def get_categories(self): - items = self.xml.findall('{%s}KEYWORD' % self.namespace) - if items is None: - return [] - keywords = [] - for item in items: - keywords.append(item.text) - return keywords - - def del_categories(self): - items = self.xml.findall('{%s}KEYWORD' % self.namespace) - for item in items: - self.xml.remove(item) - - -class Birthday(ElementBase): - name = 'BDAY' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'birthdays' - interfaces = set([name]) - is_extension = True - - def set_bday(self, value): - if isinstance(value, dt.datetime): - value = xep_0082.format_datetime(value) - self.xml.text = value - - def get_bday(self): - if not self.xml.text: - return None - return xep_0082.parse(self.xml.text) - - -class Rev(ElementBase): - name = 'REV' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'revision_dates' - interfaces = set([name]) - is_extension = True - - def set_rev(self, value): - if isinstance(value, dt.datetime): - value = xep_0082.format_datetime(value) - self.xml.text = value - - def get_rev(self): - if not self.xml.text: - return None - return xep_0082.parse(self.xml.text) - - -class Title(ElementBase): - name = 'TITLE' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'titles' - interfaces = set([name]) - is_extension = True - - def set_title(self, value): - self.xml.text = value - - def get_title(self): - return self.xml.text - - -class Role(ElementBase): - name = 'ROLE' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'roles' - interfaces = set([name]) - is_extension = True - - def set_role(self, value): - self.xml.text = value - - def get_role(self): - return self.xml.text - - -class Note(ElementBase): - name = 'NOTE' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'notes' - interfaces = set([name]) - is_extension = True - - def set_note(self, value): - self.xml.text = value - - def get_note(self): - return self.xml.text - - -class Desc(ElementBase): - name = 'DESC' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'descriptions' - interfaces = set([name]) - is_extension = True - - def set_desc(self, value): - self.xml.text = value - - def get_desc(self): - return self.xml.text - - -class URL(ElementBase): - name = 'URL' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'urls' - interfaces = set([name]) - is_extension = True - - def set_url(self, value): - self.xml.text = value - - def get_url(self): - return self.xml.text - - -class UID(ElementBase): - name = 'UID' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'uids' - interfaces = set([name]) - is_extension = True - - def set_uid(self, value): - self.xml.text = value - - def get_uid(self): - return self.xml.text - - -class ProdID(ElementBase): - name = 'PRODID' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'product_ids' - interfaces = set([name]) - is_extension = True - - def set_prodid(self, value): - self.xml.text = value - - def get_prodid(self): - return self.xml.text - - -class Mailer(ElementBase): - name = 'MAILER' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'mailers' - interfaces = set([name]) - is_extension = True - - def set_mailer(self, value): - self.xml.text = value - - def get_mailer(self): - return self.xml.text - - -class SortString(ElementBase): - name = 'SORT-STRING' - namespace = 'vcard-temp' - plugin_attrib = 'SORT_STRING' - plugin_multi_attrib = 'sort_strings' - interfaces = set([name]) - is_extension = True - - def set_sort_string(self, value): - self.xml.text = value - - def get_sort_string(self): - return self.xml.text - - -class Agent(ElementBase): - name = 'AGENT' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'agents' - interfaces = set(['EXTVAL']) - sub_interfaces = interfaces - - -class JabberID(ElementBase): - name = 'JABBERID' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'jids' - interfaces = set([name]) - is_extension = True - - def set_jabberid(self, value): - self.xml.text = JID(value).bare - - def get_jabberid(self): - return JID(self.xml.text) - - -class TimeZone(ElementBase): - name = 'TZ' - namespace = 'vcard-temp' - plugin_attrib = name - plugin_multi_attrib = 'timezones' - interfaces = set([name]) - is_extension = True - - def set_tz(self, value): - time = xep_0082.time(offset=value) - if time[-1] == 'Z': - self.xml.text = 'Z' - else: - self.xml.text = time[-6:] - - def get_tz(self): - if not self.xml.text: - return xep_0082.tzutc() - time = xep_0082.parse('00:00:00%s' % self.xml.text) - return time.tzinfo - - -register_stanza_plugin(VCardTemp, Name) -register_stanza_plugin(VCardTemp, Address, iterable=True) -register_stanza_plugin(VCardTemp, Agent, iterable=True) -register_stanza_plugin(VCardTemp, Birthday, iterable=True) -register_stanza_plugin(VCardTemp, Categories, iterable=True) -register_stanza_plugin(VCardTemp, Desc, iterable=True) -register_stanza_plugin(VCardTemp, Email, iterable=True) -register_stanza_plugin(VCardTemp, Geo, iterable=True) -register_stanza_plugin(VCardTemp, JabberID, iterable=True) -register_stanza_plugin(VCardTemp, Label, iterable=True) -register_stanza_plugin(VCardTemp, Logo, iterable=True) -register_stanza_plugin(VCardTemp, Mailer, iterable=True) -register_stanza_plugin(VCardTemp, Note, iterable=True) -register_stanza_plugin(VCardTemp, Nickname, iterable=True) -register_stanza_plugin(VCardTemp, Org, iterable=True) -register_stanza_plugin(VCardTemp, Photo, iterable=True) -register_stanza_plugin(VCardTemp, ProdID, iterable=True) -register_stanza_plugin(VCardTemp, Rev, iterable=True) -register_stanza_plugin(VCardTemp, Role, iterable=True) -register_stanza_plugin(VCardTemp, SortString, iterable=True) -register_stanza_plugin(VCardTemp, Sound, iterable=True) -register_stanza_plugin(VCardTemp, Telephone, iterable=True) -register_stanza_plugin(VCardTemp, Title, iterable=True) -register_stanza_plugin(VCardTemp, TimeZone, iterable=True) -register_stanza_plugin(VCardTemp, UID, iterable=True) -register_stanza_plugin(VCardTemp, URL, iterable=True) - -register_stanza_plugin(Photo, BinVal) -register_stanza_plugin(Logo, BinVal) -register_stanza_plugin(Sound, BinVal) - -register_stanza_plugin(Agent, VCardTemp) diff --git a/sleekxmpp/plugins/xep_0054/vcard_temp.py b/sleekxmpp/plugins/xep_0054/vcard_temp.py deleted file mode 100644 index 97da8c7c..00000000 --- a/sleekxmpp/plugins/xep_0054/vcard_temp.py +++ /dev/null @@ -1,146 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import JID, Iq -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0054 import VCardTemp, stanza - - -log = logging.getLogger(__name__) - - -class XEP_0054(BasePlugin): - - """ - XEP-0054: vcard-temp - """ - - name = 'xep_0054' - description = 'XEP-0054: vcard-temp' - dependencies = set(['xep_0030', 'xep_0082']) - stanza = stanza - - def plugin_init(self): - """ - Start the XEP-0054 plugin. - """ - register_stanza_plugin(Iq, VCardTemp) - - - self.api.register(self._set_vcard, 'set_vcard', default=True) - self.api.register(self._get_vcard, 'get_vcard', default=True) - self.api.register(self._del_vcard, 'del_vcard', default=True) - - self._vcard_cache = {} - - self.xmpp.register_handler( - Callback('VCardTemp', - StanzaPath('iq/vcard_temp'), - self._handle_get_vcard)) - - def plugin_end(self): - self.xmpp.remove_handler('VCardTemp') - self.xmpp['xep_0030'].del_feature(feature='vcard-temp') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('vcard-temp') - - def make_vcard(self): - return VCardTemp() - - def get_vcard(self, jid=None, ifrom=None, local=None, cached=False, - block=True, callback=None, timeout=None): - if local is None: - if jid is not None and not isinstance(jid, JID): - jid = JID(jid) - if self.xmpp.is_component: - if jid.domain == self.xmpp.boundjid.domain: - local = True - else: - if str(jid) == str(self.xmpp.boundjid): - local = True - jid = jid.full - elif jid in (None, ''): - local = True - - if local: - vcard = self.api['get_vcard'](jid, None, ifrom) - if not isinstance(vcard, Iq): - iq = self.xmpp.Iq() - if vcard is None: - vcard = VCardTemp() - iq.append(vcard) - return iq - return vcard - - if cached: - vcard = self.api['get_vcard'](jid, None, ifrom) - if vcard is not None: - if not isinstance(vcard, Iq): - iq = self.xmpp.Iq() - iq.append(vcard) - return iq - return vcard - - iq = self.xmpp.Iq() - iq['to'] = jid - iq['from'] = ifrom - iq['type'] = 'get' - iq.enable('vcard_temp') - - vcard = iq.send(block=block, callback=callback, timeout=timeout) - - if block: - self.api['set_vcard'](vcard['from'], args=vcard['vcard_temp']) - return vcard - - def publish_vcard(self, vcard=None, jid=None, block=True, ifrom=None, - callback=None, timeout=None): - self.api['set_vcard'](jid, None, ifrom, vcard) - if self.xmpp.is_component: - return - - iq = self.xmpp.Iq() - iq['to'] = jid - iq['from'] = ifrom - iq['type'] = 'set' - iq.append(vcard) - return iq.send(block=block, callback=callback, timeout=timeout) - - def _handle_get_vcard(self, iq): - if iq['type'] == 'result': - self.api['set_vcard'](jid=iq['from'], args=iq['vcard_temp']) - return - elif iq['type'] == 'get': - vcard = self.api['get_vcard'](iq['from'].bare) - if isinstance(vcard, Iq): - vcard.send() - else: - iq.reply() - iq.append(vcard) - iq.send() - elif iq['type'] == 'set': - raise XMPPError('service-unavailable') - - # ================================================================= - - def _set_vcard(self, jid, node, ifrom, vcard): - self._vcard_cache[jid.bare] = vcard - - def _get_vcard(self, jid, node, ifrom, vcard): - return self._vcard_cache.get(jid.bare, None) - - def _del_vcard(self, jid, node, ifrom, vcard): - if jid.bare in self._vcard_cache: - del self._vcard_cache[jid.bare] diff --git a/sleekxmpp/plugins/xep_0059/__init__.py b/sleekxmpp/plugins/xep_0059/__init__.py deleted file mode 100644 index 3464ce32..00000000 --- a/sleekxmpp/plugins/xep_0059/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Erik Reuterborg Larsson - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0059.stanza import Set -from sleekxmpp.plugins.xep_0059.rsm import ResultIterator, XEP_0059 - - -register_plugin(XEP_0059) - -# Retain some backwards compatibility -xep_0059 = XEP_0059 diff --git a/sleekxmpp/plugins/xep_0059/rsm.py b/sleekxmpp/plugins/xep_0059/rsm.py deleted file mode 100644 index d73b45bc..00000000 --- a/sleekxmpp/plugins/xep_0059/rsm.py +++ /dev/null @@ -1,145 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Erik Reuterborg Larsson - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -import sleekxmpp -from sleekxmpp import Iq -from sleekxmpp.plugins import BasePlugin, register_plugin -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.xep_0059 import stanza, Set -from sleekxmpp.exceptions import XMPPError - - -log = logging.getLogger(__name__) - - -class ResultIterator(): - - """ - An iterator for Result Set Managment - """ - - def __init__(self, query, interface, results='substanzas', amount=10, - start=None, reverse=False): - """ - Arguments: - query -- The template query - interface -- The substanza of the query, for example disco_items - results -- The query stanza's interface which provides a - countable list of query results. - amount -- The max amounts of items to request per iteration - start -- From which item id to start - reverse -- If True, page backwards through the results - - Example: - q = Iq() - q['to'] = 'pubsub.example.com' - q['disco_items']['node'] = 'blog' - for i in ResultIterator(q, 'disco_items', '10'): - print i['disco_items']['items'] - - """ - self.query = query - self.amount = amount - self.start = start - self.interface = interface - self.results = results - self.reverse = reverse - self._stop = False - - def __iter__(self): - return self - - def __next__(self): - return self.next() - - def next(self): - """ - Return the next page of results from a query. - - Note: If using backwards paging, then the next page of - results will be the items before the current page - of items. - """ - if self._stop: - raise StopIteration - self.query[self.interface]['rsm']['before'] = self.reverse - self.query['id'] = self.query.stream.new_id() - self.query[self.interface]['rsm']['max'] = str(self.amount) - - if self.start and self.reverse: - self.query[self.interface]['rsm']['before'] = self.start - elif self.start: - self.query[self.interface]['rsm']['after'] = self.start - - try: - r = self.query.send(block=True) - - if not r[self.interface]['rsm']['first'] and \ - not r[self.interface]['rsm']['last']: - raise StopIteration - - if r[self.interface]['rsm']['count'] and \ - r[self.interface]['rsm']['first_index']: - count = int(r[self.interface]['rsm']['count']) - first = int(r[self.interface]['rsm']['first_index']) - num_items = len(r[self.interface][self.results]) - if first + num_items == count: - self._stop = True - - if self.reverse: - self.start = r[self.interface]['rsm']['first'] - else: - self.start = r[self.interface]['rsm']['last'] - - return r - except XMPPError: - raise StopIteration - - -class XEP_0059(BasePlugin): - - """ - XEP-0050: Result Set Management - """ - - name = 'xep_0059' - description = 'XEP-0059: Result Set Management' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - """ - Start the XEP-0059 plugin. - """ - register_stanza_plugin(self.xmpp['xep_0030'].stanza.DiscoItems, - self.stanza.Set) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=Set.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(Set.namespace) - - def iterate(self, stanza, interface, results='substanzas'): - """ - Create a new result set iterator for a given stanza query. - - Arguments: - stanza -- A stanza object to serve as a template for - queries made each iteration. For example, a - basic disco#items query. - interface -- The name of the substanza to which the - result set management stanza should be - appended. For example, for disco#items queries - the interface 'disco_items' should be used. - results -- The name of the interface containing the - query results (typically just 'substanzas'). - """ - return ResultIterator(stanza, interface, results) diff --git a/sleekxmpp/plugins/xep_0059/stanza.py b/sleekxmpp/plugins/xep_0059/stanza.py deleted file mode 100644 index 48f5c8a0..00000000 --- a/sleekxmpp/plugins/xep_0059/stanza.py +++ /dev/null @@ -1,108 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Erik Reuterborg Larsson - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase, ET -from sleekxmpp.plugins.xep_0030.stanza.items import DiscoItems - - -class Set(ElementBase): - - """ - XEP-0059 (Result Set Managment) can be used to manage the - results of queries. For example, limiting the number of items - per response or starting at certain positions. - - Example set stanzas: - - - - 2 - - - - - - - - - - conference.example.com - pubsub.example.com - - - - - Stanza Interface: - first_index -- The index attribute of - after -- The id defining from which item to start - before -- The id defining from which item to - start when browsing backwards - max -- Max amount per response - first -- Id for the first item in the response - last -- Id for the last item in the response - index -- Used to set an index to start from - count -- The number of remote items available - - Methods: - set_first_index -- Sets the index attribute for and - creates the element if it doesn't exist - get_first_index -- Returns the value of the index - attribute for - del_first_index -- Removes the index attribute for - but keeps the element - set_before -- Sets the value of , if the value is True - then the element will be created without a value - get_before -- Returns the value of , if it is - empty it will return True - - """ - namespace = 'http://jabber.org/protocol/rsm' - name = 'set' - plugin_attrib = 'rsm' - sub_interfaces = set(('first', 'after', 'before', 'count', - 'index', 'last', 'max')) - interfaces = set(('first_index', 'first', 'after', 'before', - 'count', 'index', 'last', 'max')) - - def set_first_index(self, val): - fi = self.find("{%s}first" % (self.namespace)) - if fi is not None: - if val: - fi.attrib['index'] = val - elif 'index' in fi.attrib: - del fi.attrib['index'] - elif val: - fi = ET.Element("{%s}first" % (self.namespace)) - fi.attrib['index'] = val - self.xml.append(fi) - - def get_first_index(self): - fi = self.find("{%s}first" % (self.namespace)) - if fi is not None: - return fi.attrib.get('index', '') - - def del_first_index(self): - fi = self.xml.find("{%s}first" % (self.namespace)) - if fi is not None: - del fi.attrib['index'] - - def set_before(self, val): - b = self.xml.find("{%s}before" % (self.namespace)) - if b is None and val is True: - self._set_sub_text('{%s}before' % self.namespace, '', True) - else: - self._set_sub_text('{%s}before' % self.namespace, val) - - def get_before(self): - b = self.xml.find("{%s}before" % (self.namespace)) - if b is not None and not b.text: - return True - elif b is not None: - return b.text - else: - return None diff --git a/sleekxmpp/plugins/xep_0060/__init__.py b/sleekxmpp/plugins/xep_0060/__init__.py deleted file mode 100644 index 86e2f472..00000000 --- a/sleekxmpp/plugins/xep_0060/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0060.pubsub import XEP_0060 -from sleekxmpp.plugins.xep_0060 import stanza - - -register_plugin(XEP_0060) - - -# Retain some backwards compatibility -xep_0060 = XEP_0060 diff --git a/sleekxmpp/plugins/xep_0060/pubsub.py b/sleekxmpp/plugins/xep_0060/pubsub.py deleted file mode 100644 index bec5f565..00000000 --- a/sleekxmpp/plugins/xep_0060/pubsub.py +++ /dev/null @@ -1,577 +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. -""" - -import logging - -from sleekxmpp.xmlstream import JID -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0060 import stanza - - -log = logging.getLogger(__name__) - - -class XEP_0060(BasePlugin): - - """ - XEP-0060 Publish Subscribe - """ - - name = 'xep_0060' - description = 'XEP-0060: Publish-Subscribe' - dependencies = set(['xep_0030', 'xep_0004', 'xep_0082', 'xep_0131']) - stanza = stanza - - def plugin_init(self): - self.node_event_map = {} - - self.xmpp.register_handler( - Callback('Pubsub Event: Items', - StanzaPath('message/pubsub_event/items'), - self._handle_event_items)) - self.xmpp.register_handler( - Callback('Pubsub Event: Purge', - StanzaPath('message/pubsub_event/purge'), - self._handle_event_purge)) - self.xmpp.register_handler( - Callback('Pubsub Event: Delete', - StanzaPath('message/pubsub_event/delete'), - self._handle_event_delete)) - self.xmpp.register_handler( - Callback('Pubsub Event: Configuration', - StanzaPath('message/pubsub_event/configuration'), - self._handle_event_configuration)) - self.xmpp.register_handler( - Callback('Pubsub Event: Subscription', - StanzaPath('message/pubsub_event/subscription'), - self._handle_event_subscription)) - - self.xmpp['xep_0131'].supported_headers.add('SubID') - - def plugin_end(self): - self.xmpp.remove_handler('Pubsub Event: Items') - self.xmpp.remove_handler('Pubsub Event: Purge') - self.xmpp.remove_handler('Pubsub Event: Delete') - self.xmpp.remove_handler('Pubsub Event: Configuration') - self.xmpp.remove_handler('Pubsub Event: Subscription') - - def _handle_event_items(self, msg): - """Raise events for publish and retraction notifications.""" - node = msg['pubsub_event']['items']['node'] - - multi = len(msg['pubsub_event']['items']) > 1 - values = {} - if multi: - values = msg.values - del values['pubsub_event'] - - for item in msg['pubsub_event']['items']: - event_name = self.node_event_map.get(node, None) - event_type = 'publish' - if item.name == 'retract': - event_type = 'retract' - - if multi: - condensed = self.xmpp.Message() - condensed.values = values - condensed['pubsub_event']['items']['node'] = node - condensed['pubsub_event']['items'].append(item) - self.xmpp.event('pubsub_%s' % event_type, msg) - if event_name: - self.xmpp.event('%s_%s' % (event_name, event_type), - condensed) - else: - self.xmpp.event('pubsub_%s' % event_type, msg) - if event_name: - self.xmpp.event('%s_%s' % (event_name, event_type), msg) - - def _handle_event_purge(self, msg): - """Raise events for node purge notifications.""" - node = msg['pubsub_event']['purge']['node'] - event_name = self.node_event_map.get(node, None) - - self.xmpp.event('pubsub_purge', msg) - if event_name: - self.xmpp.event('%s_purge' % event_name, msg) - - def _handle_event_delete(self, msg): - """Raise events for node deletion notifications.""" - node = msg['pubsub_event']['delete']['node'] - event_name = self.node_event_map.get(node, None) - - self.xmpp.event('pubsub_delete', msg) - if event_name: - self.xmpp.event('%s_delete' % event_name, msg) - - def _handle_event_configuration(self, msg): - """Raise events for node configuration notifications.""" - node = msg['pubsub_event']['configuration']['node'] - event_name = self.node_event_map.get(node, None) - - self.xmpp.event('pubsub_config', msg) - if event_name: - self.xmpp.event('%s_config' % event_name, msg) - - def _handle_event_subscription(self, msg): - """Raise events for node subscription notifications.""" - node = msg['pubsub_event']['subscription']['node'] - event_name = self.node_event_map.get(node, None) - - self.xmpp.event('pubsub_subscription', msg) - if event_name: - self.xmpp.event('%s_subscription' % event_name, msg) - - def map_node_event(self, node, event_name): - """ - Map node names to events. - - When a pubsub event is received for the given node, - raise the provided event. - - For example:: - - map_node_event('http://jabber.org/protocol/tune', - 'user_tune') - - will produce the events 'user_tune_publish' and 'user_tune_retract' - when the respective notifications are received from the node - 'http://jabber.org/protocol/tune', among other events. - - Arguments: - node -- The node name to map to an event. - event_name -- The name of the event to raise when a - notification from the given node is received. - """ - self.node_event_map[node] = event_name - - def create_node(self, jid, node, config=None, ntype=None, ifrom=None, - block=True, callback=None, timeout=None): - """ - Create and configure a new pubsub node. - - A server MAY use a different name for the node than the one provided, - so be sure to check the result stanza for a server assigned name. - - If no configuration form is provided, the node will be created using - the server's default configuration. To get the default configuration - use get_node_config(). - - Arguments: - jid -- The JID of the pubsub service. - node -- Optional name of the node to create. If no name is - provided, the server MAY generate a node ID for you. - The server can also assign a different name than the - one you provide; check the result stanza to see if - the server assigned a name. - config -- Optional XEP-0004 data form of configuration settings. - ntype -- The type of node to create. Servers typically default - to using 'leaf' if no type is provided. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub']['create']['node'] = node - - if config is not None: - form_type = 'http://jabber.org/protocol/pubsub#node_config' - if 'FORM_TYPE' in config['fields']: - config.field['FORM_TYPE']['value'] = form_type - else: - config.add_field(var='FORM_TYPE', - ftype='hidden', - value=form_type) - if ntype: - if 'pubsub#node_type' in config['fields']: - config.field['pubsub#node_type']['value'] = ntype - else: - config.add_field(var='pubsub#node_type', value=ntype) - iq['pubsub']['configure'].append(config) - - return iq.send(block=block, callback=callback, timeout=timeout) - - def subscribe(self, jid, node, bare=True, subscribee=None, options=None, - ifrom=None, block=True, callback=None, timeout=None): - """ - Subscribe to updates from a pubsub node. - - The rules for determining the JID that is subscribing to the node are: - 1. If subscribee is given, use that as provided. - 2. If ifrom was given, use the bare or full version based on bare. - 3. Otherwise, use self.xmpp.boundjid based on bare. - - Arguments: - jid -- The pubsub service JID. - node -- The node to subscribe to. - bare -- Indicates if the subscribee is a bare or full JID. - Defaults to True for a bare JID. - subscribee -- The JID that is subscribing to the node. - options -- - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a - response before exiting the send call if blocking - is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub']['subscribe']['node'] = node - - if subscribee is None: - if ifrom: - if bare: - subscribee = JID(ifrom).bare - else: - subscribee = ifrom - else: - if bare: - subscribee = self.xmpp.boundjid.bare - else: - subscribee = self.xmpp.boundjid - - iq['pubsub']['subscribe']['jid'] = subscribee - if options is not None: - iq['pubsub']['options'].append(options) - return iq.send(block=block, callback=callback, timeout=timeout) - - def unsubscribe(self, jid, node, subid=None, bare=True, subscribee=None, - ifrom=None, block=True, callback=None, timeout=None): - """ - Unubscribe from updates from a pubsub node. - - The rules for determining the JID that is unsubscribing - from the node are: - 1. If subscribee is given, use that as provided. - 2. If ifrom was given, use the bare or full version based on bare. - 3. Otherwise, use self.xmpp.boundjid based on bare. - - Arguments: - jid -- The pubsub service JID. - node -- The node to subscribe to. - subid -- The specific subscription, if multiple subscriptions - exist for this JID/node combination. - bare -- Indicates if the subscribee is a bare or full JID. - Defaults to True for a bare JID. - subscribee -- The JID that is subscribing to the node. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a - response before exiting the send call if blocking - is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub']['unsubscribe']['node'] = node - - if subscribee is None: - if ifrom: - if bare: - subscribee = JID(ifrom).bare - else: - subscribee = ifrom - else: - if bare: - subscribee = self.xmpp.boundjid.bare - else: - subscribee = self.xmpp.boundjid - - iq['pubsub']['unsubscribe']['jid'] = subscribee - iq['pubsub']['unsubscribe']['subid'] = subid - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_subscriptions(self, jid, node=None, ifrom=None, block=True, - callback=None, timeout=None): - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - iq['pubsub']['subscriptions']['node'] = node - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_affiliations(self, jid, node=None, ifrom=None, block=True, - callback=None, timeout=None): - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - iq['pubsub']['affiliations']['node'] = node - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_subscription_options(self, jid, node=None, user_jid=None, - ifrom=None, block=True, callback=None, - timeout=None): - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - if user_jid is None: - iq['pubsub']['default']['node'] = node - else: - iq['pubsub']['options']['node'] = node - iq['pubsub']['options']['jid'] = user_jid - return iq.send(block=block, callback=callback, timeout=timeout) - - def set_subscription_options(self, jid, node, user_jid, options, - ifrom=None, block=True, callback=None, - timeout=None): - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - iq['pubsub']['options']['node'] = node - iq['pubsub']['options']['jid'] = user_jid - iq['pubsub']['options'].append(options) - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_node_config(self, jid, node=None, ifrom=None, block=True, - callback=None, timeout=None): - """ - Retrieve the configuration for a node, or the pubsub service's - default configuration for new nodes. - - Arguments: - jid -- The JID of the pubsub service. - node -- The node to retrieve the configuration for. If None, - the default configuration for new nodes will be - requested. Defaults to None. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - if node is None: - iq['pubsub_owner']['default'] - else: - iq['pubsub_owner']['configure']['node'] = node - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_node_subscriptions(self, jid, node, ifrom=None, block=True, - callback=None, timeout=None): - """ - Retrieve the subscriptions associated with a given node. - - Arguments: - jid -- The JID of the pubsub service. - node -- The node to retrieve subscriptions from. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - iq['pubsub_owner']['subscriptions']['node'] = node - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_node_affiliations(self, jid, node, ifrom=None, block=True, - callback=None, timeout=None): - """ - Retrieve the affiliations associated with a given node. - - Arguments: - jid -- The JID of the pubsub service. - node -- The node to retrieve affiliations from. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - iq['pubsub_owner']['affiliations']['node'] = node - return iq.send(block=block, callback=callback, timeout=timeout) - - def delete_node(self, jid, node, ifrom=None, block=True, - callback=None, timeout=None): - """ - Delete a a pubsub node. - - Arguments: - jid -- The JID of the pubsub service. - node -- The node to delete. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub_owner']['delete']['node'] = node - return iq.send(block=block, callback=callback, timeout=timeout) - - def set_node_config(self, jid, node, config, ifrom=None, block=True, - callback=None, timeout=None): - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub_owner']['configure']['node'] = node - iq['pubsub_owner']['configure'].append(config) - return iq.send(block=block, callback=callback, timeout=timeout) - - def publish(self, jid, node, id=None, payload=None, options=None, - ifrom=None, block=True, callback=None, timeout=None): - """ - Add a new item to a node, or edit an existing item. - - For services that support it, you can use the publish command - as an event signal by not including an ID or payload. - - When including a payload and you do not provide an ID then - the service will generally create an ID for you. - - Publish options may be specified, and how those options - are processed is left to the service, such as treating - the options as preconditions that the node's settings - must match. - - Arguments: - jid -- The JID of the pubsub service. - node -- The node to publish the item to. - id -- Optionally specify the ID of the item. - payload -- The item content to publish. - options -- A form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub']['publish']['node'] = node - if id is not None: - iq['pubsub']['publish']['item']['id'] = id - if payload is not None: - iq['pubsub']['publish']['item']['payload'] = payload - iq['pubsub']['publish_options'] = options - return iq.send(block=block, callback=callback, timeout=timeout) - - def retract(self, jid, node, id, notify=None, ifrom=None, block=True, - callback=None, timeout=None): - """ - Delete a single item from a node. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - - iq['pubsub']['retract']['node'] = node - iq['pubsub']['retract']['notify'] = notify - iq['pubsub']['retract']['item']['id'] = id - return iq.send(block=block, callback=callback, timeout=timeout) - - def purge(self, jid, node, ifrom=None, block=True, callback=None, - timeout=None): - """ - Remove all items from a node. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub_owner']['purge']['node'] = node - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_nodes(self, *args, **kwargs): - """ - Discover the nodes provided by a Pubsub service, using disco. - """ - return self.xmpp['xep_0030'].get_items(*args, **kwargs) - - def get_item(self, jid, node, item_id, ifrom=None, block=True, - callback=None, timeout=None): - """ - Retrieve the content of an individual item. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - item = stanza.Item() - item['id'] = item_id - iq['pubsub']['items']['node'] = node - iq['pubsub']['items'].append(item) - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_items(self, jid, node, item_ids=None, max_items=None, - iterator=False, ifrom=None, block=False, - callback=None, timeout=None): - """ - Request the contents of a node's items. - - The desired items can be specified, or a query for the last - few published items can be used. - - Pubsub services may use result set management for nodes with - many items, so an iterator can be returned if needed. - """ - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='get') - iq['pubsub']['items']['node'] = node - iq['pubsub']['items']['max_items'] = max_items - - if item_ids is not None: - for item_id in item_ids: - item = stanza.Item() - item['id'] = item_id - iq['pubsub']['items'].append(item) - - if iterator: - return self.xmpp['xep_0059'].iterate(iq, 'pubsub') - else: - return iq.send(block=block, callback=callback, timeout=timeout) - - def get_item_ids(self, jid, node, ifrom=None, block=True, - callback=None, timeout=None, iterator=False): - """ - Retrieve the ItemIDs hosted by a given node, using disco. - """ - return self.xmpp['xep_0030'].get_items(jid, node, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout, - iterator=iterator) - - def modify_affiliations(self, jid, node, affiliations=None, ifrom=None, - block=True, callback=None, timeout=None): - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub_owner']['affiliations']['node'] = node - - if affiliations is None: - affiliations = [] - - for jid, affiliation in affiliations: - aff = stanza.OwnerAffiliation() - aff['jid'] = jid - aff['affiliation'] = affiliation - iq['pubsub_owner']['affiliations'].append(aff) - - return iq.send(block=block, callback=callback, timeout=timeout) - - def modify_subscriptions(self, jid, node, subscriptions=None, ifrom=None, - block=True, callback=None, timeout=None): - iq = self.xmpp.Iq(sto=jid, sfrom=ifrom, stype='set') - iq['pubsub_owner']['subscriptions']['node'] = node - - if subscriptions is None: - subscriptions = [] - - for jid, subscription in subscriptions: - sub = stanza.OwnerSubscription() - sub['jid'] = jid - sub['subscription'] = subscription - iq['pubsub_owner']['subscriptions'].append(sub) - - return iq.send(block=block, callback=callback, timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0060/stanza/__init__.py b/sleekxmpp/plugins/xep_0060/stanza/__init__.py deleted file mode 100644 index 37f52f0e..00000000 --- a/sleekxmpp/plugins/xep_0060/stanza/__init__.py +++ /dev/null @@ -1,12 +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.xep_0060.stanza.pubsub import * -from sleekxmpp.plugins.xep_0060.stanza.pubsub_owner import * -from sleekxmpp.plugins.xep_0060.stanza.pubsub_event import * -from sleekxmpp.plugins.xep_0060.stanza.pubsub_errors import * diff --git a/sleekxmpp/plugins/xep_0060/stanza/base.py b/sleekxmpp/plugins/xep_0060/stanza/base.py deleted file mode 100644 index d0b7851e..00000000 --- a/sleekxmpp/plugins/xep_0060/stanza/base.py +++ /dev/null @@ -1,29 +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.xmlstream import ET - - -class OptionalSetting(object): - - interfaces = set(('required',)) - - def set_required(self, value): - if value in (True, 'true', 'True', '1'): - self.xml.append(ET.Element("{%s}required" % self.namespace)) - elif self['required']: - self.del_required() - - def get_required(self): - required = self.xml.find("{%s}required" % self.namespace) - return required is not None - - def del_required(self): - required = self.xml.find("{%s}required" % self.namespace) - if required is not None: - self.xml.remove(required) diff --git a/sleekxmpp/plugins/xep_0060/stanza/pubsub.py b/sleekxmpp/plugins/xep_0060/stanza/pubsub.py deleted file mode 100644 index c1907a13..00000000 --- a/sleekxmpp/plugins/xep_0060/stanza/pubsub.py +++ /dev/null @@ -1,272 +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 import Iq, Message -from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, ET, JID -from sleekxmpp.plugins import xep_0004 -from sleekxmpp.plugins.xep_0060.stanza.base import OptionalSetting - - -class Pubsub(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'pubsub' - plugin_attrib = name - interfaces = set(tuple()) - - -class Affiliations(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'affiliations' - plugin_attrib = name - interfaces = set(('node',)) - - -class Affiliation(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'affiliation' - plugin_attrib = name - interfaces = set(('node', 'affiliation', 'jid')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -class Subscription(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscription' - plugin_attrib = name - interfaces = set(('jid', 'node', 'subscription', 'subid')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -class Subscriptions(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscriptions' - plugin_attrib = name - interfaces = set(('node',)) - - -class SubscribeOptions(ElementBase, OptionalSetting): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscribe-options' - plugin_attrib = 'suboptions' - interfaces = set(('required',)) - - -class Item(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'item' - plugin_attrib = name - interfaces = set(('id', 'payload')) - - def set_payload(self, value): - del self['payload'] - if isinstance(value, ElementBase): - if value.tag_name() in self.plugin_tag_map: - self.init_plugin(value.plugin_attrib, existing_xml=value.xml) - self.xml.append(value.xml) - else: - self.xml.append(value) - - def get_payload(self): - childs = list(self.xml) - if len(childs) > 0: - return childs[0] - - def del_payload(self): - for child in self.xml: - self.xml.remove(child) - - -class Items(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'items' - plugin_attrib = name - interfaces = set(('node', 'max_items')) - - def set_max_items(self, value): - self._set_attr('max_items', str(value)) - - -class Create(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'create' - plugin_attrib = name - interfaces = set(('node',)) - - -class Default(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'default' - plugin_attrib = name - interfaces = set(('node', 'type')) - - def get_type(self): - t = self._get_attr('type') - if not t: - return 'leaf' - return t - - -class Publish(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'publish' - plugin_attrib = name - interfaces = set(('node',)) - - -class Retract(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'retract' - plugin_attrib = name - interfaces = set(('node', 'notify')) - - def get_notify(self): - notify = self._get_attr('notify') - if notify in ('0', 'false'): - return False - elif notify in ('1', 'true'): - return True - return None - - def set_notify(self, value): - del self['notify'] - if value is None: - return - elif value in (True, '1', 'true', 'True'): - self._set_attr('notify', 'true') - else: - self._set_attr('notify', 'false') - - -class Unsubscribe(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'unsubscribe' - plugin_attrib = name - interfaces = set(('node', 'jid', 'subid')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -class Subscribe(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscribe' - plugin_attrib = name - interfaces = set(('node', 'jid')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -class Configure(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'configure' - plugin_attrib = name - interfaces = set(('node', 'type')) - - def getType(self): - t = self._get_attr('type') - if not t: - t == 'leaf' - return t - - -class Options(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'options' - plugin_attrib = name - interfaces = set(('jid', 'node', 'options')) - - def __init__(self, *args, **kwargs): - ElementBase.__init__(self, *args, **kwargs) - - def get_options(self): - config = self.xml.find('{jabber:x:data}x') - form = xep_0004.Form(xml=config) - return form - - def set_options(self, value): - self.xml.append(value.getXML()) - return self - - def del_options(self): - config = self.xml.find('{jabber:x:data}x') - self.xml.remove(config) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -class PublishOptions(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'publish-options' - plugin_attrib = 'publish_options' - interfaces = set(('publish_options',)) - is_extension = True - - def get_publish_options(self): - config = self.xml.find('{jabber:x:data}x') - if config is None: - return None - form = xep_0004.Form(xml=config) - return form - - def set_publish_options(self, value): - if value is None: - self.del_publish_options() - else: - self.xml.append(value.getXML()) - return self - - def del_publish_options(self): - config = self.xml.find('{jabber:x:data}x') - if config is not None: - self.xml.remove(config) - self.parent().xml.remove(self.xml) - - -register_stanza_plugin(Iq, Pubsub) -register_stanza_plugin(Pubsub, Affiliations) -register_stanza_plugin(Pubsub, Configure) -register_stanza_plugin(Pubsub, Create) -register_stanza_plugin(Pubsub, Default) -register_stanza_plugin(Pubsub, Items) -register_stanza_plugin(Pubsub, Options) -register_stanza_plugin(Pubsub, Publish) -register_stanza_plugin(Pubsub, PublishOptions) -register_stanza_plugin(Pubsub, Retract) -register_stanza_plugin(Pubsub, Subscribe) -register_stanza_plugin(Pubsub, Subscription) -register_stanza_plugin(Pubsub, Subscriptions) -register_stanza_plugin(Pubsub, Unsubscribe) -register_stanza_plugin(Affiliations, Affiliation, iterable=True) -register_stanza_plugin(Configure, xep_0004.Form) -register_stanza_plugin(Items, Item, iterable=True) -register_stanza_plugin(Publish, Item, iterable=True) -register_stanza_plugin(Retract, Item) -register_stanza_plugin(Subscribe, Options) -register_stanza_plugin(Subscription, SubscribeOptions) -register_stanza_plugin(Subscriptions, Subscription, iterable=True) diff --git a/sleekxmpp/plugins/xep_0060/stanza/pubsub_errors.py b/sleekxmpp/plugins/xep_0060/stanza/pubsub_errors.py deleted file mode 100644 index 59cf1a50..00000000 --- a/sleekxmpp/plugins/xep_0060/stanza/pubsub_errors.py +++ /dev/null @@ -1,86 +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.stanza import Error -from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin - - -class PubsubErrorCondition(ElementBase): - - plugin_attrib = 'pubsub' - interfaces = set(('condition', 'unsupported')) - plugin_attrib_map = {} - plugin_tag_map = {} - conditions = set(('closed-node', 'configuration-required', 'invalid-jid', - 'invalid-options', 'invalid-payload', 'invalid-subid', - 'item-forbidden', 'item-required', 'jid-required', - 'max-items-exceeded', 'max-nodes-exceeded', - 'nodeid-required', 'not-in-roster-group', - 'not-subscribed', 'payload-too-big', - 'payload-required', 'pending-subscription', - 'presence-subscription-required', 'subid-required', - 'too-many-subscriptions', 'unsupported')) - condition_ns = 'http://jabber.org/protocol/pubsub#errors' - - def setup(self, xml): - """Don't create XML for the plugin.""" - self.xml = ET.Element('') - - def get_condition(self): - """Return the condition element's name.""" - for child in self.parent().xml: - if "{%s}" % self.condition_ns in child.tag: - cond = child.tag.split('}', 1)[-1] - if cond in self.conditions: - return cond - return '' - - def set_condition(self, value): - """ - Set the tag name of the condition element. - - Arguments: - value -- The tag name of the condition element. - """ - if value in self.conditions: - del self['condition'] - cond = ET.Element("{%s}%s" % (self.condition_ns, value)) - self.parent().xml.append(cond) - return self - - def del_condition(self): - """Remove the condition element.""" - for child in self.parent().xml: - if "{%s}" % self.condition_ns in child.tag: - tag = child.tag.split('}', 1)[-1] - if tag in self.conditions: - self.parent().xml.remove(child) - return self - - def get_unsupported(self): - """Return the name of an unsupported feature""" - xml = self.parent().xml.find('{%s}unsupported' % self.condition_ns) - if xml is not None: - return xml.attrib.get('feature', '') - return '' - - def set_unsupported(self, value): - """Mark a feature as unsupported""" - self.del_unsupported() - xml = ET.Element('{%s}unsupported' % self.condition_ns) - xml.attrib['feature'] = value - self.parent().xml.append(xml) - - def del_unsupported(self): - """Delete an unsupported feature condition.""" - xml = self.parent().xml.find('{%s}unsupported' % self.condition_ns) - if xml is not None: - self.parent().xml.remove(xml) - - -register_stanza_plugin(Error, PubsubErrorCondition) diff --git a/sleekxmpp/plugins/xep_0060/stanza/pubsub_event.py b/sleekxmpp/plugins/xep_0060/stanza/pubsub_event.py deleted file mode 100644 index 32f217fa..00000000 --- a/sleekxmpp/plugins/xep_0060/stanza/pubsub_event.py +++ /dev/null @@ -1,151 +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. -""" - -import datetime as dt - -from sleekxmpp import Message -from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, ET, JID -from sleekxmpp.plugins.xep_0004 import Form -from sleekxmpp.plugins import xep_0082 - - -class Event(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'event' - plugin_attrib = 'pubsub_event' - interfaces = set() - - -class EventItem(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'item' - plugin_attrib = name - interfaces = set(('id', 'payload', 'node', 'publisher')) - - def set_payload(self, value): - self.xml.append(value) - - def get_payload(self): - childs = list(self.xml) - if len(childs) > 0: - return childs[0] - - def del_payload(self): - for child in self.xml: - self.xml.remove(child) - - -class EventRetract(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'retract' - plugin_attrib = name - interfaces = set(('id',)) - - -class EventItems(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'items' - plugin_attrib = name - interfaces = set(('node',)) - - -class EventCollection(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'collection' - plugin_attrib = name - interfaces = set(('node',)) - - -class EventAssociate(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'associate' - plugin_attrib = name - interfaces = set(('node',)) - - -class EventDisassociate(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'disassociate' - plugin_attrib = name - interfaces = set(('node',)) - - -class EventConfiguration(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'configuration' - plugin_attrib = name - interfaces = set(('node',)) - - -class EventPurge(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'purge' - plugin_attrib = name - interfaces = set(('node',)) - - -class EventDelete(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'delete' - plugin_attrib = name - interfaces = set(('node', 'redirect')) - - def set_redirect(self, uri): - del self['redirect'] - redirect = ET.Element('{%s}redirect' % self.namespace) - redirect.attrib['uri'] = uri - self.xml.append(redirect) - - def get_redirect(self): - redirect = self.xml.find('{%s}redirect' % self.namespace) - if redirect is not None: - return redirect.attrib.get('uri', '') - return '' - - def del_redirect(self): - redirect = self.xml.find('{%s}redirect' % self.namespace) - if redirect is not None: - self.xml.remove(redirect) - - -class EventSubscription(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'subscription' - plugin_attrib = name - interfaces = set(('node', 'expiry', 'jid', 'subid', 'subscription')) - - def get_expiry(self): - expiry = self._get_attr('expiry') - if expiry.lower() == 'presence': - return expiry - return xep_0082.parse(expiry) - - def set_expiry(self, value): - if isinstance(value, dt.datetime): - value = xep_0082.format_datetime(value) - self._set_attr('expiry', value) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -register_stanza_plugin(Message, Event) -register_stanza_plugin(Event, EventCollection) -register_stanza_plugin(Event, EventConfiguration) -register_stanza_plugin(Event, EventPurge) -register_stanza_plugin(Event, EventDelete) -register_stanza_plugin(Event, EventItems) -register_stanza_plugin(Event, EventSubscription) -register_stanza_plugin(EventCollection, EventAssociate) -register_stanza_plugin(EventCollection, EventDisassociate) -register_stanza_plugin(EventConfiguration, Form) -register_stanza_plugin(EventItems, EventItem, iterable=True) -register_stanza_plugin(EventItems, EventRetract, iterable=True) diff --git a/sleekxmpp/plugins/xep_0060/stanza/pubsub_owner.py b/sleekxmpp/plugins/xep_0060/stanza/pubsub_owner.py deleted file mode 100644 index d975a46d..00000000 --- a/sleekxmpp/plugins/xep_0060/stanza/pubsub_owner.py +++ /dev/null @@ -1,134 +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 import Iq -from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, ET, JID -from sleekxmpp.plugins.xep_0004 import Form -from sleekxmpp.plugins.xep_0060.stanza.base import OptionalSetting -from sleekxmpp.plugins.xep_0060.stanza.pubsub import Affiliations, Affiliation -from sleekxmpp.plugins.xep_0060.stanza.pubsub import Configure, Subscriptions - - -class PubsubOwner(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'pubsub' - plugin_attrib = 'pubsub_owner' - interfaces = set(tuple()) - - -class DefaultConfig(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'default' - plugin_attrib = name - interfaces = set(('node', 'config')) - - def __init__(self, *args, **kwargs): - ElementBase.__init__(self, *args, **kwargs) - - def get_config(self): - return self['form'] - - def set_config(self, value): - del self['from'] - self.append(value) - return self - - -class OwnerAffiliations(Affiliations): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('node',)) - - def append(self, affiliation): - if not isinstance(affiliation, OwnerAffiliation): - raise TypeError - self.xml.append(affiliation.xml) - - -class OwnerAffiliation(Affiliation): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('affiliation', 'jid')) - - -class OwnerConfigure(Configure): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'configure' - plugin_attrib = name - interfaces = set(('node',)) - - -class OwnerDefault(OwnerConfigure): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('node',)) - - -class OwnerDelete(ElementBase, OptionalSetting): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'delete' - plugin_attrib = name - interfaces = set(('node',)) - - -class OwnerPurge(ElementBase, OptionalSetting): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'purge' - plugin_attrib = name - interfaces = set(('node',)) - - -class OwnerRedirect(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'redirect' - plugin_attrib = name - interfaces = set(('node', 'jid')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -class OwnerSubscriptions(Subscriptions): - name = 'subscriptions' - namespace = 'http://jabber.org/protocol/pubsub#owner' - plugin_attrib = name - interfaces = set(('node',)) - - def append(self, subscription): - if not isinstance(subscription, OwnerSubscription): - raise TypeError - self.xml.append(subscription.xml) - - -class OwnerSubscription(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'subscription' - plugin_attrib = name - interfaces = set(('jid', 'subscription')) - - def set_jid(self, value): - self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -register_stanza_plugin(Iq, PubsubOwner) -register_stanza_plugin(PubsubOwner, DefaultConfig) -register_stanza_plugin(PubsubOwner, OwnerAffiliations) -register_stanza_plugin(PubsubOwner, OwnerConfigure) -register_stanza_plugin(PubsubOwner, OwnerDefault) -register_stanza_plugin(PubsubOwner, OwnerDelete) -register_stanza_plugin(PubsubOwner, OwnerPurge) -register_stanza_plugin(PubsubOwner, OwnerSubscriptions) -register_stanza_plugin(DefaultConfig, Form) -register_stanza_plugin(OwnerAffiliations, OwnerAffiliation, iterable=True) -register_stanza_plugin(OwnerConfigure, Form) -register_stanza_plugin(OwnerDefault, Form) -register_stanza_plugin(OwnerDelete, OwnerRedirect) -register_stanza_plugin(OwnerSubscriptions, OwnerSubscription, iterable=True) diff --git a/sleekxmpp/plugins/xep_0065/__init__.py b/sleekxmpp/plugins/xep_0065/__init__.py deleted file mode 100644 index feca2ef1..00000000 --- a/sleekxmpp/plugins/xep_0065/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0065.stanza import Socks5 -from sleekxmpp.plugins.xep_0065.proxy import XEP_0065 - - -register_plugin(XEP_0065) diff --git a/sleekxmpp/plugins/xep_0065/proxy.py b/sleekxmpp/plugins/xep_0065/proxy.py deleted file mode 100644 index fdd9f97e..00000000 --- a/sleekxmpp/plugins/xep_0065/proxy.py +++ /dev/null @@ -1,292 +0,0 @@ -import logging -import threading -import socket - -from hashlib import sha1 -from uuid import uuid4 - -from sleekxmpp.thirdparty.socks import socksocket, PROXY_TYPE_SOCKS5 - -from sleekxmpp.stanza import Iq -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins.base import base_plugin - -from sleekxmpp.plugins.xep_0065 import stanza, Socks5 - - -log = logging.getLogger(__name__) - - -class XEP_0065(base_plugin): - - name = 'xep_0065' - description = "Socks5 Bytestreams" - dependencies = set(['xep_0030']) - default_config = { - 'auto_accept': False - } - - def plugin_init(self): - register_stanza_plugin(Iq, Socks5) - - self._proxies = {} - self._sessions = {} - self._sessions_lock = threading.Lock() - - self._preauthed_sids_lock = threading.Lock() - self._preauthed_sids = {} - - self.xmpp.register_handler( - Callback('Socks5 Bytestreams', - StanzaPath('iq@type=set/socks/streamhost'), - self._handle_streamhost)) - - self.api.register(self._authorized, 'authorized', default=True) - self.api.register(self._authorized_sid, 'authorized_sid', default=True) - self.api.register(self._preauthorize_sid, 'preauthorize_sid', default=True) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(Socks5.namespace) - - def plugin_end(self): - self.xmpp.remove_handler('Socks5 Bytestreams') - self.xmpp.remove_handler('Socks5 Streamhost Used') - self.xmpp['xep_0030'].del_feature(feature=Socks5.namespace) - - def get_socket(self, sid): - """Returns the socket associated to the SID.""" - return self._sessions.get(sid, None) - - def handshake(self, to, ifrom=None, sid=None, timeout=None): - """ Starts the handshake to establish the socks5 bytestreams - connection. - """ - if not self._proxies: - self._proxies = self.discover_proxies() - - if sid is None: - sid = uuid4().hex - - used = self.request_stream(to, sid=sid, ifrom=ifrom, timeout=timeout) - proxy = used['socks']['streamhost_used']['jid'] - - if proxy not in self._proxies: - log.warning('Received unknown SOCKS5 proxy: %s', proxy) - return - - with self._sessions_lock: - self._sessions[sid] = self._connect_proxy( - sid, - self.xmpp.boundjid, - to, - self._proxies[proxy][0], - self._proxies[proxy][1], - peer=to) - - # Request that the proxy activate the session with the target. - self.activate(proxy, sid, to, timeout=timeout) - socket = self.get_socket(sid) - self.xmpp.event('stream:%s:%s' % (sid, to), socket) - return socket - - def request_stream(self, to, sid=None, ifrom=None, block=True, timeout=None, callback=None): - if sid is None: - sid = uuid4().hex - - # Requester initiates S5B negotiation with Target by sending - # IQ-set that includes the JabberID and network address of - # StreamHost as well as the StreamID (SID) of the proposed - # bytestream. - iq = self.xmpp.Iq() - iq['to'] = to - iq['from'] = ifrom - iq['type'] = 'set' - iq['socks']['sid'] = sid - for proxy, (host, port) in self._proxies.items(): - iq['socks'].add_streamhost(proxy, host, port) - return iq.send(block=block, timeout=timeout, callback=callback) - - def discover_proxies(self, jid=None, ifrom=None, timeout=None): - """Auto-discover the JIDs of SOCKS5 proxies on an XMPP server.""" - if jid is None: - if self.xmpp.is_component: - jid = self.xmpp.server - else: - jid = self.xmpp.boundjid.server - - discovered = set() - - disco_items = self.xmpp['xep_0030'].get_items(jid, timeout=timeout) - - for item in disco_items['disco_items']['items']: - try: - disco_info = self.xmpp['xep_0030'].get_info(item[0], timeout=timeout) - except XMPPError: - continue - else: - # Verify that the identity is a bytestream proxy. - identities = disco_info['disco_info']['identities'] - for identity in identities: - if identity[0] == 'proxy' and identity[1] == 'bytestreams': - discovered.add(disco_info['from']) - - for jid in discovered: - try: - addr = self.get_network_address(jid, ifrom=ifrom, timeout=timeout) - self._proxies[jid] = (addr['socks']['streamhost']['host'], - addr['socks']['streamhost']['port']) - except XMPPError: - continue - - return self._proxies - - def get_network_address(self, proxy, ifrom=None, block=True, timeout=None, callback=None): - """Get the network information of a proxy.""" - iq = self.xmpp.Iq(sto=proxy, stype='get', sfrom=ifrom) - iq.enable('socks') - return iq.send(block=block, timeout=timeout, callback=callback) - - def _handle_streamhost(self, iq): - """Handle incoming SOCKS5 session request.""" - sid = iq['socks']['sid'] - if not sid: - raise XMPPError(etype='modify', condition='bad-request') - - if not self._accept_stream(iq): - raise XMPPError(etype='modify', condition='not-acceptable') - - streamhosts = iq['socks']['streamhosts'] - conn = None - used_streamhost = None - - sender = iq['from'] - for streamhost in streamhosts: - try: - conn = self._connect_proxy(sid, - sender, - self.xmpp.boundjid, - streamhost['host'], - streamhost['port'], - peer=sender) - used_streamhost = streamhost['jid'] - break - except socket.error: - continue - else: - raise XMPPError(etype='cancel', condition='item-not-found') - - iq.reply() - with self._sessions_lock: - self._sessions[sid] = conn - iq['socks']['sid'] = sid - iq['socks']['streamhost_used']['jid'] = used_streamhost - iq.send() - self.xmpp.event('socks5_stream', conn) - self.xmpp.event('stream:%s:%s' % (sid, conn.peer_jid), conn) - - def activate(self, proxy, sid, target, ifrom=None, block=True, timeout=None, callback=None): - """Activate the socks5 session that has been negotiated.""" - iq = self.xmpp.Iq(sto=proxy, stype='set', sfrom=ifrom) - iq['socks']['sid'] = sid - iq['socks']['activate'] = target - iq.send(block=block, timeout=timeout, callback=callback) - - def deactivate(self, sid): - """Closes the proxy socket associated with this SID.""" - sock = self._sessions.get(sid) - if sock: - try: - # sock.close() will also delete sid from self._sessions (see _connect_proxy) - sock.close() - except socket.error: - pass - # Though this should not be neccessary remove the closed session anyway - with self._sessions_lock: - if sid in self._sessions: - log.warn(('SOCKS5 session with sid = "%s" was not ' + - 'removed from _sessions by sock.close()') % sid) - del self._sessions[sid] - - def close(self): - """Closes all proxy sockets.""" - for sid, sock in self._sessions.items(): - sock.close() - with self._sessions_lock: - self._sessions = {} - - def _connect_proxy(self, sid, requester, target, proxy, proxy_port, peer=None): - """ Establishes a connection between the client and the server-side - Socks5 proxy. - - sid : The StreamID. - requester : The JID of the requester. - target : The JID of the target. - proxy_host : The hostname or the IP of the proxy. - proxy_port : The port of the proxy. or - peer : The JID for the other side of the stream, regardless - of target or requester status. - """ - # Because the xep_0065 plugin uses the proxy_port as string, - # the Proxy class accepts the proxy_port argument as a string - # or an integer. Here, we force to use the port as an integer. - proxy_port = int(proxy_port) - - sock = socksocket() - sock.setproxy(PROXY_TYPE_SOCKS5, proxy, port=proxy_port) - - # The hostname MUST be SHA1(SID + Requester JID + Target JID) - # where the output is hexadecimal-encoded (not binary). - digest = sha1() - digest.update(sid) - digest.update(str(requester)) - digest.update(str(target)) - - dest = digest.hexdigest() - - # The port MUST be 0. - sock.connect((dest, 0)) - log.info('Socket connected.') - - _close = sock.close - def close(*args, **kwargs): - with self._sessions_lock: - if sid in self._sessions: - del self._sessions[sid] - _close() - log.info('Socket closed.') - sock.close = close - - sock.peer_jid = peer - sock.self_jid = target if requester == peer else requester - - self.xmpp.event('socks_connected', sid) - return sock - - def _accept_stream(self, iq): - receiver = iq['to'] - sender = iq['from'] - sid = iq['socks']['sid'] - - if self.api['authorized_sid'](receiver, sid, sender, iq): - return True - return self.api['authorized'](receiver, sid, sender, iq) - - def _authorized(self, jid, sid, ifrom, iq): - return self.auto_accept - - def _authorized_sid(self, jid, sid, ifrom, iq): - with self._preauthed_sids_lock: - log.debug('>>> authed sids: %s', self._preauthed_sids) - log.debug('>>> lookup: %s %s %s', jid, sid, ifrom) - if (jid, sid, ifrom) in self._preauthed_sids: - del self._preauthed_sids[(jid, sid, ifrom)] - return True - return False - - def _preauthorize_sid(self, jid, sid, ifrom, data): - log.debug('>>>> %s %s %s %s', jid, sid, ifrom, data) - with self._preauthed_sids_lock: - self._preauthed_sids[(jid, sid, ifrom)] = True diff --git a/sleekxmpp/plugins/xep_0065/stanza.py b/sleekxmpp/plugins/xep_0065/stanza.py deleted file mode 100644 index e48bf1b5..00000000 --- a/sleekxmpp/plugins/xep_0065/stanza.py +++ /dev/null @@ -1,47 +0,0 @@ -from sleekxmpp.jid import JID -from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin - - -class Socks5(ElementBase): - name = 'query' - namespace = 'http://jabber.org/protocol/bytestreams' - plugin_attrib = 'socks' - interfaces = set(['sid', 'activate']) - sub_interfaces = set(['activate']) - - def add_streamhost(self, jid, host, port): - sh = StreamHost(parent=self) - sh['jid'] = jid - sh['host'] = host - sh['port'] = port - - -class StreamHost(ElementBase): - name = 'streamhost' - namespace = 'http://jabber.org/protocol/bytestreams' - plugin_attrib = 'streamhost' - plugin_multi_attrib = 'streamhosts' - interfaces = set(['host', 'jid', 'port']) - - def set_jid(self, value): - return self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -class StreamHostUsed(ElementBase): - name = 'streamhost-used' - namespace = 'http://jabber.org/protocol/bytestreams' - plugin_attrib = 'streamhost_used' - interfaces = set(['jid']) - - def set_jid(self, value): - return self._set_attr('jid', str(value)) - - def get_jid(self): - return JID(self._get_attr('jid')) - - -register_stanza_plugin(Socks5, StreamHost, iterable=True) -register_stanza_plugin(Socks5, StreamHostUsed) diff --git a/sleekxmpp/plugins/xep_0066/__init__.py b/sleekxmpp/plugins/xep_0066/__init__.py deleted file mode 100644 index 68a50180..00000000 --- a/sleekxmpp/plugins/xep_0066/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0066 import stanza -from sleekxmpp.plugins.xep_0066.stanza import OOB, OOBTransfer -from sleekxmpp.plugins.xep_0066.oob import XEP_0066 - - -register_plugin(XEP_0066) - - -# Retain some backwards compatibility -xep_0066 = XEP_0066 diff --git a/sleekxmpp/plugins/xep_0066/oob.py b/sleekxmpp/plugins/xep_0066/oob.py deleted file mode 100644 index 959c15a2..00000000 --- a/sleekxmpp/plugins/xep_0066/oob.py +++ /dev/null @@ -1,158 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 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 Message, Presence, Iq -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0066 import stanza - - -log = logging.getLogger(__name__) - - -class XEP_0066(BasePlugin): - - """ - XEP-0066: Out of Band Data - - Out of Band Data is a basic method for transferring files between - XMPP agents. The URL of the resource in question is sent to the receiving - entity, which then downloads the resource before responding to the OOB - request. OOB is also used as a generic means to transmit URLs in other - stanzas to indicate where to find additional information. - - Also see . - - Events: - oob_transfer -- Raised when a request to download a resource - has been received. - - Methods: - send_oob -- Send a request to another entity to download a file - or other addressable resource. - """ - - name = 'xep_0066' - description = 'XEP-0066: Out of Band Data' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - """Start the XEP-0066 plugin.""" - - self.url_handlers = {'global': self._default_handler, - 'jid': {}} - - register_stanza_plugin(Iq, stanza.OOBTransfer) - register_stanza_plugin(Message, stanza.OOB) - register_stanza_plugin(Presence, stanza.OOB) - - self.xmpp.register_handler( - Callback('OOB Transfer', - StanzaPath('iq@type=set/oob_transfer'), - self._handle_transfer)) - - def plugin_end(self): - self.xmpp.remove_handler('OOB Transfer') - self.xmpp['xep_0030'].del_feature(feature=stanza.OOBTransfer.namespace) - self.xmpp['xep_0030'].del_feature(feature=stanza.OOB.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(stanza.OOBTransfer.namespace) - self.xmpp['xep_0030'].add_feature(stanza.OOB.namespace) - - def register_url_handler(self, jid=None, handler=None): - """ - Register a handler to process download requests, either for all - JIDs or a single JID. - - Arguments: - jid -- If None, then set the handler as a global default. - handler -- If None, then remove the existing handler for the - given JID, or reset the global handler if the JID - is None. - """ - if jid is None: - if handler is not None: - self.url_handlers['global'] = handler - else: - self.url_handlers['global'] = self._default_handler - else: - if handler is not None: - self.url_handlers['jid'][jid] = handler - else: - del self.url_handlers['jid'][jid] - - def send_oob(self, to, url, desc=None, ifrom=None, **iqargs): - """ - Initiate a basic file transfer by sending the URL of - a file or other resource. - - Arguments: - url -- The URL of the resource to transfer. - desc -- An optional human readable description of the item - that is to be transferred. - ifrom -- Specifiy the sender's JID. - block -- If true, block and wait for the stanzas' reply. - timeout -- The time in seconds to block while waiting for - a reply. If None, then wait indefinitely. - callback -- Optional callback to execute when a reply is - received instead of blocking and waiting for - the reply. - """ - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['to'] = to - iq['from'] = ifrom - iq['oob_transfer']['url'] = url - iq['oob_transfer']['desc'] = desc - return iq.send(**iqargs) - - def _run_url_handler(self, iq): - """ - Execute the appropriate handler for a transfer request. - - Arguments: - iq -- The Iq stanza containing the OOB transfer request. - """ - if iq['to'] in self.url_handlers['jid']: - return self.url_handlers['jid'][iq['to']](iq) - else: - if self.url_handlers['global']: - self.url_handlers['global'](iq) - else: - raise XMPPError('service-unavailable') - - def _default_handler(self, iq): - """ - As a safe default, don't actually download files. - - Register a new handler using self.register_url_handler to - screen requests and download files. - - Arguments: - iq -- The Iq stanza containing the OOB transfer request. - """ - raise XMPPError('service-unavailable') - - def _handle_transfer(self, iq): - """ - Handle receiving an out-of-band transfer request. - - Arguments: - iq -- An Iq stanza containing an OOB transfer request. - """ - log.debug('Received out-of-band data request for %s from %s:' % ( - iq['oob_transfer']['url'], iq['from'])) - self._run_url_handler(iq) - iq.reply().send() diff --git a/sleekxmpp/plugins/xep_0066/stanza.py b/sleekxmpp/plugins/xep_0066/stanza.py deleted file mode 100644 index 21387485..00000000 --- a/sleekxmpp/plugins/xep_0066/stanza.py +++ /dev/null @@ -1,33 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 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 - - -class OOBTransfer(ElementBase): - - """ - """ - - name = 'query' - namespace = 'jabber:iq:oob' - plugin_attrib = 'oob_transfer' - interfaces = set(('url', 'desc', 'sid')) - sub_interfaces = set(('url', 'desc')) - - -class OOB(ElementBase): - - """ - """ - - name = 'x' - namespace = 'jabber:x:oob' - plugin_attrib = 'oob' - interfaces = set(('url', 'desc')) - sub_interfaces = interfaces diff --git a/sleekxmpp/plugins/xep_0071/__init__.py b/sleekxmpp/plugins/xep_0071/__init__.py deleted file mode 100644 index c21e9265..00000000 --- a/sleekxmpp/plugins/xep_0071/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permissio -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0071.stanza import XHTML_IM -from sleekxmpp.plugins.xep_0071.xhtml_im import XEP_0071 - - -register_plugin(XEP_0071) diff --git a/sleekxmpp/plugins/xep_0071/stanza.py b/sleekxmpp/plugins/xep_0071/stanza.py deleted file mode 100644 index d5ff1a1b..00000000 --- a/sleekxmpp/plugins/xep_0071/stanza.py +++ /dev/null @@ -1,81 +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.stanza import Message -from sleekxmpp.util import unicode -from sleekxmpp.thirdparty import OrderedDict -from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin, tostring - - -XHTML_NS = 'http://www.w3.org/1999/xhtml' - - -class XHTML_IM(ElementBase): - - namespace = 'http://jabber.org/protocol/xhtml-im' - name = 'html' - interfaces = set(['body']) - lang_interfaces = set(['body']) - plugin_attrib = name - - def set_body(self, content, lang=None): - if lang is None: - lang = self.get_lang() - self.del_body(lang) - if lang == '*': - for sublang, subcontent in content.items(): - self.set_body(subcontent, sublang) - else: - if isinstance(content, type(ET.Element('test'))): - content = unicode(ET.tostring(content)) - else: - content = unicode(content) - header = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>') - if msg['type'] == 'error': - self.xmpp.event('amp_error', msg) - elif msg['amp']['status'] in ('alert', 'notify'): - self.xmpp.event('amp_%s' % msg['amp']['status'], msg) - - def _handle_amp_feature(self, features): - log.debug('Advanced Message Processing is available.') - self.xmpp.features.add('amp') - - def discover_support(self, jid=None, **iqargs): - if jid is None: - if self.xmpp.is_component: - jid = self.xmpp.server_host - else: - jid = self.xmpp.boundjid.host - - return self.xmpp['xep_0030'].get_info( - jid=jid, - node='http://jabber.org/protocol/amp', - **iqargs) diff --git a/sleekxmpp/plugins/xep_0079/stanza.py b/sleekxmpp/plugins/xep_0079/stanza.py deleted file mode 100644 index cb6932d6..00000000 --- a/sleekxmpp/plugins/xep_0079/stanza.py +++ /dev/null @@ -1,96 +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 __future__ import unicode_literals - -from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin - - -class AMP(ElementBase): - namespace = 'http://jabber.org/protocol/amp' - name = 'amp' - plugin_attrib = 'amp' - interfaces = set(['from', 'to', 'status', 'per_hop']) - - def get_from(self): - return JID(self._get_attr('from')) - - def set_from(self, value): - return self._set_attr('from', str(value)) - - def get_to(self): - return JID(self._get_attr('from')) - - def set_to(self, value): - return self._set_attr('to', str(value)) - - def get_per_hop(self): - return self._get_attr('per-hop') == 'true' - - def set_per_hop(self, value): - if value: - return self._set_attr('per-hop', 'true') - else: - return self._del_attr('per-hop') - - def del_per_hop(self): - return self._del_attr('per-hop') - - def add_rule(self, action, condition, value): - rule = Rule(parent=self) - rule['action'] = action - rule['condition'] = condition - rule['value'] = value - - -class Rule(ElementBase): - namespace = 'http://jabber.org/protocol/amp' - name = 'rule' - plugin_attrib = name - plugin_multi_attrib = 'rules' - interfaces = set(['action', 'condition', 'value']) - - -class InvalidRules(ElementBase): - namespace = 'http://jabber.org/protocol/amp' - name = 'invalid-rules' - plugin_attrib = 'invalid_rules' - - -class UnsupportedConditions(ElementBase): - namespace = 'http://jabber.org/protocol/amp' - name = 'unsupported-conditions' - plugin_attrib = 'unsupported_conditions' - - -class UnsupportedActions(ElementBase): - namespace = 'http://jabber.org/protocol/amp' - name = 'unsupported-actions' - plugin_attrib = 'unsupported_actions' - - -class FailedRule(Rule): - namespace = 'http://jabber.org/protocol/amp#errors' - - -class FailedRules(ElementBase): - namespace = 'http://jabber.org/protocol/amp#errors' - name = 'failed-rules' - plugin_attrib = 'failed_rules' - - -class AMPFeature(ElementBase): - namespace = 'http://jabber.org/features/amp' - name = 'amp' - - -register_stanza_plugin(AMP, Rule, iterable=True) -register_stanza_plugin(InvalidRules, Rule, iterable=True) -register_stanza_plugin(UnsupportedConditions, Rule, iterable=True) -register_stanza_plugin(UnsupportedActions, Rule, iterable=True) -register_stanza_plugin(FailedRules, FailedRule, iterable=True) diff --git a/sleekxmpp/plugins/xep_0080/__init__.py b/sleekxmpp/plugins/xep_0080/__init__.py deleted file mode 100644 index cad23d22..00000000 --- a/sleekxmpp/plugins/xep_0080/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Erik Reuterborg Larsson - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0080.stanza import Geoloc -from sleekxmpp.plugins.xep_0080.geoloc import XEP_0080 - - -register_plugin(XEP_0080) diff --git a/sleekxmpp/plugins/xep_0080/geoloc.py b/sleekxmpp/plugins/xep_0080/geoloc.py deleted file mode 100644 index ba594cce..00000000 --- a/sleekxmpp/plugins/xep_0080/geoloc.py +++ /dev/null @@ -1,125 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Erik Reuterborg Larsson - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -import sleekxmpp -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.xep_0080 import stanza, Geoloc - - -log = logging.getLogger(__name__) - - -class XEP_0080(BasePlugin): - - """ - XEP-0080: User Location - """ - - name = 'xep_0080' - description = 'XEP-0080: User Location' - dependencies = set(['xep_0163']) - stanza = stanza - - def plugin_end(self): - self.xmpp['xep_0163'].remove_interest(Geoloc.namespace) - self.xmpp['xep_0030'].del_feature(feature=Geoloc.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('user_location', Geoloc) - - def publish_location(self, **kwargs): - """ - Publish the user's current location. - - Arguments: - accuracy -- Horizontal GPS error in meters. - alt -- Altitude in meters above or below sea level. - area -- A named area such as a campus or neighborhood. - bearing -- GPS bearing (direction in which the entity is - heading to reach its next waypoint), measured in - decimal degrees relative to true north. - building -- A specific building on a street or in an area. - country -- The nation where the user is located. - countrycode -- The ISO 3166 two-letter country code. - datum -- GPS datum. - description -- A natural-language name for or description of - the location. - error -- Horizontal GPS error in arc minutes. Obsoleted by - the accuracy parameter. - floor -- A particular floor in a building. - lat -- Latitude in decimal degrees North. - locality -- A locality within the administrative region, such - as a town or city. - lon -- Longitude in decimal degrees East. - postalcode -- A code used for postal delivery. - region -- An administrative region of the nation, such - as a state or province. - room -- A particular room in a building. - speed -- The speed at which the entity is moving, - in meters per second. - street -- A thoroughfare within the locality, or a crossing - of two thoroughfares. - text -- A catch-all element that captures any other - information about the location. - timestamp -- UTC timestamp specifying the moment when the - reading was taken. - uri -- A URI or URL pointing to information about - the location. - - options -- Optional form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - options = kwargs.get('options', None) - ifrom = kwargs.get('ifrom', None) - block = kwargs.get('block', None) - callback = kwargs.get('callback', None) - timeout = kwargs.get('timeout', None) - for param in ('ifrom', 'block', 'callback', 'timeout', 'options'): - if param in kwargs: - del kwargs[param] - - geoloc = Geoloc() - geoloc.values = kwargs - - return self.xmpp['xep_0163'].publish(geoloc, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing user location information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - geoloc = Geoloc() - return self.xmpp['xep_0163'].publish(geoloc, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0080/stanza.py b/sleekxmpp/plugins/xep_0080/stanza.py deleted file mode 100644 index 8f466516..00000000 --- a/sleekxmpp/plugins/xep_0080/stanza.py +++ /dev/null @@ -1,266 +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. -""" - -from sleekxmpp.xmlstream import ElementBase -from sleekxmpp.plugins import xep_0082 - - -class Geoloc(ElementBase): - - """ - XMPP's stanza allows entities to know the current - geographical or physical location of an entity. (XEP-0080: User Location) - - Example stanzas: - - - - 20 - Italy - 45.44 - Venice - 12.33 - - - Stanza Interface: - accuracy -- Horizontal GPS error in meters. - alt -- Altitude in meters above or below sea level. - area -- A named area such as a campus or neighborhood. - bearing -- GPS bearing (direction in which the entity is - heading to reach its next waypoint), measured in - decimal degrees relative to true north. - building -- A specific building on a street or in an area. - country -- The nation where the user is located. - countrycode -- The ISO 3166 two-letter country code. - datum -- GPS datum. - description -- A natural-language name for or description of - the location. - error -- Horizontal GPS error in arc minutes. Obsoleted by - the accuracy parameter. - floor -- A particular floor in a building. - lat -- Latitude in decimal degrees North. - locality -- A locality within the administrative region, such - as a town or city. - lon -- Longitude in decimal degrees East. - postalcode -- A code used for postal delivery. - region -- An administrative region of the nation, such - as a state or province. - room -- A particular room in a building. - speed -- The speed at which the entity is moving, - in meters per second. - street -- A thoroughfare within the locality, or a crossing - of two thoroughfares. - text -- A catch-all element that captures any other - information about the location. - timestamp -- UTC timestamp specifying the moment when the - reading was taken. - uri -- A URI or URL pointing to information about - the location. - """ - - namespace = 'http://jabber.org/protocol/geoloc' - name = 'geoloc' - interfaces = set(('accuracy', 'alt', 'area', 'bearing', 'building', - 'country', 'countrycode', 'datum', 'dscription', - 'error', 'floor', 'lat', 'locality', 'lon', - 'postalcode', 'region', 'room', 'speed', 'street', - 'text', 'timestamp', 'uri')) - sub_interfaces = interfaces - plugin_attrib = name - - def exception(self, e): - """ - Override exception passback for presence. - """ - pass - - def set_accuracy(self, accuracy): - """ - Set the value of the element. - - Arguments: - accuracy -- Horizontal GPS error in meters - """ - self._set_sub_text('accuracy', text=str(accuracy)) - return self - - def get_accuracy(self): - """ - Return the value of the element as an integer. - """ - p = self._get_sub_text('accuracy') - if not p: - return None - else: - try: - return int(p) - except ValueError: - return None - - def set_alt(self, alt): - """ - Set the value of the element. - - Arguments: - alt -- Altitude in meters above or below sea level - """ - self._set_sub_text('alt', text=str(alt)) - return self - - def get_alt(self): - """ - Return the value of the element as an integer. - """ - p = self._get_sub_text('alt') - if not p: - return None - else: - try: - return int(p) - except ValueError: - return None - - def set_bearing(self, bearing): - """ - Set the value of the element. - - Arguments: - bearing -- GPS bearing (direction in which the entity is heading - to reach its next waypoint), measured in decimal - degrees relative to true north - """ - self._set_sub_text('bearing', text=str(bearing)) - return self - - def get_bearing(self): - """ - Return the value of the element as a float. - """ - p = self._get_sub_text('bearing') - if not p: - return None - else: - try: - return float(p) - except ValueError: - return None - - def set_error(self, error): - """ - Set the value of the element. - - Arguments: - error -- Horizontal GPS error in arc minutes; this - element is deprecated in favor of - """ - self._set_sub_text('error', text=str(error)) - return self - - def get_error(self): - """ - Return the value of the element as a float. - """ - p = self._get_sub_text('error') - if not p: - return None - else: - try: - return float(p) - except ValueError: - return None - - def set_lat(self, lat): - """ - Set the value of the element. - - Arguments: - lat -- Latitude in decimal degrees North - """ - self._set_sub_text('lat', text=str(lat)) - return self - - def get_lat(self): - """ - Return the value of the element as a float. - """ - p = self._get_sub_text('lat') - if not p: - return None - else: - try: - return float(p) - except ValueError: - return None - - def set_lon(self, lon): - """ - Set the value of the element. - - Arguments: - lon -- Longitude in decimal degrees East - """ - self._set_sub_text('lon', text=str(lon)) - return self - - def get_lon(self): - """ - Return the value of the element as a float. - """ - p = self._get_sub_text('lon') - if not p: - return None - else: - try: - return float(p) - except ValueError: - return None - - def set_speed(self, speed): - """ - Set the value of the element. - - Arguments: - speed -- The speed at which the entity is moving, - in meters per second - """ - self._set_sub_text('speed', text=str(speed)) - return self - - def get_speed(self): - """ - Return the value of the element as a float. - """ - p = self._get_sub_text('speed') - if not p: - return None - else: - try: - return float(p) - except ValueError: - return None - - def set_timestamp(self, timestamp): - """ - Set the value of the element. - - Arguments: - timestamp -- UTC timestamp specifying the moment when - the reading was taken - """ - self._set_sub_text('timestamp', text=str(xep_0082.datetime(timestamp))) - return self - - def get_timestamp(self): - """ - Return the value of the element as a DateTime. - """ - p = self._get_sub_text('timestamp') - if not p: - return None - else: - return xep_0082.datetime(p) diff --git a/sleekxmpp/plugins/xep_0082.py b/sleekxmpp/plugins/xep_0082.py deleted file mode 100644 index 26eb68fa..00000000 --- a/sleekxmpp/plugins/xep_0082.py +++ /dev/null @@ -1,228 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import datetime as dt - -from sleekxmpp.plugins import BasePlugin, register_plugin -from sleekxmpp.thirdparty import tzutc, tzoffset, parse_iso - - -# ===================================================================== -# To make it easier for stanzas without direct access to plugin objects -# to use the XEP-0082 utility methods, we will define them as top-level -# functions and then just reference them in the plugin itself. - -def parse(time_str): - """ - Convert a string timestamp into a datetime object. - - Arguments: - time_str -- A formatted timestamp string. - """ - return parse_iso(time_str) - - -def format_date(time_obj): - """ - Return a formatted string version of a date object. - - Format: - YYYY-MM-DD - - Arguments: - time_obj -- A date or datetime object. - """ - if isinstance(time_obj, dt.datetime): - time_obj = time_obj.date() - return time_obj.isoformat() - - -def format_time(time_obj): - """ - Return a formatted string version of a time object. - - format: - hh:mm:ss[.sss][TZD] - - arguments: - time_obj -- A time or datetime object. - """ - if isinstance(time_obj, dt.datetime): - time_obj = time_obj.timetz() - timestamp = time_obj.isoformat() - if time_obj.tzinfo == tzutc(): - timestamp = timestamp[:-6] - return '%sZ' % timestamp - return timestamp - - -def format_datetime(time_obj): - """ - Return a formatted string version of a datetime object. - - Format: - YYYY-MM-DDThh:mm:ss[.sss]TZD - - arguments: - time_obj -- A datetime object. - """ - timestamp = time_obj.isoformat('T') - if time_obj.tzinfo == tzutc(): - timestamp = timestamp[:-6] - return '%sZ' % timestamp - return timestamp - - -def date(year=None, month=None, day=None, obj=False): - """ - Create a date only timestamp for the given instant. - - Unspecified components default to their current counterparts. - - Arguments: - year -- Integer value of the year (4 digits) - month -- Integer value of the month - day -- Integer value of the day of the month. - obj -- If True, return the date object instead - of a formatted string. Defaults to False. - """ - today = dt.datetime.utcnow() - if year is None: - year = today.year - if month is None: - month = today.month - if day is None: - day = today.day - value = dt.date(year, month, day) - if obj: - return value - return format_date(value) - - -def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False): - """ - Create a time only timestamp for the given instant. - - Unspecified components default to their current counterparts. - - Arguments: - hour -- Integer value of the hour. - min -- Integer value of the number of minutes. - sec -- Integer value of the number of seconds. - micro -- Integer value of the number of microseconds. - offset -- Either a positive or negative number of seconds - to offset from UTC to match a desired timezone, - or a tzinfo object. - obj -- If True, return the time object instead - of a formatted string. Defaults to False. - """ - now = dt.datetime.utcnow() - if hour is None: - hour = now.hour - if min is None: - min = now.minute - if sec is None: - sec = now.second - if micro is None: - micro = now.microsecond - if offset is None: - offset = tzutc() - elif not isinstance(offset, dt.tzinfo): - offset = tzoffset(None, offset) - value = dt.time(hour, min, sec, micro, offset) - if obj: - return value - return format_time(value) - - -def datetime(year=None, month=None, day=None, hour=None, - min=None, sec=None, micro=None, offset=None, - separators=True, obj=False): - """ - Create a datetime timestamp for the given instant. - - Unspecified components default to their current counterparts. - - Arguments: - year -- Integer value of the year (4 digits) - month -- Integer value of the month - day -- Integer value of the day of the month. - hour -- Integer value of the hour. - min -- Integer value of the number of minutes. - sec -- Integer value of the number of seconds. - micro -- Integer value of the number of microseconds. - offset -- Either a positive or negative number of seconds - to offset from UTC to match a desired timezone, - or a tzinfo object. - obj -- If True, return the datetime object instead - of a formatted string. Defaults to False. - """ - now = dt.datetime.utcnow() - if year is None: - year = now.year - if month is None: - month = now.month - if day is None: - day = now.day - if hour is None: - hour = now.hour - if min is None: - min = now.minute - if sec is None: - sec = now.second - if micro is None: - micro = now.microsecond - if offset is None: - offset = tzutc() - elif not isinstance(offset, dt.tzinfo): - offset = tzoffset(None, offset) - - value = dt.datetime(year, month, day, hour, - min, sec, micro, offset) - if obj: - return value - return format_datetime(value) - - -class XEP_0082(BasePlugin): - - """ - XEP-0082: XMPP Date and Time Profiles - - XMPP uses a subset of the formats allowed by ISO 8601 as a matter of - pragmatism based on the relatively few formats historically used by - the XMPP. - - Also see . - - Methods: - date -- Create a time stamp using the Date profile. - datetime -- Create a time stamp using the DateTime profile. - time -- Create a time stamp using the Time profile. - format_date -- Format an existing date object. - format_datetime -- Format an existing datetime object. - format_time -- Format an existing time object. - parse -- Convert a time string into a Python datetime object. - """ - - name = 'xep_0082' - description = 'XEP-0082: XMPP Date and Time Profiles' - dependencies = set() - - def plugin_init(self): - """Start the XEP-0082 plugin.""" - self.date = date - self.datetime = datetime - self.time = time - self.format_date = format_date - self.format_datetime = format_datetime - self.format_time = format_time - self.parse = parse - - -register_plugin(XEP_0082) diff --git a/sleekxmpp/plugins/xep_0084/__init__.py b/sleekxmpp/plugins/xep_0084/__init__.py deleted file mode 100644 index 6b87573f..00000000 --- a/sleekxmpp/plugins/xep_0084/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0084 import stanza -from sleekxmpp.plugins.xep_0084.stanza import Data, MetaData -from sleekxmpp.plugins.xep_0084.avatar import XEP_0084 - - -register_plugin(XEP_0084) diff --git a/sleekxmpp/plugins/xep_0084/avatar.py b/sleekxmpp/plugins/xep_0084/avatar.py deleted file mode 100644 index 677a888d..00000000 --- a/sleekxmpp/plugins/xep_0084/avatar.py +++ /dev/null @@ -1,111 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import hashlib -import logging - -from sleekxmpp import Iq -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.plugins.xep_0084 import stanza, Data, MetaData - - -log = logging.getLogger(__name__) - - -class XEP_0084(BasePlugin): - - name = 'xep_0084' - description = 'XEP-0084: User Avatar' - dependencies = set(['xep_0163', 'xep_0060']) - stanza = stanza - - def plugin_init(self): - pubsub_stanza = self.xmpp['xep_0060'].stanza - register_stanza_plugin(pubsub_stanza.Item, Data) - register_stanza_plugin(pubsub_stanza.EventItem, Data) - - self.xmpp['xep_0060'].map_node_event(Data.namespace, 'avatar_data') - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=MetaData.namespace) - self.xmpp['xep_0163'].remove_interest(MetaData.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('avatar_metadata', MetaData) - - def generate_id(self, data): - return hashlib.sha1(data).hexdigest() - - def retrieve_avatar(self, jid, id, url=None, ifrom=None, block=True, - callback=None, timeout=None): - return self.xmpp['xep_0060'].get_item(jid, Data.namespace, id, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def publish_avatar(self, data, ifrom=None, block=True, callback=None, - timeout=None): - payload = Data() - payload['value'] = data - return self.xmpp['xep_0163'].publish(payload, - id=self.generate_id(data), - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def publish_avatar_metadata(self, items=None, pointers=None, - ifrom=None, block=True, - callback=None, timeout=None): - metadata = MetaData() - if items is None: - items = [] - if not isinstance(items, (list, set)): - items = [items] - for info in items: - metadata.add_info(info['id'], info['type'], info['bytes'], - height=info.get('height', ''), - width=info.get('width', ''), - url=info.get('url', '')) - - if pointers is not None: - for pointer in pointers: - metadata.add_pointer(pointer) - - return self.xmpp['xep_0163'].publish(metadata, - id=info['id'], - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing avatar metadata information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - metadata = MetaData() - return self.xmpp['xep_0163'].publish(metadata, - node=MetaData.namespace, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0084/stanza.py b/sleekxmpp/plugins/xep_0084/stanza.py deleted file mode 100644 index 22f11b72..00000000 --- a/sleekxmpp/plugins/xep_0084/stanza.py +++ /dev/null @@ -1,78 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from base64 import b64encode, b64decode - -from sleekxmpp.util import bytes -from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin - - -class Data(ElementBase): - name = 'data' - namespace = 'urn:xmpp:avatar:data' - plugin_attrib = 'avatar_data' - interfaces = set(['value']) - - def get_value(self): - if self.xml.text: - return b64decode(bytes(self.xml.text)) - return '' - - def set_value(self, value): - if value: - self.xml.text = b64encode(bytes(value)) - else: - self.xml.text = '' - - def del_value(self): - self.xml.text = '' - - -class MetaData(ElementBase): - name = 'metadata' - namespace = 'urn:xmpp:avatar:metadata' - plugin_attrib = 'avatar_metadata' - interfaces = set() - - def add_info(self, id, itype, ibytes, height=None, width=None, url=None): - info = Info() - info.values = {'id': id, - 'type': itype, - 'bytes': '%s' % ibytes, - 'height': height, - 'width': width, - 'url': url} - self.append(info) - - def add_pointer(self, xml): - if not isinstance(xml, Pointer): - pointer = Pointer() - pointer.append(xml) - self.append(pointer) - else: - self.append(xml) - - -class Info(ElementBase): - name = 'info' - namespace = 'urn:xmpp:avatar:metadata' - plugin_attrib = 'info' - plugin_multi_attrib = 'items' - interfaces = set(['bytes', 'height', 'id', 'type', 'url', 'width']) - - -class Pointer(ElementBase): - name = 'pointer' - namespace = 'urn:xmpp:avatar:metadata' - plugin_attrib = 'pointer' - plugin_multi_attrib = 'pointers' - interfaces = set() - - -register_stanza_plugin(MetaData, Info, iterable=True) -register_stanza_plugin(MetaData, Pointer, iterable=True) diff --git a/sleekxmpp/plugins/xep_0085/__init__.py b/sleekxmpp/plugins/xep_0085/__init__.py deleted file mode 100644 index 445d5059..00000000 --- a/sleekxmpp/plugins/xep_0085/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permissio -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0085.stanza import ChatState -from sleekxmpp.plugins.xep_0085.chat_states import XEP_0085 - - -register_plugin(XEP_0085) - - -# Retain some backwards compatibility -xep_0085 = XEP_0085 diff --git a/sleekxmpp/plugins/xep_0085/chat_states.py b/sleekxmpp/plugins/xep_0085/chat_states.py deleted file mode 100644 index 17f82afd..00000000 --- a/sleekxmpp/plugins/xep_0085/chat_states.py +++ /dev/null @@ -1,56 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permissio -""" - -import logging - -import sleekxmpp -from sleekxmpp.stanza import Message -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, ET -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0085 import stanza, ChatState - - -log = logging.getLogger(__name__) - - -class XEP_0085(BasePlugin): - - """ - XEP-0085 Chat State Notifications - """ - - name = 'xep_0085' - description = 'XEP-0085: Chat State Notifications' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - self.xmpp.register_handler( - Callback('Chat State', - StanzaPath('message/chat_state'), - self._handle_chat_state)) - - register_stanza_plugin(Message, stanza.Active) - register_stanza_plugin(Message, stanza.Composing) - register_stanza_plugin(Message, stanza.Gone) - register_stanza_plugin(Message, stanza.Inactive) - register_stanza_plugin(Message, stanza.Paused) - - def plugin_end(self): - self.xmpp.remove_handler('Chat State') - - def session_bind(self, jid): - self.xmpp.plugin['xep_0030'].add_feature(ChatState.namespace) - - def _handle_chat_state(self, msg): - state = msg['chat_state'] - log.debug("Chat State: %s, %s", state, msg['from'].jid) - self.xmpp.event('chatstate', msg) - self.xmpp.event('chatstate_%s' % state, msg) diff --git a/sleekxmpp/plugins/xep_0085/stanza.py b/sleekxmpp/plugins/xep_0085/stanza.py deleted file mode 100644 index c2cafb19..00000000 --- a/sleekxmpp/plugins/xep_0085/stanza.py +++ /dev/null @@ -1,94 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permissio -""" - -import sleekxmpp -from sleekxmpp.xmlstream import ElementBase, ET - - -class ChatState(ElementBase): - - """ - Example chat state stanzas: - - - - - - - - - Stanza Interfaces: - chat_state - - Attributes: - states - - Methods: - get_chat_state - set_chat_state - del_chat_state - """ - - name = '' - namespace = 'http://jabber.org/protocol/chatstates' - plugin_attrib = 'chat_state' - interfaces = set(('chat_state',)) - sub_interfaces = interfaces - is_extension = True - - states = set(('active', 'composing', 'gone', 'inactive', 'paused')) - - def setup(self, xml=None): - self.xml = ET.Element('') - return True - - def get_chat_state(self): - parent = self.parent() - for state in self.states: - state_xml = parent.find('{%s}%s' % (self.namespace, state)) - if state_xml is not None: - self.xml = state_xml - return state - return '' - - def set_chat_state(self, state): - self.del_chat_state() - parent = self.parent() - if state in self.states: - self.xml = ET.Element('{%s}%s' % (self.namespace, state)) - parent.append(self.xml) - elif state not in [None, '']: - raise ValueError('Invalid chat state') - - def del_chat_state(self): - parent = self.parent() - for state in self.states: - state_xml = parent.find('{%s}%s' % (self.namespace, state)) - if state_xml is not None: - self.xml = ET.Element('') - parent.xml.remove(state_xml) - - -class Active(ChatState): - name = 'active' - - -class Composing(ChatState): - name = 'composing' - - -class Gone(ChatState): - name = 'gone' - - -class Inactive(ChatState): - name = 'inactive' - - -class Paused(ChatState): - name = 'paused' diff --git a/sleekxmpp/plugins/xep_0086/__init__.py b/sleekxmpp/plugins/xep_0086/__init__.py deleted file mode 100644 index 94600e85..00000000 --- a/sleekxmpp/plugins/xep_0086/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0086.stanza import LegacyError -from sleekxmpp.plugins.xep_0086.legacy_error import XEP_0086 - - -register_plugin(XEP_0086) - - -# Retain some backwards compatibility -xep_0086 = XEP_0086 diff --git a/sleekxmpp/plugins/xep_0086/legacy_error.py b/sleekxmpp/plugins/xep_0086/legacy_error.py deleted file mode 100644 index f7d0ac9c..00000000 --- a/sleekxmpp/plugins/xep_0086/legacy_error.py +++ /dev/null @@ -1,46 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.stanza import Error -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0086 import stanza, LegacyError - - -class XEP_0086(BasePlugin): - - """ - XEP-0086: Error Condition Mappings - - Older XMPP implementations used code based error messages, similar - to HTTP response codes. Since then, error condition elements have - been introduced. XEP-0086 provides a mapping between the new - condition elements and a combination of error types and the older - response codes. - - Also see . - - Configuration Values: - override -- Indicates if applying legacy error codes should - be done automatically. Defaults to True. - If False, then inserting legacy error codes can - be done using: - iq['error']['legacy']['condition'] = ... - """ - - name = 'xep_0086' - description = 'XEP-0086: Error Condition Mappings' - dependencies = set() - stanza = stanza - default_config = { - 'override': True - } - - def plugin_init(self): - register_stanza_plugin(Error, LegacyError, - overrides=self.override) diff --git a/sleekxmpp/plugins/xep_0086/stanza.py b/sleekxmpp/plugins/xep_0086/stanza.py deleted file mode 100644 index d4909806..00000000 --- a/sleekxmpp/plugins/xep_0086/stanza.py +++ /dev/null @@ -1,91 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.stanza import Error -from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin - - -class LegacyError(ElementBase): - - """ - Older XMPP implementations used code based error messages, similar - to HTTP response codes. Since then, error condition elements have - been introduced. XEP-0086 provides a mapping between the new - condition elements and a combination of error types and the older - response codes. - - Also see . - - Example legacy error stanzas: - - - - - - - - - Attributes: - error_map -- A map of error conditions to error types and - code values. - Methods: - setup -- Overrides ElementBase.setup - set_condition -- Remap the type and code interfaces when a - condition is set. - """ - - name = 'legacy' - namespace = Error.namespace - plugin_attrib = name - interfaces = set(('condition',)) - overrides = ['set_condition'] - - error_map = {'bad-request': ('modify', '400'), - 'conflict': ('cancel', '409'), - 'feature-not-implemented': ('cancel', '501'), - 'forbidden': ('auth', '403'), - 'gone': ('modify', '302'), - 'internal-server-error': ('wait', '500'), - 'item-not-found': ('cancel', '404'), - 'jid-malformed': ('modify', '400'), - 'not-acceptable': ('modify', '406'), - 'not-allowed': ('cancel', '405'), - 'not-authorized': ('auth', '401'), - 'payment-required': ('auth', '402'), - 'recipient-unavailable': ('wait', '404'), - 'redirect': ('modify', '302'), - 'registration-required': ('auth', '407'), - 'remote-server-not-found': ('cancel', '404'), - 'remote-server-timeout': ('wait', '504'), - 'resource-constraint': ('wait', '500'), - 'service-unavailable': ('cancel', '503'), - 'subscription-required': ('auth', '407'), - 'undefined-condition': (None, '500'), - 'unexpected-request': ('wait', '400')} - - def setup(self, xml): - """Don't create XML for the plugin.""" - self.xml = ET.Element('') - - def set_condition(self, value): - """ - Set the error type and code based on the given error - condition value. - - Arguments: - value -- The new error condition. - """ - self.parent().set_condition(value) - - error_data = self.error_map.get(value, None) - if error_data is not None: - if error_data[0] is not None: - self.parent()['type'] = error_data[0] - self.parent()['code'] = error_data[1] diff --git a/sleekxmpp/plugins/xep_0091/__init__.py b/sleekxmpp/plugins/xep_0091/__init__.py deleted file mode 100644 index 04f21ef5..00000000 --- a/sleekxmpp/plugins/xep_0091/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0091 import stanza -from sleekxmpp.plugins.xep_0091.stanza import LegacyDelay -from sleekxmpp.plugins.xep_0091.legacy_delay import XEP_0091 - - -register_plugin(XEP_0091) diff --git a/sleekxmpp/plugins/xep_0091/legacy_delay.py b/sleekxmpp/plugins/xep_0091/legacy_delay.py deleted file mode 100644 index 7323d468..00000000 --- a/sleekxmpp/plugins/xep_0091/legacy_delay.py +++ /dev/null @@ -1,29 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - - -from sleekxmpp.stanza import Message, Presence -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0091 import stanza - - -class XEP_0091(BasePlugin): - - """ - XEP-0091: Legacy Delayed Delivery - """ - - name = 'xep_0091' - description = 'XEP-0091: Legacy Delayed Delivery' - dependencies = set() - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Message, stanza.LegacyDelay) - register_stanza_plugin(Presence, stanza.LegacyDelay) diff --git a/sleekxmpp/plugins/xep_0091/stanza.py b/sleekxmpp/plugins/xep_0091/stanza.py deleted file mode 100644 index 17e55764..00000000 --- a/sleekxmpp/plugins/xep_0091/stanza.py +++ /dev/null @@ -1,47 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import datetime as dt - -from sleekxmpp.jid import JID -from sleekxmpp.xmlstream import ElementBase -from sleekxmpp.plugins import xep_0082 - - -class LegacyDelay(ElementBase): - - name = 'x' - namespace = 'jabber:x:delay' - plugin_attrib = 'legacy_delay' - interfaces = set(('from', 'stamp', 'text')) - - def get_from(self): - from_ = self._get_attr('from') - return JID(from_) if from_ else None - - def set_from(self, value): - self._set_attr('from', str(value)) - - def get_stamp(self): - timestamp = self._get_attr('stamp') - return xep_0082.parse('%sZ' % timestamp) if timestamp else None - - def set_stamp(self, value): - if isinstance(value, dt.datetime): - value = value.astimezone(xep_0082.tzutc) - value = xep_0082.format_datetime(value) - self._set_attr('stamp', value[0:19].replace('-', '')) - - def get_text(self): - return self.xml.text - - def set_text(self, value): - self.xml.text = value - - def del_text(self): - self.xml.text = '' diff --git a/sleekxmpp/plugins/xep_0092/__init__.py b/sleekxmpp/plugins/xep_0092/__init__.py deleted file mode 100644 index 293eaae6..00000000 --- a/sleekxmpp/plugins/xep_0092/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0092 import stanza -from sleekxmpp.plugins.xep_0092.stanza import Version -from sleekxmpp.plugins.xep_0092.version import XEP_0092 - - -register_plugin(XEP_0092) - - -# Retain some backwards compatibility -xep_0092 = XEP_0092 diff --git a/sleekxmpp/plugins/xep_0092/stanza.py b/sleekxmpp/plugins/xep_0092/stanza.py deleted file mode 100644 index 77654e37..00000000 --- a/sleekxmpp/plugins/xep_0092/stanza.py +++ /dev/null @@ -1,42 +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. -""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class Version(ElementBase): - - """ - XMPP allows for an agent to advertise the name and version of the - underlying software libraries, as well as the operating system - that the agent is running on. - - Example version stanzas: - - - - - - - SleekXMPP - 1.0 - Linux - - - - Stanza Interface: - name -- The human readable name of the software. - version -- The specific version of the software. - os -- The name of the operating system running the program. - """ - - name = 'query' - namespace = 'jabber:iq:version' - plugin_attrib = 'software_version' - interfaces = set(('name', 'version', 'os')) - sub_interfaces = interfaces diff --git a/sleekxmpp/plugins/xep_0092/version.py b/sleekxmpp/plugins/xep_0092/version.py deleted file mode 100644 index b16ad516..00000000 --- a/sleekxmpp/plugins/xep_0092/version.py +++ /dev/null @@ -1,85 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -import sleekxmpp -from sleekxmpp import Iq -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0092 import Version, stanza - - -log = logging.getLogger(__name__) - - -class XEP_0092(BasePlugin): - - """ - XEP-0092: Software Version - """ - - name = 'xep_0092' - description = 'XEP-0092: Software Version' - dependencies = set(['xep_0030']) - stanza = stanza - default_config = { - 'software_name': 'SleekXMPP', - 'version': sleekxmpp.__version__, - 'os': '' - } - - def plugin_init(self): - """ - Start the XEP-0092 plugin. - """ - if 'name' in self.config: - self.software_name = self.config['name'] - - self.xmpp.register_handler( - Callback('Software Version', - StanzaPath('iq@type=get/software_version'), - self._handle_version)) - - register_stanza_plugin(Iq, Version) - - def plugin_end(self): - self.xmpp.remove_handler('Software Version') - self.xmpp['xep_0030'].del_feature(feature='jabber:iq:version') - - def session_bind(self, jid): - self.xmpp.plugin['xep_0030'].add_feature('jabber:iq:version') - - def _handle_version(self, iq): - """ - Respond to a software version query. - - Arguments: - iq -- The Iq stanza containing the software version query. - """ - iq.reply() - iq['software_version']['name'] = self.software_name - iq['software_version']['version'] = self.version - iq['software_version']['os'] = self.os - iq.send() - - def get_version(self, jid, ifrom=None, block=True, timeout=None, callback=None): - """ - Retrieve the software version of a remote agent. - - Arguments: - jid -- The JID of the entity to query. - """ - iq = self.xmpp.Iq() - iq['to'] = jid - iq['from'] = ifrom - iq['type'] = 'get' - iq['query'] = Version.namespace - return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/xep_0095/__init__.py b/sleekxmpp/plugins/xep_0095/__init__.py deleted file mode 100644 index 4465ef5c..00000000 --- a/sleekxmpp/plugins/xep_0095/__init__.py +++ /dev/null @@ -1,16 +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 - -from sleekxmpp.plugins.xep_0095 import stanza -from sleekxmpp.plugins.xep_0095.stanza import SI -from sleekxmpp.plugins.xep_0095.stream_initiation import XEP_0095 - - -register_plugin(XEP_0095) diff --git a/sleekxmpp/plugins/xep_0095/stanza.py b/sleekxmpp/plugins/xep_0095/stanza.py deleted file mode 100644 index 34999a11..00000000 --- a/sleekxmpp/plugins/xep_0095/stanza.py +++ /dev/null @@ -1,25 +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 - - -class SI(ElementBase): - name = 'si' - namespace = 'http://jabber.org/protocol/si' - plugin_attrib = 'si' - interfaces = set(['id', 'mime_type', 'profile']) - - def get_mime_type(self): - return self._get_attr('mime-type', 'application/octet-stream') - - def set_mime_type(self, value): - self._set_attr('mime-type', value) - - def del_mime_type(self): - self._del_attr('mime-type') diff --git a/sleekxmpp/plugins/xep_0095/stream_initiation.py b/sleekxmpp/plugins/xep_0095/stream_initiation.py deleted file mode 100644 index 927248a5..00000000 --- a/sleekxmpp/plugins/xep_0095/stream_initiation.py +++ /dev/null @@ -1,214 +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 -import threading - -from uuid import uuid4 - -from sleekxmpp import Iq, Message -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.plugins.xep_0095 import stanza, SI - - -log = logging.getLogger(__name__) - - -SOCKS5 = 'http://jabber.org/protocol/bytestreams' -IBB = 'http://jabber.org/protocol/ibb' - - -class XEP_0095(BasePlugin): - - name = 'xep_0095' - description = 'XEP-0095: Stream Initiation' - dependencies = set(['xep_0020', 'xep_0030', 'xep_0047', 'xep_0065']) - stanza = stanza - - def plugin_init(self): - self._profiles = {} - self._methods = {} - self._methods_order = [] - self._pending_lock = threading.Lock() - self._pending= {} - - self.register_method(SOCKS5, 'xep_0065', 100) - self.register_method(IBB, 'xep_0047', 50) - - register_stanza_plugin(Iq, SI) - register_stanza_plugin(SI, self.xmpp['xep_0020'].stanza.FeatureNegotiation) - - self.xmpp.register_handler( - Callback('SI Request', - StanzaPath('iq@type=set/si'), - self._handle_request)) - - self.api.register(self._add_pending, 'add_pending', default=True) - self.api.register(self._get_pending, 'get_pending', default=True) - self.api.register(self._del_pending, 'del_pending', default=True) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(SI.namespace) - - def plugin_end(self): - self.xmpp.remove_handler('SI Request') - self.xmpp['xep_0030'].del_feature(feature=SI.namespace) - - def register_profile(self, profile_name, plugin): - self._profiles[profile_name] = plugin - - def unregister_profile(self, profile_name): - try: - del self._profiles[profile_name] - except KeyError: - pass - - def register_method(self, method, plugin_name, order=50): - self._methods[method] = (plugin_name, order) - self._methods_order.append((order, method, plugin_name)) - self._methods_order.sort() - - def unregister_method(self, method): - if method in self._methods: - plugin_name, order = self._methods[method] - del self._methods[method] - self._methods_order.remove((order, method, plugin_name)) - self._methods_order.sort() - - def _handle_request(self, iq): - profile = iq['si']['profile'] - sid = iq['si']['id'] - - if not sid: - raise XMPPError(etype='modify', condition='bad-request') - if profile not in self._profiles: - raise XMPPError( - etype='modify', - condition='bad-request', - extension='bad-profile', - extension_ns=SI.namespace) - - neg = iq['si']['feature_neg']['form']['fields'] - options = neg['stream-method']['options'] or [] - methods = [] - for opt in options: - methods.append(opt['value']) - for method in methods: - if method in self._methods: - supported = True - break - else: - raise XMPPError('bad-request', - extension='no-valid-streams', - extension_ns=SI.namespace) - - selected_method = None - log.debug('Available: %s', methods) - for order, method, plugin in self._methods_order: - log.debug('Testing: %s', method) - if method in methods: - selected_method = method - break - - receiver = iq['to'] - sender = iq['from'] - - self.api['add_pending'](receiver, sid, sender, { - 'response_id': iq['id'], - 'method': selected_method, - 'profile': profile - }) - self.xmpp.event('si_request', iq) - - def offer(self, jid, sid=None, mime_type=None, profile=None, - methods=None, payload=None, ifrom=None, - **iqargs): - if sid is None: - sid = uuid4().hex - if methods is None: - methods = list(self._methods.keys()) - if not isinstance(methods, (list, tuple, set)): - methods = [methods] - - si = self.xmpp.Iq() - si['to'] = jid - si['from'] = ifrom - si['type'] = 'set' - si['si']['id'] = sid - si['si']['mime_type'] = mime_type - si['si']['profile'] = profile - if not isinstance(payload, (list, tuple, set)): - payload = [payload] - for item in payload: - si['si'].append(item) - si['si']['feature_neg']['form'].add_field( - var='stream-method', - ftype='list-single', - options=methods) - return si.send(**iqargs) - - def accept(self, jid, sid, payload=None, ifrom=None, stream_handler=None): - stream = self.api['get_pending'](ifrom, sid, jid) - iq = self.xmpp.Iq() - iq['id'] = stream['response_id'] - iq['to'] = jid - iq['from'] = ifrom - iq['type'] = 'result' - if payload: - iq['si'].append(payload) - iq['si']['feature_neg']['form']['type'] = 'submit' - iq['si']['feature_neg']['form'].add_field( - var='stream-method', - ftype='list-single', - value=stream['method']) - - if ifrom is None: - ifrom = self.xmpp.boundjid - - method_plugin = self._methods[stream['method']][0] - self.xmpp[method_plugin].api['preauthorize_sid'](ifrom, sid, jid) - - self.api['del_pending'](ifrom, sid, jid) - - if stream_handler: - self.xmpp.add_event_handler('stream:%s:%s' % (sid, jid), - stream_handler, - threaded=True, - disposable=True) - return iq.send() - - def decline(self, jid, sid, ifrom=None): - stream = self.api['get_pending'](ifrom, sid, jid) - if not stream: - return - iq = self.xmpp.Iq() - iq['id'] = stream['response_id'] - iq['to'] = jid - iq['from'] = ifrom - iq['type'] = 'error' - iq['error']['condition'] = 'forbidden' - iq['error']['text'] = 'Offer declined' - self.api['del_pending'](ifrom, sid, jid) - return iq.send() - - def _add_pending(self, jid, node, ifrom, data): - with self._pending_lock: - self._pending[(jid, node, ifrom)] = data - - def _get_pending(self, jid, node, ifrom, data): - with self._pending_lock: - return self._pending.get((jid, node, ifrom), None) - - def _del_pending(self, jid, node, ifrom, data): - with self._pending_lock: - if (jid, node, ifrom) in self._pending: - del self._pending[(jid, node, ifrom)] diff --git a/sleekxmpp/plugins/xep_0096/__init__.py b/sleekxmpp/plugins/xep_0096/__init__.py deleted file mode 100644 index 5f836169..00000000 --- a/sleekxmpp/plugins/xep_0096/__init__.py +++ /dev/null @@ -1,16 +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 - -from sleekxmpp.plugins.xep_0096 import stanza -from sleekxmpp.plugins.xep_0096.stanza import File -from sleekxmpp.plugins.xep_0096.file_transfer import XEP_0096 - - -register_plugin(XEP_0096) diff --git a/sleekxmpp/plugins/xep_0096/file_transfer.py b/sleekxmpp/plugins/xep_0096/file_transfer.py deleted file mode 100644 index 6873c7f5..00000000 --- a/sleekxmpp/plugins/xep_0096/file_transfer.py +++ /dev/null @@ -1,58 +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 import Iq, Message -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.plugins.xep_0096 import stanza, File - - -log = logging.getLogger(__name__) - - -class XEP_0096(BasePlugin): - - name = 'xep_0096' - description = 'XEP-0096: SI File Transfer' - dependencies = set(['xep_0095']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(self.xmpp['xep_0095'].stanza.SI, File) - - self.xmpp['xep_0095'].register_profile(File.namespace, self) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(File.namespace) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=File.namespace) - self.xmpp['xep_0095'].unregister_profile(File.namespace, self) - - def request_file_transfer(self, jid, sid=None, name=None, size=None, - desc=None, hash=None, date=None, - allow_ranged=False, mime_type=None, - **iqargs): - data = File() - data['name'] = name - data['size'] = size - data['date'] = date - data['desc'] = desc - if allow_ranged: - data.enable('range') - - return self.xmpp['xep_0095'].offer(jid, - sid=sid, - mime_type=mime_type, - profile=File.namespace, - payload=data, - **iqargs) diff --git a/sleekxmpp/plugins/xep_0096/stanza.py b/sleekxmpp/plugins/xep_0096/stanza.py deleted file mode 100644 index 65eb5bc5..00000000 --- a/sleekxmpp/plugins/xep_0096/stanza.py +++ /dev/null @@ -1,48 +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 datetime as dt - -from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin -from sleekxmpp.plugins import xep_0082 - - -class File(ElementBase): - name = 'file' - namespace = 'http://jabber.org/protocol/si/profile/file-transfer' - plugin_attrib = 'file' - interfaces = set(['name', 'size', 'date', 'hash', 'desc']) - sub_interfaces = set(['desc']) - - def set_size(self, value): - self._set_attr('size', str(value)) - - def get_date(self): - timestamp = self._get_attr('date') - return xep_0082.parse(timestamp) - - def set_date(self, value): - if isinstance(value, dt.datetime): - value = xep_0082.format_datetime(value) - self._set_attr('date', value) - - -class Range(ElementBase): - name = 'range' - namespace = 'http://jabber.org/protocol/si/profile/file-transfer' - plugin_attrib = 'range' - interfaces = set(['length', 'offset']) - - def set_length(self, value): - self._set_attr('length', str(value)) - - def set_offset(self, value): - self._set_attr('offset', str(value)) - - -register_stanza_plugin(File, Range) diff --git a/sleekxmpp/plugins/xep_0106.py b/sleekxmpp/plugins/xep_0106.py deleted file mode 100644 index 1859a77b..00000000 --- a/sleekxmpp/plugins/xep_0106.py +++ /dev/null @@ -1,26 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - - -from sleekxmpp.plugins import BasePlugin, register_plugin - - -class XEP_0106(BasePlugin): - - name = 'xep_0106' - description = 'XEP-0106: JID Escaping' - dependencies = set(['xep_0030']) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(feature='jid\\20escaping') - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature='jid\\20escaping') - - -register_plugin(XEP_0106) diff --git a/sleekxmpp/plugins/xep_0107/__init__.py b/sleekxmpp/plugins/xep_0107/__init__.py deleted file mode 100644 index 04302df8..00000000 --- a/sleekxmpp/plugins/xep_0107/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0107 import stanza -from sleekxmpp.plugins.xep_0107.stanza import UserMood -from sleekxmpp.plugins.xep_0107.user_mood import XEP_0107 - - -register_plugin(XEP_0107) diff --git a/sleekxmpp/plugins/xep_0107/stanza.py b/sleekxmpp/plugins/xep_0107/stanza.py deleted file mode 100644 index 2c5814ea..00000000 --- a/sleekxmpp/plugins/xep_0107/stanza.py +++ /dev/null @@ -1,55 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class UserMood(ElementBase): - - name = 'mood' - namespace = 'http://jabber.org/protocol/mood' - plugin_attrib = 'mood' - interfaces = set(['value', 'text']) - sub_interfaces = set(['text']) - moods = set(['afraid', 'amazed', 'amorous', 'angry', 'annoyed', 'anxious', - 'aroused', 'ashamed', 'bored', 'brave', 'calm', 'cautious', - 'cold', 'confident', 'confused', 'contemplative', 'contented', - 'cranky', 'crazy', 'creative', 'curious', 'dejected', - 'depressed', 'disappointed', 'disgusted', 'dismayed', - 'distracted', 'embarrassed', 'envious', 'excited', - 'flirtatious', 'frustrated', 'grateful', 'grieving', 'grumpy', - 'guilty', 'happy', 'hopeful', 'hot', 'humbled', 'humiliated', - 'hungry', 'hurt', 'impressed', 'in_awe', 'in_love', - 'indignant', 'interested', 'intoxicated', 'invincible', - 'jealous', 'lonely', 'lost', 'lucky', 'mean', 'moody', - 'nervous', 'neutral', 'offended', 'outraged', 'playful', - 'proud', 'relaxed', 'relieved', 'remorseful', 'restless', - 'sad', 'sarcastic', 'satisfied', 'serious', 'shocked', - 'shy', 'sick', 'sleepy', 'spontaneous', 'stressed', 'strong', - 'surprised', 'thankful', 'thirsty', 'tired', 'undefined', - 'weak', 'worried']) - - def set_value(self, value): - self.del_value() - if value in self.moods: - self._set_sub_text(value, '', keep=True) - else: - raise ValueError('Unknown mood value') - - def get_value(self): - for child in self.xml: - if child.tag.startswith('{%s}' % self.namespace): - elem_name = child.tag.split('}')[-1] - if elem_name in self.moods: - return elem_name - return '' - - def del_value(self): - curr_value = self.get_value() - if curr_value: - self._set_sub_text(curr_value, '', keep=False) diff --git a/sleekxmpp/plugins/xep_0107/user_mood.py b/sleekxmpp/plugins/xep_0107/user_mood.py deleted file mode 100644 index 2d2f3551..00000000 --- a/sleekxmpp/plugins/xep_0107/user_mood.py +++ /dev/null @@ -1,93 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import Message -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0107 import stanza, UserMood - - -log = logging.getLogger(__name__) - - -class XEP_0107(BasePlugin): - - """ - XEP-0107: User Mood - """ - - name = 'xep_0107' - description = 'XEP-0107: User Mood' - dependencies = set(['xep_0163']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Message, UserMood) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=UserMood.namespace) - self.xmpp['xep_0163'].remove_interest(UserMood.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('user_mood', UserMood) - - def publish_mood(self, value=None, text=None, options=None, - ifrom=None, block=True, callback=None, timeout=None): - """ - Publish the user's current mood. - - Arguments: - value -- The name of the mood to publish. - text -- Optional natural-language description or reason - for the mood. - options -- Optional form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - mood = UserMood() - mood['value'] = value - mood['text'] = text - return self.xmpp['xep_0163'].publish(mood, - node=UserMood.namespace, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing user mood information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - mood = UserMood() - return self.xmpp['xep_0163'].publish(mood, - node=UserMood.namespace, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0108/__init__.py b/sleekxmpp/plugins/xep_0108/__init__.py deleted file mode 100644 index 34d45113..00000000 --- a/sleekxmpp/plugins/xep_0108/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0108 import stanza -from sleekxmpp.plugins.xep_0108.stanza import UserActivity -from sleekxmpp.plugins.xep_0108.user_activity import XEP_0108 - - -register_plugin(XEP_0108) diff --git a/sleekxmpp/plugins/xep_0108/stanza.py b/sleekxmpp/plugins/xep_0108/stanza.py deleted file mode 100644 index 4650160a..00000000 --- a/sleekxmpp/plugins/xep_0108/stanza.py +++ /dev/null @@ -1,83 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class UserActivity(ElementBase): - - name = 'activity' - namespace = 'http://jabber.org/protocol/activity' - plugin_attrib = 'activity' - interfaces = set(['value', 'text']) - sub_interfaces = set(['text']) - general = set(['doing_chores', 'drinking', 'eating', 'exercising', - 'grooming', 'having_appointment', 'inactive', 'relaxing', - 'talking', 'traveling', 'undefined', 'working']) - specific = set(['at_the_spa', 'brushing_teeth', 'buying_groceries', - 'cleaning', 'coding', 'commuting', 'cooking', 'cycling', - 'dancing', 'day_off', 'doing_maintenance', - 'doing_the_dishes', 'doing_the_laundry', 'driving', - 'fishing', 'gaming', 'gardening', 'getting_a_haircut', - 'going_out', 'hanging_out', 'having_a_beer', - 'having_a_snack', 'having_breakfast', 'having_coffee', - 'having_dinner', 'having_lunch', 'having_tea', 'hiding', - 'hiking', 'in_a_car', 'in_a_meeting', 'in_real_life', - 'jogging', 'on_a_bus', 'on_a_plane', 'on_a_train', - 'on_a_trip', 'on_the_phone', 'on_vacation', - 'on_video_phone', 'other', 'partying', 'playing_sports', - 'praying', 'reading', 'rehearsing', 'running', - 'running_an_errand', 'scheduled_holiday', 'shaving', - 'shopping', 'skiing', 'sleeping', 'smoking', - 'socializing', 'studying', 'sunbathing', 'swimming', - 'taking_a_bath', 'taking_a_shower', 'thinking', - 'walking', 'walking_the_dog', 'watching_a_movie', - 'watching_tv', 'working_out', 'writing']) - - def set_value(self, value): - self.del_value() - general = value - specific = None - if isinstance(value, tuple) or isinstance(value, list): - general = value[0] - specific = value[1] - - if general in self.general: - gen_xml = ET.Element('{%s}%s' % (self.namespace, general)) - if specific: - spec_xml = ET.Element('{%s}%s' % (self.namespace, specific)) - if specific in self.specific: - gen_xml.append(spec_xml) - else: - raise ValueError('Unknown specific activity') - self.xml.append(gen_xml) - else: - raise ValueError('Unknown general activity') - - def get_value(self): - general = None - specific = None - gen_xml = None - for child in self.xml: - if child.tag.startswith('{%s}' % self.namespace): - elem_name = child.tag.split('}')[-1] - if elem_name in self.general: - general = elem_name - gen_xml = child - if gen_xml is not None: - for child in gen_xml: - if child.tag.startswith('{%s}' % self.namespace): - elem_name = child.tag.split('}')[-1] - if elem_name in self.specific: - specific = elem_name - return (general, specific) - - def del_value(self): - curr_value = self.get_value() - if curr_value[0]: - self._set_sub_text(curr_value[0], '', keep=False) diff --git a/sleekxmpp/plugins/xep_0108/user_activity.py b/sleekxmpp/plugins/xep_0108/user_activity.py deleted file mode 100644 index 3a2f49b8..00000000 --- a/sleekxmpp/plugins/xep_0108/user_activity.py +++ /dev/null @@ -1,88 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0108 import stanza, UserActivity - - -log = logging.getLogger(__name__) - - -class XEP_0108(BasePlugin): - - """ - XEP-0108: User Activity - """ - - name = 'xep_0108' - description = 'XEP-0108: User Activity' - dependencies = set(['xep_0163']) - stanza = stanza - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=UserActivity.namespace) - self.xmpp['xep_0163'].remove_interest(UserActivity.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('user_activity', UserActivity) - - def publish_activity(self, general, specific=None, text=None, options=None, - ifrom=None, block=True, callback=None, timeout=None): - """ - Publish the user's current activity. - - Arguments: - general -- The required general category of the activity. - specific -- Optional specific activity being done as part - of the general category. - text -- Optional natural-language description or reason - for the activity. - options -- Optional form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - activity = UserActivity() - activity['value'] = (general, specific) - activity['text'] = text - return self.xmpp['xep_0163'].publish(activity, - node=UserActivity.namespace, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing user activity information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - activity = UserActivity() - return self.xmpp['xep_0163'].publish(activity, - node=UserActivity.namespace, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0115/__init__.py b/sleekxmpp/plugins/xep_0115/__init__.py deleted file mode 100644 index 31a2c03a..00000000 --- a/sleekxmpp/plugins/xep_0115/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0115.stanza import Capabilities -from sleekxmpp.plugins.xep_0115.static import StaticCaps -from sleekxmpp.plugins.xep_0115.caps import XEP_0115 - - -register_plugin(XEP_0115) - - -# Retain some backwards compatibility -xep_0115 = XEP_0115 diff --git a/sleekxmpp/plugins/xep_0115/caps.py b/sleekxmpp/plugins/xep_0115/caps.py deleted file mode 100644 index 41b5c52e..00000000 --- a/sleekxmpp/plugins/xep_0115/caps.py +++ /dev/null @@ -1,345 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging -import hashlib -import base64 -import threading - -from sleekxmpp import __version__ -from sleekxmpp.stanza import StreamFeatures, Presence, Iq -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.exceptions import XMPPError, IqError, IqTimeout -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0115 import stanza, StaticCaps - - -log = logging.getLogger(__name__) - - -class XEP_0115(BasePlugin): - - """ - XEP-0115: Entity Capabalities - """ - - name = 'xep_0115' - description = 'XEP-0115: Entity Capabilities' - dependencies = set(['xep_0030', 'xep_0128', 'xep_0004']) - stanza = stanza - default_config = { - 'hash': 'sha-1', - 'caps_node': None, - 'broadcast': True - } - - def plugin_init(self): - self.hashes = {'sha-1': hashlib.sha1, - 'sha1': hashlib.sha1, - 'md5': hashlib.md5} - - if self.caps_node is None: - self.caps_node = 'http://sleekxmpp.com/ver/%s' % __version__ - - register_stanza_plugin(Presence, stanza.Capabilities) - register_stanza_plugin(StreamFeatures, stanza.Capabilities) - - self._disco_ops = ['cache_caps', - 'get_caps', - 'assign_verstring', - 'get_verstring', - 'supports', - 'has_identity'] - - self.xmpp.register_handler( - Callback('Entity Capabilites', - StanzaPath('presence/caps'), - self._handle_caps)) - - self.xmpp.add_filter('out', self._filter_add_caps) - - self.xmpp.add_event_handler('entity_caps', self._process_caps, - threaded=True) - - if not self.xmpp.is_component: - self.xmpp.register_feature('caps', - self._handle_caps_feature, - restart=False, - order=10010) - - disco = self.xmpp['xep_0030'] - self.static = StaticCaps(self.xmpp, disco.static) - - for op in self._disco_ops: - self.api.register(getattr(self.static, op), op, default=True) - - for op in ('supports', 'has_identity'): - self.xmpp['xep_0030'].api.register(getattr(self.static, op), op) - - self._run_node_handler = disco._run_node_handler - - disco.cache_caps = self.cache_caps - disco.update_caps = self.update_caps - disco.assign_verstring = self.assign_verstring - disco.get_verstring = self.get_verstring - - self._processing_lock = threading.Lock() - self._processing = set() - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=stanza.Capabilities.namespace) - self.xmpp.del_filter('out', self._filter_add_caps) - self.xmpp.del_event_handler('entity_caps', self._process_caps) - self.xmpp.remove_handler('Entity Capabilities') - if not self.xmpp.is_component: - self.xmpp.unregister_feature('caps', 10010) - for op in ('supports', 'has_identity'): - self.xmpp['xep_0030'].restore_defaults(op) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(stanza.Capabilities.namespace) - - def _filter_add_caps(self, stanza): - if not isinstance(stanza, Presence) or not self.broadcast: - return stanza - - if stanza['type'] not in ('available', 'chat', 'away', 'dnd', 'xa'): - return stanza - - ver = self.get_verstring(stanza['from']) - if ver: - stanza['caps']['node'] = self.caps_node - stanza['caps']['hash'] = self.hash - stanza['caps']['ver'] = ver - return stanza - - def _handle_caps(self, presence): - if not self.xmpp.is_component: - if presence['from'] == self.xmpp.boundjid: - return - self.xmpp.event('entity_caps', presence) - - def _handle_caps_feature(self, features): - # We already have a method to process presence with - # caps, so wrap things up and use that. - p = Presence() - p['from'] = self.xmpp.boundjid.domain - p.append(features['caps']) - self.xmpp.features.add('caps') - - self.xmpp.event('entity_caps', p) - - def _process_caps(self, pres): - if not pres['caps']['hash']: - log.debug("Received unsupported legacy caps: %s, %s, %s", - pres['caps']['node'], - pres['caps']['ver'], - pres['caps']['ext']) - self.xmpp.event('entity_caps_legacy', pres) - return - - ver = pres['caps']['ver'] - - existing_verstring = self.get_verstring(pres['from'].full) - if str(existing_verstring) == str(ver): - return - - existing_caps = self.get_caps(verstring=ver) - if existing_caps is not None: - self.assign_verstring(pres['from'], ver) - return - - if pres['caps']['hash'] not in self.hashes: - try: - log.debug("Unknown caps hash: %s", pres['caps']['hash']) - self.xmpp['xep_0030'].get_info(jid=pres['from']) - return - except XMPPError: - return - - # Only lookup the same caps once at a time. - with self._processing_lock: - if ver in self._processing: - log.debug('Already processing verstring %s' % ver) - return - self._processing.add(ver) - - log.debug("New caps verification string: %s", ver) - try: - node = '%s#%s' % (pres['caps']['node'], ver) - caps = self.xmpp['xep_0030'].get_info(pres['from'], node) - - if isinstance(caps, Iq): - caps = caps['disco_info'] - - if self._validate_caps(caps, pres['caps']['hash'], - pres['caps']['ver']): - self.assign_verstring(pres['from'], pres['caps']['ver']) - except XMPPError: - log.debug("Could not retrieve disco#info results for caps for %s", node) - - with self._processing_lock: - self._processing.remove(ver) - - def _validate_caps(self, caps, hash, check_verstring): - # Check Identities - full_ids = caps.get_identities(dedupe=False) - deduped_ids = caps.get_identities() - if len(full_ids) != len(deduped_ids): - log.debug("Duplicate disco identities found, invalid for caps") - return False - - # Check Features - full_features = caps.get_features(dedupe=False) - deduped_features = caps.get_features() - if len(full_features) != len(deduped_features): - log.debug("Duplicate disco features found, invalid for caps") - return False - - # Check Forms - form_types = [] - deduped_form_types = set() - for stanza in caps['substanzas']: - if not isinstance(stanza, self.xmpp['xep_0004'].stanza.Form): - log.debug("Non form extension found, ignoring for caps") - caps.xml.remove(stanza.xml) - continue - if 'FORM_TYPE' in stanza['fields']: - f_type = tuple(stanza['fields']['FORM_TYPE']['value']) - form_types.append(f_type) - deduped_form_types.add(f_type) - if len(form_types) != len(deduped_form_types): - log.debug("Duplicated FORM_TYPE values, " + \ - "invalid for caps") - return False - - if len(f_type) > 1: - deduped_type = set(f_type) - if len(f_type) != len(deduped_type): - log.debug("Extra FORM_TYPE data, invalid for caps") - return False - - if stanza['fields']['FORM_TYPE']['type'] != 'hidden': - log.debug("Field FORM_TYPE type not 'hidden', " + \ - "ignoring form for caps") - caps.xml.remove(stanza.xml) - else: - log.debug("No FORM_TYPE found, ignoring form for caps") - caps.xml.remove(stanza.xml) - - verstring = self.generate_verstring(caps, hash) - if verstring != check_verstring: - log.debug("Verification strings do not match: %s, %s" % ( - verstring, check_verstring)) - return False - - self.cache_caps(verstring, caps) - return True - - def generate_verstring(self, info, hash): - hash = self.hashes.get(hash, None) - if hash is None: - return None - - S = '' - - # Convert None to '' in the identities - def clean_identity(id): - return map(lambda i: i or '', id) - identities = map(clean_identity, info['identities']) - - identities = sorted(('/'.join(i) for i in identities)) - features = sorted(info['features']) - - S += '<'.join(identities) + '<' - S += '<'.join(features) + '<' - - form_types = {} - - for stanza in info['substanzas']: - if isinstance(stanza, self.xmpp['xep_0004'].stanza.Form): - if 'FORM_TYPE' in stanza['fields']: - f_type = stanza['values']['FORM_TYPE'] - if len(f_type): - f_type = f_type[0] - if f_type not in form_types: - form_types[f_type] = [] - form_types[f_type].append(stanza) - - sorted_forms = sorted(form_types.keys()) - for f_type in sorted_forms: - for form in form_types[f_type]: - S += '%s<' % f_type - fields = sorted(form['fields'].keys()) - fields.remove('FORM_TYPE') - for field in fields: - S += '%s<' % field - vals = form['fields'][field].get_value(convert=False) - if vals is None: - S += '<' - else: - if not isinstance(vals, list): - vals = [vals] - S += '<'.join(sorted(vals)) + '<' - - binary = hash(S.encode('utf8')).digest() - return base64.b64encode(binary).decode('utf-8') - - def update_caps(self, jid=None, node=None, preserve=False): - try: - info = self.xmpp['xep_0030'].get_info(jid, node, local=True) - if isinstance(info, Iq): - info = info['disco_info'] - ver = self.generate_verstring(info, self.hash) - self.xmpp['xep_0030'].set_info( - jid=jid, - node='%s#%s' % (self.caps_node, ver), - info=info) - self.cache_caps(ver, info) - self.assign_verstring(jid, ver) - - if self.xmpp.session_started_event.is_set() and self.broadcast: - if self.xmpp.is_component or preserve: - for contact in self.xmpp.roster[jid]: - self.xmpp.roster[jid][contact].send_last_presence() - else: - self.xmpp.roster[jid].send_last_presence() - except XMPPError: - return - - def get_verstring(self, jid=None): - if jid in ('', None): - jid = self.xmpp.boundjid.full - if isinstance(jid, JID): - jid = jid.full - return self.api['get_verstring'](jid) - - def assign_verstring(self, jid=None, verstring=None): - if jid in (None, ''): - jid = self.xmpp.boundjid.full - if isinstance(jid, JID): - jid = jid.full - return self.api['assign_verstring'](jid, args={ - 'verstring': verstring}) - - def cache_caps(self, verstring=None, info=None): - data = {'verstring': verstring, 'info': info} - return self.api['cache_caps'](args=data) - - def get_caps(self, jid=None, verstring=None): - if verstring is None: - if jid is not None: - verstring = self.get_verstring(jid) - else: - return None - if isinstance(jid, JID): - jid = jid.full - data = {'verstring': verstring} - return self.api['get_caps'](jid, args=data) diff --git a/sleekxmpp/plugins/xep_0115/stanza.py b/sleekxmpp/plugins/xep_0115/stanza.py deleted file mode 100644 index 3e80b5cf..00000000 --- a/sleekxmpp/plugins/xep_0115/stanza.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from __future__ import unicode_literals - -from sleekxmpp.xmlstream import ElementBase - - -class Capabilities(ElementBase): - - namespace = 'http://jabber.org/protocol/caps' - name = 'c' - plugin_attrib = 'caps' - interfaces = set(('hash', 'node', 'ver', 'ext')) diff --git a/sleekxmpp/plugins/xep_0115/static.py b/sleekxmpp/plugins/xep_0115/static.py deleted file mode 100644 index f83c244c..00000000 --- a/sleekxmpp/plugins/xep_0115/static.py +++ /dev/null @@ -1,146 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 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 JID -from sleekxmpp.exceptions import IqError, IqTimeout - - -log = logging.getLogger(__name__) - - -class StaticCaps(object): - - """ - Extend the default StaticDisco implementation to provide - support for extended identity information. - """ - - def __init__(self, xmpp, static): - """ - Augment the default XEP-0030 static handler object. - - Arguments: - static -- The default static XEP-0030 handler object. - """ - self.xmpp = xmpp - self.disco = self.xmpp['xep_0030'] - self.caps = self.xmpp['xep_0115'] - self.static = static - self.ver_cache = {} - self.jid_vers = {} - - def supports(self, jid, node, ifrom, data): - """ - Check if a JID supports a given feature. - - The data parameter may provide: - feature -- The feature to check for support. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the info. - cached -- If true, then look for the disco info data from - the local cache system. If no results are found, - send the query as usual. The self.use_cache - setting must be set to true for this option to - be useful. If set to false, then the cache will - be skipped, even if a result has already been - cached. Defaults to false. - """ - feature = data.get('feature', None) - - data = {'local': data.get('local', False), - 'cached': data.get('cached', True)} - - if not feature: - return False - - if node in (None, ''): - info = self.caps.get_caps(jid) - if info and feature in info['features']: - return True - - try: - info = self.disco.get_info(jid=jid, node=node, - ifrom=ifrom, **data) - info = self.disco._wrap(ifrom, jid, info, True) - return feature in info['disco_info']['features'] - except IqError: - return False - except IqTimeout: - return None - - def has_identity(self, jid, node, ifrom, data): - """ - Check if a JID has a given identity. - - The data parameter may provide: - category -- The category of the identity to check. - itype -- The type of the identity to check. - lang -- The language of the identity to check. - local -- If true, then the query is for a JID/node - combination handled by this Sleek instance and - no stanzas need to be sent. - Otherwise, a disco stanza must be sent to the - remove JID to retrieve the info. - cached -- If true, then look for the disco info data from - the local cache system. If no results are found, - send the query as usual. The self.use_cache - setting must be set to true for this option to - be useful. If set to false, then the cache will - be skipped, even if a result has already been - cached. Defaults to false. - """ - identity = (data.get('category', None), - data.get('itype', None), - data.get('lang', None)) - - data = {'local': data.get('local', False), - 'cached': data.get('cached', True)} - - trunc = lambda i: (i[0], i[1], i[2]) - - if node in (None, ''): - info = self.caps.get_caps(jid) - if info and identity in map(trunc, info['identities']): - return True - - try: - info = self.disco.get_info(jid=jid, node=node, - ifrom=ifrom, **data) - info = self.disco._wrap(ifrom, jid, info, True) - return identity in map(trunc, info['disco_info']['identities']) - except IqError: - return False - except IqTimeout: - return None - - def cache_caps(self, jid, node, ifrom, data): - with self.static.lock: - verstring = data.get('verstring', None) - info = data.get('info', None) - if not verstring or not info: - return - self.ver_cache[verstring] = info - - def assign_verstring(self, jid, node, ifrom, data): - with self.static.lock: - if isinstance(jid, JID): - jid = jid.full - self.jid_vers[jid] = data.get('verstring', None) - - def get_verstring(self, jid, node, ifrom, data): - with self.static.lock: - return self.jid_vers.get(jid, None) - - def get_caps(self, jid, node, ifrom, data): - with self.static.lock: - return self.ver_cache.get(data.get('verstring', None), None) diff --git a/sleekxmpp/plugins/xep_0118/__init__.py b/sleekxmpp/plugins/xep_0118/__init__.py deleted file mode 100644 index 565f7844..00000000 --- a/sleekxmpp/plugins/xep_0118/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0118 import stanza -from sleekxmpp.plugins.xep_0118.stanza import UserTune -from sleekxmpp.plugins.xep_0118.user_tune import XEP_0118 - - -register_plugin(XEP_0118) diff --git a/sleekxmpp/plugins/xep_0118/stanza.py b/sleekxmpp/plugins/xep_0118/stanza.py deleted file mode 100644 index 3fdab284..00000000 --- a/sleekxmpp/plugins/xep_0118/stanza.py +++ /dev/null @@ -1,25 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class UserTune(ElementBase): - - name = 'tune' - namespace = 'http://jabber.org/protocol/tune' - plugin_attrib = 'tune' - interfaces = set(['artist', 'length', 'rating', 'source', - 'title', 'track', 'uri']) - sub_interfaces = interfaces - - def set_length(self, value): - self._set_sub_text('length', str(value)) - - def set_rating(self, value): - self._set_sub_text('rating', str(value)) diff --git a/sleekxmpp/plugins/xep_0118/user_tune.py b/sleekxmpp/plugins/xep_0118/user_tune.py deleted file mode 100644 index 1bb00122..00000000 --- a/sleekxmpp/plugins/xep_0118/user_tune.py +++ /dev/null @@ -1,96 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0118 import stanza, UserTune - - -log = logging.getLogger(__name__) - - -class XEP_0118(BasePlugin): - - """ - XEP-0118: User Tune - """ - - name = 'xep_0118' - description = 'XEP-0118: User Tune' - dependencies = set(['xep_0163']) - stanza = stanza - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=UserTune.namespace) - self.xmpp['xep_0163'].remove_interest(UserTune.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('user_tune', UserTune) - - def publish_tune(self, artist=None, length=None, rating=None, source=None, - title=None, track=None, uri=None, options=None, - ifrom=None, block=True, callback=None, timeout=None): - """ - Publish the user's current tune. - - Arguments: - artist -- The artist or performer of the song. - length -- The length of the song in seconds. - rating -- The user's rating of the song (from 1 to 10) - source -- The album name, website, or other source of the song. - title -- The title of the song. - track -- The song's track number, or other unique identifier. - uri -- A URL to more information about the song. - options -- Optional form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - tune = UserTune() - tune['artist'] = artist - tune['length'] = length - tune['rating'] = rating - tune['source'] = source - tune['title'] = title - tune['track'] = track - tune['uri'] = uri - return self.xmpp['xep_0163'].publish(tune, - node=UserTune.namespace, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing user tune information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - tune = UserTune() - return self.xmpp['xep_0163'].publish(tune, - node=UserTune.namespace, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0128/__init__.py b/sleekxmpp/plugins/xep_0128/__init__.py deleted file mode 100644 index 27c2cc33..00000000 --- a/sleekxmpp/plugins/xep_0128/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0128.static import StaticExtendedDisco -from sleekxmpp.plugins.xep_0128.extended_disco import XEP_0128 - - -register_plugin(XEP_0128) - - -# Retain some backwards compatibility -xep_0128 = XEP_0128 diff --git a/sleekxmpp/plugins/xep_0128/extended_disco.py b/sleekxmpp/plugins/xep_0128/extended_disco.py deleted file mode 100644 index d785affe..00000000 --- a/sleekxmpp/plugins/xep_0128/extended_disco.py +++ /dev/null @@ -1,99 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -import sleekxmpp -from sleekxmpp import Iq -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0004 import Form -from sleekxmpp.plugins.xep_0030 import DiscoInfo -from sleekxmpp.plugins.xep_0128 import StaticExtendedDisco - - -class XEP_0128(BasePlugin): - - """ - XEP-0128: Service Discovery Extensions - - Allow the use of data forms to add additional identity - information to disco#info results. - - Also see . - - Attributes: - disco -- A reference to the XEP-0030 plugin. - static -- Object containing the default set of static - node handlers. - xmpp -- The main SleekXMPP object. - - Methods: - set_extended_info -- Set extensions to a disco#info result. - add_extended_info -- Add an extension to a disco#info result. - del_extended_info -- Remove all extensions from a disco#info result. - """ - - name = 'xep_0128' - description = 'XEP-0128: Service Discovery Extensions' - dependencies = set(['xep_0030', 'xep_0004']) - - def plugin_init(self): - """Start the XEP-0128 plugin.""" - self._disco_ops = ['set_extended_info', - 'add_extended_info', - 'del_extended_info'] - - register_stanza_plugin(DiscoInfo, Form, iterable=True) - - self.disco = self.xmpp['xep_0030'] - self.static = StaticExtendedDisco(self.disco.static) - - self.disco.set_extended_info = self.set_extended_info - self.disco.add_extended_info = self.add_extended_info - self.disco.del_extended_info = self.del_extended_info - - for op in self._disco_ops: - self.api.register(getattr(self.static, op), op, default=True) - - def set_extended_info(self, jid=None, node=None, **kwargs): - """ - Set additional, extended identity information to a node. - - Replaces any existing extended information. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - data -- Either a form, or a list of forms to use - as extended information, replacing any - existing extensions. - """ - self.api['set_extended_info'](jid, node, None, kwargs) - - def add_extended_info(self, jid=None, node=None, **kwargs): - """ - Add additional, extended identity information to a node. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - data -- Either a form, or a list of forms to add - as extended information. - """ - self.api['add_extended_info'](jid, node, None, kwargs) - - def del_extended_info(self, jid=None, node=None, **kwargs): - """ - Remove all extended identity information to a node. - - Arguments: - jid -- The JID to modify. - node -- The node to modify. - """ - self.api['del_extended_info'](jid, node, None, kwargs) diff --git a/sleekxmpp/plugins/xep_0128/static.py b/sleekxmpp/plugins/xep_0128/static.py deleted file mode 100644 index 427011c0..00000000 --- a/sleekxmpp/plugins/xep_0128/static.py +++ /dev/null @@ -1,73 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -import sleekxmpp -from sleekxmpp.plugins.xep_0030 import StaticDisco - - -log = logging.getLogger(__name__) - - -class StaticExtendedDisco(object): - - """ - Extend the default StaticDisco implementation to provide - support for extended identity information. - """ - - def __init__(self, static): - """ - Augment the default XEP-0030 static handler object. - - Arguments: - static -- The default static XEP-0030 handler object. - """ - self.static = static - - def set_extended_info(self, jid, node, ifrom, data): - """ - Replace the extended identity data for a JID/node combination. - - The data parameter may provide: - data -- Either a single data form, or a list of data forms. - """ - with self.static.lock: - self.del_extended_info(jid, node, ifrom, data) - self.add_extended_info(jid, node, ifrom, data) - - def add_extended_info(self, jid, node, ifrom, data): - """ - Add additional extended identity data for a JID/node combination. - - The data parameter may provide: - data -- Either a single data form, or a list of data forms. - """ - with self.static.lock: - self.static.add_node(jid, node) - - forms = data.get('data', []) - if not isinstance(forms, list): - forms = [forms] - - info = self.static.get_node(jid, node)['info'] - for form in forms: - info.append(form) - - def del_extended_info(self, jid, node, ifrom, data): - """ - Replace the extended identity data for a JID/node combination. - - The data parameter is not used. - """ - with self.static.lock: - if self.static.node_exists(jid, node): - info = self.static.get_node(jid, node)['info'] - for form in info['substanza']: - info.xml.remove(form.xml) diff --git a/sleekxmpp/plugins/xep_0131/__init__.py b/sleekxmpp/plugins/xep_0131/__init__.py deleted file mode 100644 index ec71c98d..00000000 --- a/sleekxmpp/plugins/xep_0131/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0131 import stanza -from sleekxmpp.plugins.xep_0131.stanza import Headers -from sleekxmpp.plugins.xep_0131.headers import XEP_0131 - - -register_plugin(XEP_0131) diff --git a/sleekxmpp/plugins/xep_0131/headers.py b/sleekxmpp/plugins/xep_0131/headers.py deleted file mode 100644 index 3e47541a..00000000 --- a/sleekxmpp/plugins/xep_0131/headers.py +++ /dev/null @@ -1,41 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp import Message, Presence -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0131 import stanza -from sleekxmpp.plugins.xep_0131.stanza import Headers - - -class XEP_0131(BasePlugin): - - name = 'xep_0131' - description = 'XEP-0131: Stanza Headers and Internet Metadata' - dependencies = set(['xep_0030']) - stanza = stanza - default_config = { - 'supported_headers': set() - } - - def plugin_init(self): - register_stanza_plugin(Message, Headers) - register_stanza_plugin(Presence, Headers) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=Headers.namespace) - for header in self.supported_headers: - self.xmpp['xep_0030'].del_feature( - feature='%s#%s' % (Headers.namespace, header)) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(Headers.namespace) - for header in self.supported_headers: - self.xmpp['xep_0030'].add_feature('%s#%s' % ( - Headers.namespace, - header)) diff --git a/sleekxmpp/plugins/xep_0131/stanza.py b/sleekxmpp/plugins/xep_0131/stanza.py deleted file mode 100644 index 347adf96..00000000 --- a/sleekxmpp/plugins/xep_0131/stanza.py +++ /dev/null @@ -1,51 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.thirdparty import OrderedDict -from sleekxmpp.xmlstream import ET, ElementBase - - -class Headers(ElementBase): - name = 'headers' - namespace = 'http://jabber.org/protocol/shim' - plugin_attrib = 'headers' - interfaces = set(['headers']) - is_extension = True - - def get_headers(self): - result = OrderedDict() - headers = self.xml.findall('{%s}header' % self.namespace) - for header in headers: - name = header.attrib.get('name', '') - value = header.text - if name in result: - if not isinstance(result[name], set): - result[name] = [result[name]] - else: - result[name] = [] - result[name].add(value) - else: - result[name] = value - return result - - def set_headers(self, values): - self.del_headers() - for name in values: - vals = values[name] - if not isinstance(vals, (list, set)): - vals = [values[name]] - for value in vals: - header = ET.Element('{%s}header' % self.namespace) - header.attrib['name'] = name - header.text = value - self.xml.append(header) - - def del_headers(self): - headers = self.xml.findall('{%s}header' % self.namespace) - for header in headers: - self.xml.remove(header) diff --git a/sleekxmpp/plugins/xep_0133.py b/sleekxmpp/plugins/xep_0133.py deleted file mode 100644 index 7bbe4c3c..00000000 --- a/sleekxmpp/plugins/xep_0133.py +++ /dev/null @@ -1,54 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - - -from sleekxmpp.plugins import BasePlugin, register_plugin - - -class XEP_0133(BasePlugin): - - name = 'xep_0133' - description = 'XEP-0133: Service Administration' - dependencies = set(['xep_0030', 'xep_0004', 'xep_0050']) - commands = set(['add-user', 'delete-user', 'disable-user', - 'reenable-user', 'end-user-session', 'get-user-password', - 'change-user-password', 'get-user-roster', - 'get-user-lastlogin', 'user-stats', 'edit-blacklist', - 'edit-whitelist', 'get-registered-users-num', - 'get-disabled-users-num', 'get-online-users-num', - 'get-active-users-num', 'get-idle-users-num', - 'get-registered-users-list', 'get-disabled-users-list', - 'get-online-users-list', 'get-online-users', - 'get-active-users', 'get-idle-userslist', 'announce', - 'set-motd', 'edit-motd', 'delete-motd', 'set-welcome', - 'delete-welcome', 'edit-admin', 'restart', 'shutdown']) - - def get_commands(self, jid=None, **kwargs): - if jid is None: - jid = self.xmpp.boundjid.server - return self.xmpp['xep_0050'].get_commands(jid, **kwargs) - - -def create_command(name): - def admin_command(self, jid=None, session=None, ifrom=None, block=False): - if jid is None: - jid = self.xmpp.boundjid.server - self.xmpp['xep_0050'].start_command( - jid=jid, - node='http://jabber.org/protocol/admin#%s' % name, - session=session, - ifrom=ifrom, - block=block) - return admin_command - - -for cmd in XEP_0133.commands: - setattr(XEP_0133, cmd.replace('-', '_'), create_command(cmd)) - - -register_plugin(XEP_0133) diff --git a/sleekxmpp/plugins/xep_0152/__init__.py b/sleekxmpp/plugins/xep_0152/__init__.py deleted file mode 100644 index 7de031b7..00000000 --- a/sleekxmpp/plugins/xep_0152/__init__.py +++ /dev/null @@ -1,16 +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 - -from sleekxmpp.plugins.xep_0152 import stanza -from sleekxmpp.plugins.xep_0152.stanza import Reachability -from sleekxmpp.plugins.xep_0152.reachability import XEP_0152 - - -register_plugin(XEP_0152) diff --git a/sleekxmpp/plugins/xep_0152/reachability.py b/sleekxmpp/plugins/xep_0152/reachability.py deleted file mode 100644 index 4cf81739..00000000 --- a/sleekxmpp/plugins/xep_0152/reachability.py +++ /dev/null @@ -1,93 +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.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0152 import stanza, Reachability - - -log = logging.getLogger(__name__) - - -class XEP_0152(BasePlugin): - - """ - XEP-0152: Reachability Addresses - """ - - name = 'xep_0152' - description = 'XEP-0152: Reachability Addresses' - dependencies = set(['xep_0163']) - stanza = stanza - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=Reachability.namespace) - self.xmpp['xep_0163'].remove_interest(Reachability.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('reachability', Reachability) - - def publish_reachability(self, addresses, options=None, - ifrom=None, block=True, callback=None, timeout=None): - """ - Publish alternative addresses where the user can be reached. - - Arguments: - addresses -- A list of dictionaries containing the URI and - optional description for each address. - options -- Optional form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - if not isinstance(addresses, (list, tuple)): - addresses = [addresses] - reach = Reachability() - for address in addresses: - if not hasattr(address, 'items'): - address = {'uri': address} - - addr = stanza.Address() - for key, val in address.items(): - addr[key] = val - reach.append(addr) - return self.xmpp['xep_0163'].publish(reach, - node=Reachability.namespace, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing user activity information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - reach = Reachability() - return self.xmpp['xep_0163'].publish(reach, - node=Reachability.namespace, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0152/stanza.py b/sleekxmpp/plugins/xep_0152/stanza.py deleted file mode 100644 index bd173ce1..00000000 --- a/sleekxmpp/plugins/xep_0152/stanza.py +++ /dev/null @@ -1,29 +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 Reachability(ElementBase): - name = 'reach' - namespace = 'urn:xmpp:reach:0' - plugin_attrib = 'reach' - interfaces = set() - - -class Address(ElementBase): - name = 'addr' - namespace = 'urn:xmpp:reach:0' - plugin_attrib = 'address' - plugin_multi_attrib = 'addresses' - interfaces = set(['uri', 'desc']) - lang_interfaces = set(['desc']) - sub_interfaces = set(['desc']) - - -register_stanza_plugin(Reachability, Address, iterable=True) diff --git a/sleekxmpp/plugins/xep_0153/__init__.py b/sleekxmpp/plugins/xep_0153/__init__.py deleted file mode 100644 index f52b7712..00000000 --- a/sleekxmpp/plugins/xep_0153/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0153.stanza import VCardTempUpdate -from sleekxmpp.plugins.xep_0153.vcard_avatar import XEP_0153 - - -register_plugin(XEP_0153) diff --git a/sleekxmpp/plugins/xep_0153/stanza.py b/sleekxmpp/plugins/xep_0153/stanza.py deleted file mode 100644 index 4e6a660f..00000000 --- a/sleekxmpp/plugins/xep_0153/stanza.py +++ /dev/null @@ -1,29 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase - - -class VCardTempUpdate(ElementBase): - name = 'x' - namespace = 'vcard-temp:x:update' - plugin_attrib = 'vcard_temp_update' - interfaces = set(['photo']) - sub_interfaces = interfaces - - def set_photo(self, value): - if value is not None: - self._set_sub_text('photo', value, keep=True) - else: - self._del_sub('photo') - - def get_photo(self): - photo = self.xml.find('{%s}photo' % self.namespace) - if photo is None: - return None - return photo.text diff --git a/sleekxmpp/plugins/xep_0153/vcard_avatar.py b/sleekxmpp/plugins/xep_0153/vcard_avatar.py deleted file mode 100644 index ec1ae782..00000000 --- a/sleekxmpp/plugins/xep_0153/vcard_avatar.py +++ /dev/null @@ -1,152 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import hashlib -import logging -import threading - -from sleekxmpp.stanza import Presence -from sleekxmpp.exceptions import XMPPError -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0153 import stanza, VCardTempUpdate - - -log = logging.getLogger(__name__) - - -class XEP_0153(BasePlugin): - - name = 'xep_0153' - description = 'XEP-0153: vCard-Based Avatars' - dependencies = set(['xep_0054']) - stanza = stanza - - def plugin_init(self): - self._hashes = {} - - self._allow_advertising = threading.Event() - - register_stanza_plugin(Presence, VCardTempUpdate) - - self.xmpp.add_filter('out', self._update_presence) - - self.xmpp.add_event_handler('session_start', self._start) - self.xmpp.add_event_handler('session_end', self._end) - - self.xmpp.add_event_handler('presence_available', self._recv_presence) - self.xmpp.add_event_handler('presence_dnd', self._recv_presence) - self.xmpp.add_event_handler('presence_xa', self._recv_presence) - self.xmpp.add_event_handler('presence_chat', self._recv_presence) - self.xmpp.add_event_handler('presence_away', self._recv_presence) - - self.api.register(self._set_hash, 'set_hash', default=True) - self.api.register(self._get_hash, 'get_hash', default=True) - self.api.register(self._reset_hash, 'reset_hash', default=True) - - def plugin_end(self): - self.xmpp.del_filter('out', self._update_presence) - self.xmpp.del_event_handler('session_start', self._start) - self.xmpp.del_event_handler('session_end', self._end) - self.xmpp.del_event_handler('presence_available', self._recv_presence) - self.xmpp.del_event_handler('presence_dnd', self._recv_presence) - self.xmpp.del_event_handler('presence_xa', self._recv_presence) - self.xmpp.del_event_handler('presence_chat', self._recv_presence) - self.xmpp.del_event_handler('presence_away', self._recv_presence) - - def set_avatar(self, jid=None, avatar=None, mtype=None, block=True, - timeout=None, callback=None): - if jid is None: - jid = self.xmpp.boundjid.bare - - vcard = self.xmpp['xep_0054'].get_vcard(jid, cached=True) - vcard = vcard['vcard_temp'] - vcard['PHOTO']['TYPE'] = mtype - vcard['PHOTO']['BINVAL'] = avatar - - self.xmpp['xep_0054'].publish_vcard(jid=jid, vcard=vcard) - - self.api['reset_hash'](jid) - self.xmpp.roster[jid].send_last_presence() - - def _start(self, event): - try: - vcard = self.xmpp['xep_0054'].get_vcard(self.xmpp.boundjid.bare) - data = vcard['vcard_temp']['PHOTO']['BINVAL'] - if not data: - new_hash = '' - else: - new_hash = hashlib.sha1(data).hexdigest() - self.api['set_hash'](self.xmpp.boundjid, args=new_hash) - self._allow_advertising.set() - except XMPPError: - log.debug('Could not retrieve vCard for %s' % self.xmpp.boundjid.bare) - - def _end(self, event): - self._allow_advertising.clear() - - def _update_presence(self, stanza): - if not isinstance(stanza, Presence): - return stanza - - if stanza['type'] not in ('available', 'dnd', 'chat', 'away', 'xa'): - return stanza - - current_hash = self.api['get_hash'](stanza['from']) - stanza['vcard_temp_update']['photo'] = current_hash - return stanza - - def _reset_hash(self, jid, node, ifrom, args): - own_jid = (jid.bare == self.xmpp.boundjid.bare) - if self.xmpp.is_component: - own_jid = (jid.domain == self.xmpp.boundjid.domain) - - self.api['set_hash'](jid, args=None) - if own_jid: - self.xmpp.roster[jid].send_last_presence() - - try: - iq = self.xmpp['xep_0054'].get_vcard(jid=jid.bare, ifrom=ifrom) - - data = iq['vcard_temp']['PHOTO']['BINVAL'] - if not data: - new_hash = '' - else: - new_hash = hashlib.sha1(data).hexdigest() - - self.api['set_hash'](jid, args=new_hash) - except XMPPError: - log.debug('Could not retrieve vCard for %s' % jid) - - def _recv_presence(self, pres): - try: - if pres['muc']['affiliation']: - # Don't process vCard avatars for MUC occupants - # since they all share the same bare JID. - return - except: pass - - if not pres.match('presence/vcard_temp_update'): - self.api['set_hash'](pres['from'], args=None) - return - - data = pres['vcard_temp_update']['photo'] - if data is None: - return - elif data == '' or data != self.api['get_hash'](pres['from']): - ifrom = pres['to'] if self.xmpp.is_component else None - self.api['reset_hash'](pres['from'], ifrom=ifrom) - self.xmpp.event('vcard_avatar_update', pres) - - # ================================================================= - - def _get_hash(self, jid, node, ifrom, args): - return self._hashes.get(jid.bare, None) - - def _set_hash(self, jid, node, ifrom, args): - self._hashes[jid.bare] = args diff --git a/sleekxmpp/plugins/xep_0163.py b/sleekxmpp/plugins/xep_0163.py deleted file mode 100644 index 2d1a63b7..00000000 --- a/sleekxmpp/plugins/xep_0163.py +++ /dev/null @@ -1,123 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 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.base import BasePlugin, register_plugin - - -log = logging.getLogger(__name__) - - -class XEP_0163(BasePlugin): - - """ - XEP-0163: Personal Eventing Protocol (PEP) - """ - - name = 'xep_0163' - description = 'XEP-0163: Personal Eventing Protocol (PEP)' - dependencies = set(['xep_0030', 'xep_0060', 'xep_0115']) - - def register_pep(self, name, stanza): - """ - Setup and configure events and stanza registration for - the given PEP stanza: - - - Add disco feature for the PEP content. - - Register disco interest in the PEP content. - - Map events from the PEP content's namespace to the given name. - - :param str name: The event name prefix to use for PEP events. - :param stanza: The stanza class for the PEP content. - """ - pubsub_stanza = self.xmpp['xep_0060'].stanza - register_stanza_plugin(pubsub_stanza.EventItem, stanza) - - self.add_interest(stanza.namespace) - self.xmpp['xep_0030'].add_feature(stanza.namespace) - self.xmpp['xep_0060'].map_node_event(stanza.namespace, name) - - def add_interest(self, namespace, jid=None): - """ - Mark an interest in a PEP subscription by including a disco - feature with the '+notify' extension. - - Arguments: - namespace -- The base namespace to register as an interest, such - as 'http://jabber.org/protocol/tune'. This may also - be a list of such namespaces. - jid -- Optionally specify the JID. - """ - if not isinstance(namespace, set) and not isinstance(namespace, list): - namespace = [namespace] - - for ns in namespace: - self.xmpp['xep_0030'].add_feature('%s+notify' % ns, - jid=jid) - self.xmpp['xep_0115'].update_caps(jid) - - def remove_interest(self, namespace, jid=None): - """ - Mark an interest in a PEP subscription by including a disco - feature with the '+notify' extension. - - Arguments: - namespace -- The base namespace to remove as an interest, such - as 'http://jabber.org/protocol/tune'. This may also - be a list of such namespaces. - jid -- Optionally specify the JID. - """ - if not isinstance(namespace, (set, list)): - namespace = [namespace] - - for ns in namespace: - self.xmpp['xep_0030'].del_feature(jid=jid, - feature='%s+notify' % namespace) - self.xmpp['xep_0115'].update_caps(jid) - - def publish(self, stanza, node=None, id=None, options=None, ifrom=None, - block=True, callback=None, timeout=None): - """ - Publish a PEP update. - - This is just a (very) thin wrapper around the XEP-0060 publish() - method to set the defaults expected by PEP. - - Arguments: - stanza -- The PEP update stanza to publish. - node -- The node to publish the item to. If not specified, - the stanza's namespace will be used. - id -- Optionally specify the ID of the item. - options -- A form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - if node is None: - node = stanza.namespace - if id is None: - id = 'current' - - return self.xmpp['xep_0060'].publish(ifrom, node, - id=id, - payload=stanza.xml, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - -register_plugin(XEP_0163) diff --git a/sleekxmpp/plugins/xep_0172/__init__.py b/sleekxmpp/plugins/xep_0172/__init__.py deleted file mode 100644 index aa7b9f72..00000000 --- a/sleekxmpp/plugins/xep_0172/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0172 import stanza -from sleekxmpp.plugins.xep_0172.stanza import UserNick -from sleekxmpp.plugins.xep_0172.user_nick import XEP_0172 - - -register_plugin(XEP_0172) diff --git a/sleekxmpp/plugins/xep_0172/stanza.py b/sleekxmpp/plugins/xep_0172/stanza.py deleted file mode 100644 index 110c237b..00000000 --- a/sleekxmpp/plugins/xep_0172/stanza.py +++ /dev/null @@ -1,67 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class UserNick(ElementBase): - - """ - XEP-0172: User Nickname allows the addition of a element - in several stanza types, including and stanzas. - - The nickname contained in a should be the global, friendly or - informal name chosen by the owner of a bare JID. The element - may be included when establishing communications with new entities, - such as normal XMPP users or MUC services. - - The nickname contained in a element will not necessarily be - the same as the nickname used in a MUC. - - Example stanzas: - - The User - ... - - - - The User - - - Stanza Interface: - nick -- A global, friendly or informal name chosen by a user. - - Methods: - setup -- Overrides ElementBase.setup. - get_nick -- Return the nickname in the element. - set_nick -- Add a element with the given nickname. - del_nick -- Remove the element. - """ - - namespace = 'http://jabber.org/protocol/nick' - name = 'nick' - plugin_attrib = name - interfaces = set(('nick',)) - - def set_nick(self, nick): - """ - Add a element with the given nickname. - - Arguments: - nick -- A human readable, informal name. - """ - self.xml.text = nick - - def get_nick(self): - """Return the nickname in the element.""" - return self.xml.text - - def del_nick(self): - """Remove the element.""" - if self.parent is not None: - self.parent().xml.remove(self.xml) diff --git a/sleekxmpp/plugins/xep_0172/user_nick.py b/sleekxmpp/plugins/xep_0172/user_nick.py deleted file mode 100644 index cab13c15..00000000 --- a/sleekxmpp/plugins/xep_0172/user_nick.py +++ /dev/null @@ -1,92 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 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.message import Message -from sleekxmpp.stanza.presence import Presence -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import MatchXPath -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0172 import stanza, UserNick - - -log = logging.getLogger(__name__) - - -class XEP_0172(BasePlugin): - - """ - XEP-0172: User Nickname - """ - - name = 'xep_0172' - description = 'XEP-0172: User Nickname' - dependencies = set(['xep_0163']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Message, UserNick) - register_stanza_plugin(Presence, UserNick) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=UserNick.namespace) - self.xmpp['xep_0163'].remove_interest(UserNick.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('user_nick', UserNick) - - def publish_nick(self, nick=None, options=None, ifrom=None, block=True, - callback=None, timeout=None): - """ - Publish the user's current nick. - - Arguments: - nick -- The user nickname to publish. - options -- Optional form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - nickname = UserNick() - nickname['nick'] = nick - return self.xmpp['xep_0163'].publish(nickname, - node=UserNick.namespace, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing user nick information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - nick = UserNick() - return self.xmpp['xep_0163'].publish(nick, - node=UserNick.namespace, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0184/__init__.py b/sleekxmpp/plugins/xep_0184/__init__.py deleted file mode 100644 index 4b129b6b..00000000 --- a/sleekxmpp/plugins/xep_0184/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Erik Reuterborg Larsson, 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.plugins.xep_0184.stanza import Request, Received -from sleekxmpp.plugins.xep_0184.receipt import XEP_0184 - - -register_plugin(XEP_0184) - - -# Retain some backwards compatibility -xep_0184 = XEP_0184 diff --git a/sleekxmpp/plugins/xep_0184/receipt.py b/sleekxmpp/plugins/xep_0184/receipt.py deleted file mode 100644 index 3e97d8db..00000000 --- a/sleekxmpp/plugins/xep_0184/receipt.py +++ /dev/null @@ -1,131 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Erik Reuterborg Larsson, Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp.stanza import Message -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0184 import stanza, Request, Received - - -class XEP_0184(BasePlugin): - - """ - XEP-0184: Message Delivery Receipts - """ - - name = 'xep_0184' - description = 'XEP-0184: Message Delivery Receipts' - dependencies = set(['xep_0030']) - stanza = stanza - default_config = { - 'auto_ack': True, - 'auto_request': False - } - - ack_types = ('normal', 'chat', 'headline') - - def plugin_init(self): - register_stanza_plugin(Message, Request) - register_stanza_plugin(Message, Received) - - self.xmpp.add_filter('out', self._filter_add_receipt_request) - - self.xmpp.register_handler( - Callback('Message Receipt', - StanzaPath('message/receipt'), - self._handle_receipt_received)) - - self.xmpp.register_handler( - Callback('Message Receipt Request', - StanzaPath('message/request_receipt'), - self._handle_receipt_request)) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature('urn:xmpp:receipts') - self.xmpp.del_filter('out', self._filter_add_receipt_request) - self.xmpp.remove_handler('Message Receipt') - self.xmpp.remove_handler('Message Receipt Request') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('urn:xmpp:receipts') - - def ack(self, msg): - """ - Acknowledge a message by sending a receipt. - - Arguments: - msg -- The message to acknowledge. - """ - ack = self.xmpp.Message() - ack['to'] = msg['from'] - ack['from'] = msg['to'] - ack['receipt'] = msg['id'] - ack['id'] = msg['id'] - ack.send() - - def _handle_receipt_received(self, msg): - self.xmpp.event('receipt_received', msg) - - def _handle_receipt_request(self, msg): - """ - Auto-ack message receipt requests if ``self.auto_ack`` is ``True``. - - Arguments: - msg -- The incoming message requesting a receipt. - """ - if self.auto_ack: - if msg['type'] in self.ack_types: - if not msg['receipt']: - self.ack(msg) - - def _filter_add_receipt_request(self, stanza): - """ - Auto add receipt requests to outgoing messages, if: - - - ``self.auto_request`` is set to ``True`` - - The message is not for groupchat - - The message does not contain a receipt acknowledgment - - The recipient is a bare JID or, if a full JID, one - that has the ``urn:xmpp:receipts`` feature enabled - - The disco cache is checked if a full JID is specified in - the outgoing message, which may mean a round-trip disco#info - delay for the first message sent to the JID if entity caps - are not used. - """ - - if not self.auto_request: - return stanza - - if not isinstance(stanza, Message): - return stanza - - if stanza['request_receipt']: - return stanza - - if not stanza['type'] in self.ack_types: - return stanza - - if stanza['receipt']: - return stanza - - if not stanza['body']: - return stanza - - if stanza['to'].resource: - if not self.xmpp['xep_0030'].supports(stanza['to'], - feature='urn:xmpp:receipts', - cached=True): - return stanza - - stanza['request_receipt'] = True - return stanza diff --git a/sleekxmpp/plugins/xep_0184/stanza.py b/sleekxmpp/plugins/xep_0184/stanza.py deleted file mode 100644 index a7607035..00000000 --- a/sleekxmpp/plugins/xep_0184/stanza.py +++ /dev/null @@ -1,72 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Erik Reuterborg Larsson, Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream.stanzabase import ElementBase, ET - - -class Request(ElementBase): - namespace = 'urn:xmpp:receipts' - name = 'request' - plugin_attrib = 'request_receipt' - interfaces = set(('request_receipt',)) - sub_interfaces = interfaces - is_extension = True - - def setup(self, xml=None): - self.xml = ET.Element('') - return True - - def set_request_receipt(self, val): - self.del_request_receipt() - if val: - parent = self.parent() - parent._set_sub_text("{%s}request" % self.namespace, keep=True) - if not parent['id']: - if parent.stream: - parent['id'] = parent.stream.new_id() - - def get_request_receipt(self): - parent = self.parent() - if parent.find("{%s}request" % self.namespace) is not None: - return True - else: - return False - - def del_request_receipt(self): - self.parent()._del_sub("{%s}request" % self.namespace) - - -class Received(ElementBase): - namespace = 'urn:xmpp:receipts' - name = 'received' - plugin_attrib = 'receipt' - interfaces = set(['receipt']) - sub_interfaces = interfaces - is_extension = True - - def setup(self, xml=None): - self.xml = ET.Element('') - return True - - def set_receipt(self, value): - self.del_receipt() - if value: - parent = self.parent() - xml = ET.Element("{%s}received" % self.namespace) - xml.attrib['id'] = value - parent.append(xml) - - def get_receipt(self): - parent = self.parent() - xml = parent.find("{%s}received" % self.namespace) - if xml is not None: - return xml.attrib.get('id', '') - return '' - - def del_receipt(self): - self.parent()._del_sub('{%s}received' % self.namespace) diff --git a/sleekxmpp/plugins/xep_0186/__init__.py b/sleekxmpp/plugins/xep_0186/__init__.py deleted file mode 100644 index c9b8c6b9..00000000 --- a/sleekxmpp/plugins/xep_0186/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0186 import stanza -from sleekxmpp.plugins.xep_0186.stanza import Invisible, Visible -from sleekxmpp.plugins.xep_0186.invisible_command import XEP_0186 - - -register_plugin(XEP_0186) diff --git a/sleekxmpp/plugins/xep_0186/invisible_command.py b/sleekxmpp/plugins/xep_0186/invisible_command.py deleted file mode 100644 index 15f63b2d..00000000 --- a/sleekxmpp/plugins/xep_0186/invisible_command.py +++ /dev/null @@ -1,44 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import Iq -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.plugins.xep_0186 import stanza, Visible, Invisible - - -log = logging.getLogger(__name__) - - -class XEP_0186(BasePlugin): - - name = 'xep_0186' - description = 'XEP-0186: Invisible Command' - dependencies = set(['xep_0030']) - - def plugin_init(self): - register_stanza_plugin(Iq, Visible) - register_stanza_plugin(Iq, Invisible) - - def set_invisible(self, ifrom=None, block=True, callback=None, - timeout=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - iq.enable('invisible') - iq.send(block=block, callback=callback, timeout=timeout) - - def set_visible(self, ifrom=None, block=True, callback=None, - timeout=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - iq.enable('visible') - iq.send(block=block, callback=callback, timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0186/stanza.py b/sleekxmpp/plugins/xep_0186/stanza.py deleted file mode 100644 index aadbaa16..00000000 --- a/sleekxmpp/plugins/xep_0186/stanza.py +++ /dev/null @@ -1,23 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class Invisible(ElementBase): - name = 'invisible' - namespace = 'urn:xmpp:invisible:0' - plugin_attrib = 'invisible' - interfaces = set() - - -class Visible(ElementBase): - name = 'visible' - namespace = 'urn:xmpp:visible:0' - plugin_attrib = 'visible' - interfaces = set() diff --git a/sleekxmpp/plugins/xep_0191/__init__.py b/sleekxmpp/plugins/xep_0191/__init__.py deleted file mode 100644 index 934ac631..00000000 --- a/sleekxmpp/plugins/xep_0191/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0191.stanza import Block, Unblock, BlockList -from sleekxmpp.plugins.xep_0191.blocking import XEP_0191 - - -register_plugin(XEP_0191) diff --git a/sleekxmpp/plugins/xep_0191/blocking.py b/sleekxmpp/plugins/xep_0191/blocking.py deleted file mode 100644 index 57632319..00000000 --- a/sleekxmpp/plugins/xep_0191/blocking.py +++ /dev/null @@ -1,83 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp import Iq -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream import register_stanza_plugin, JID -from sleekxmpp.plugins.xep_0191 import stanza, Block, Unblock, BlockList - - -log = logging.getLogger(__name__) - - -class XEP_0191(BasePlugin): - - name = 'xep_0191' - description = 'XEP-0191: Blocking Command' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, BlockList) - register_stanza_plugin(Iq, Block) - register_stanza_plugin(Iq, Unblock) - - self.xmpp.register_handler( - Callback('Blocked Contact', - StanzaPath('iq@type=set/block'), - self._handle_blocked)) - - self.xmpp.register_handler( - Callback('Unblocked Contact', - StanzaPath('iq@type=set/unblock'), - self._handle_unblocked)) - - def plugin_end(self): - self.xmpp.remove_handler('Blocked Contact') - self.xmpp.remove_handler('Unblocked Contact') - - def get_blocked(self, ifrom=None, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['from'] = ifrom - iq.enable('blocklist') - return iq.send(block=block, timeout=timeout, callback=callback) - - def block(self, jids, ifrom=None, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - - if not isinstance(jids, (set, list)): - jids = [jids] - - iq['block']['items'] = jids - return iq.send(block=block, timeout=timeout, callback=callback) - - def unblock(self, jids=None, ifrom=None, block=True, timeout=None, callback=None): - iq = self.xmpp.Iq() - iq['type'] = 'set' - iq['from'] = ifrom - - if jids is None: - jids = [] - if not isinstance(jids, (set, list)): - jids = [jids] - - iq['unblock']['items'] = jids - return iq.send(block=block, timeout=timeout, callback=callback) - - def _handle_blocked(self, iq): - self.xmpp.event('blocked', iq) - - def _handle_unblocked(self, iq): - self.xmpp.event('unblocked', iq) diff --git a/sleekxmpp/plugins/xep_0191/stanza.py b/sleekxmpp/plugins/xep_0191/stanza.py deleted file mode 100644 index c5a284bd..00000000 --- a/sleekxmpp/plugins/xep_0191/stanza.py +++ /dev/null @@ -1,50 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ET, ElementBase, JID - - -class BlockList(ElementBase): - name = 'blocklist' - namespace = 'urn:xmpp:blocking' - plugin_attrib = 'blocklist' - interfaces = set(['items']) - - def get_items(self): - result = set() - items = self.xml.findall('{%s}item' % self.namespace) - if items is not None: - for item in items: - jid = JID(item.attrib.get('jid', '')) - if jid: - result.add(jid) - return result - - def set_items(self, values): - self.del_items() - for jid in values: - if jid: - item = ET.Element('{%s}item' % self.namespace) - item.attrib['jid'] = JID(jid).full - self.xml.append(item) - - def del_items(self): - items = self.xml.findall('{%s}item' % self.namespace) - if items is not None: - for item in items: - self.xml.remove(item) - - -class Block(BlockList): - name = 'block' - plugin_attrib = 'block' - - -class Unblock(BlockList): - name = 'unblock' - plugin_attrib = 'unblock' diff --git a/sleekxmpp/plugins/xep_0196/__init__.py b/sleekxmpp/plugins/xep_0196/__init__.py deleted file mode 100644 index 7aeaf6c9..00000000 --- a/sleekxmpp/plugins/xep_0196/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0196 import stanza -from sleekxmpp.plugins.xep_0196.stanza import UserGaming -from sleekxmpp.plugins.xep_0196.user_gaming import XEP_0196 - - -register_plugin(XEP_0196) diff --git a/sleekxmpp/plugins/xep_0196/stanza.py b/sleekxmpp/plugins/xep_0196/stanza.py deleted file mode 100644 index 571c89d7..00000000 --- a/sleekxmpp/plugins/xep_0196/stanza.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.xmlstream import ElementBase, ET - - -class UserGaming(ElementBase): - - name = 'gaming' - namespace = 'urn:xmpp:gaming:0' - plugin_attrib = 'gaming' - interfaces = set(['character_name', 'character_profile', 'name', - 'level', 'server_address', 'server_name', 'uri']) - sub_interfaces = interfaces - diff --git a/sleekxmpp/plugins/xep_0196/user_gaming.py b/sleekxmpp/plugins/xep_0196/user_gaming.py deleted file mode 100644 index e78f1acc..00000000 --- a/sleekxmpp/plugins/xep_0196/user_gaming.py +++ /dev/null @@ -1,97 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging - -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0196 import stanza, UserGaming - - -log = logging.getLogger(__name__) - - -class XEP_0196(BasePlugin): - - """ - XEP-0196: User Gaming - """ - - name = 'xep_0196' - description = 'XEP-0196: User Gaming' - dependencies = set(['xep_0163']) - stanza = stanza - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=UserGaming.namespace) - self.xmpp['xep_0163'].remove_interest(UserGaming.namespace) - - def session_bind(self, jid): - self.xmpp['xep_0163'].register_pep('user_gaming', UserGaming) - - def publish_gaming(self, name=None, level=None, server_name=None, uri=None, - character_name=None, character_profile=None, server_address=None, - options=None, ifrom=None, block=True, callback=None, timeout=None): - """ - Publish the user's current gaming status. - - Arguments: - name -- The name of the game. - level -- The user's level in the game. - uri -- A URI for the game or relevant gaming service - server_name -- The name of the server where the user is playing. - server_address -- The hostname or IP address of the server where the - user is playing. - character_name -- The name of the user's character in the game. - character_profile -- A URI for a profile of the user's character. - options -- Optional form of publish options. - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - gaming = UserGaming() - gaming['name'] = name - gaming['level'] = level - gaming['uri'] = uri - gaming['character_name'] = character_name - gaming['character_profile'] = character_profile - gaming['server_name'] = server_name - gaming['server_address'] = server_address - return self.xmpp['xep_0163'].publish(gaming, - node=UserGaming.namespace, - options=options, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) - - def stop(self, ifrom=None, block=True, callback=None, timeout=None): - """ - Clear existing user gaming information to stop notifications. - - Arguments: - ifrom -- Specify the sender's JID. - block -- Specify if the send call will block until a response - is received, or a timeout occurs. Defaults to True. - timeout -- The length of time (in seconds) to wait for a response - before exiting the send call if blocking is used. - Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT - callback -- Optional reference to a stream handler function. Will - be executed when a reply stanza is received. - """ - gaming = UserGaming() - return self.xmpp['xep_0163'].publish(gaming, - node=UserGaming.namespace, - ifrom=ifrom, - block=block, - callback=callback, - timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0198/__init__.py b/sleekxmpp/plugins/xep_0198/__init__.py deleted file mode 100644 index db930347..00000000 --- a/sleekxmpp/plugins/xep_0198/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0198.stanza import Enable, Enabled -from sleekxmpp.plugins.xep_0198.stanza import Resume, Resumed -from sleekxmpp.plugins.xep_0198.stanza import Failed -from sleekxmpp.plugins.xep_0198.stanza import StreamManagement -from sleekxmpp.plugins.xep_0198.stanza import Ack, RequestAck - -from sleekxmpp.plugins.xep_0198.stream_management import XEP_0198 - - -register_plugin(XEP_0198) diff --git a/sleekxmpp/plugins/xep_0198/stanza.py b/sleekxmpp/plugins/xep_0198/stanza.py deleted file mode 100644 index 6461d766..00000000 --- a/sleekxmpp/plugins/xep_0198/stanza.py +++ /dev/null @@ -1,150 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.stanza import Error -from sleekxmpp.xmlstream import ElementBase, StanzaBase - - -class Enable(StanzaBase): - name = 'enable' - namespace = 'urn:xmpp:sm:3' - interfaces = set(['max', 'resume']) - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_resume(self): - return self._get_attr('resume', 'false').lower() in ('true', '1') - - def set_resume(self, val): - self._del_attr('resume') - self._set_attr('resume', 'true' if val else 'false') - - -class Enabled(StanzaBase): - name = 'enabled' - namespace = 'urn:xmpp:sm:3' - interfaces = set(['id', 'location', 'max', 'resume']) - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_resume(self): - return self._get_attr('resume', 'false').lower() in ('true', '1') - - def set_resume(self, val): - self._del_attr('resume') - self._set_attr('resume', 'true' if val else 'false') - - -class Resume(StanzaBase): - name = 'resume' - namespace = 'urn:xmpp:sm:3' - interfaces = set(['h', 'previd']) - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_h(self): - h = self._get_attr('h', None) - if h: - return int(h) - return None - - def set_h(self, val): - self._set_attr('h', str(val)) - - -class Resumed(StanzaBase): - name = 'resumed' - namespace = 'urn:xmpp:sm:3' - interfaces = set(['h', 'previd']) - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_h(self): - h = self._get_attr('h', None) - if h: - return int(h) - return None - - def set_h(self, val): - self._set_attr('h', str(val)) - - -class Failed(StanzaBase, Error): - name = 'failed' - namespace = 'urn:xmpp:sm:3' - interfaces = set() - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - -class StreamManagement(ElementBase): - name = 'sm' - namespace = 'urn:xmpp:sm:3' - plugin_attrib = name - interfaces = set(['required', 'optional']) - - def get_required(self): - return self.find('{%s}required' % self.namespace) is not None - - def set_required(self, val): - self.del_required() - if val: - self._set_sub_text('required', '', keep=True) - - def del_required(self): - self._del_sub('required') - - def get_optional(self): - return self.find('{%s}optional' % self.namespace) is not None - - def set_optional(self, val): - self.del_optional() - if val: - self._set_sub_text('optional', '', keep=True) - - def del_optional(self): - self._del_sub('optional') - - -class RequestAck(StanzaBase): - name = 'r' - namespace = 'urn:xmpp:sm:3' - interfaces = set() - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - -class Ack(StanzaBase): - name = 'a' - namespace = 'urn:xmpp:sm:3' - interfaces = set(['h']) - - def setup(self, xml): - StanzaBase.setup(self, xml) - self.xml.tag = self.tag_name() - - def get_h(self): - h = self._get_attr('h', None) - if h: - return int(h) - return None - - def set_h(self, val): - self._set_attr('h', str(val)) diff --git a/sleekxmpp/plugins/xep_0198/stream_management.py b/sleekxmpp/plugins/xep_0198/stream_management.py deleted file mode 100644 index 48029913..00000000 --- a/sleekxmpp/plugins/xep_0198/stream_management.py +++ /dev/null @@ -1,314 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging -import threading -import collections - -from sleekxmpp.stanza import Message, Presence, Iq, StreamFeatures -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.handler import Callback, Waiter -from sleekxmpp.xmlstream.matcher import MatchXPath, MatchMany -from sleekxmpp.plugins.base import BasePlugin -from sleekxmpp.plugins.xep_0198 import stanza - - -log = logging.getLogger(__name__) - - -MAX_SEQ = 2 ** 32 - - -class XEP_0198(BasePlugin): - - """ - XEP-0198: Stream Management - """ - - name = 'xep_0198' - description = 'XEP-0198: Stream Management' - dependencies = set() - stanza = stanza - default_config = { - #: The last ack number received from the server. - 'last_ack': 0, - - #: The number of stanzas to wait between sending ack requests to - #: the server. Setting this to ``1`` will send an ack request after - #: every sent stanza. Defaults to ``5``. - 'window': 5, - - #: The stream management ID for the stream. Knowing this value is - #: required in order to do stream resumption. - 'sm_id': None, - - #: A counter of handled incoming stanzas, mod 2^32. - 'handled': 0, - - #: A counter of unacked outgoing stanzas, mod 2^32. - 'seq': 0, - - #: Control whether or not the ability to resume the stream will be - #: requested when enabling stream management. Defaults to ``True``. - 'allow_resume': True, - - 'order': 10100, - 'resume_order': 9000 - } - - def plugin_init(self): - """Start the XEP-0198 plugin.""" - - # Only enable stream management for non-components, - # since components do not yet perform feature negotiation. - if self.xmpp.is_component: - return - - self.window_counter = self.window - self.window_counter_lock = threading.Lock() - - self.enabled = threading.Event() - self.unacked_queue = collections.deque() - - self.seq_lock = threading.Lock() - self.handled_lock = threading.Lock() - self.ack_lock = threading.Lock() - - register_stanza_plugin(StreamFeatures, stanza.StreamManagement) - self.xmpp.register_stanza(stanza.Enable) - self.xmpp.register_stanza(stanza.Enabled) - self.xmpp.register_stanza(stanza.Resume) - self.xmpp.register_stanza(stanza.Resumed) - self.xmpp.register_stanza(stanza.Ack) - self.xmpp.register_stanza(stanza.RequestAck) - - # Only end the session when a element is sent, - # not just because the connection has died. - self.xmpp.end_session_on_disconnect = False - - # Register the feature twice because it may be ordered two - # different ways: enabling after binding and resumption - # before binding. - self.xmpp.register_feature('sm', - self._handle_sm_feature, - restart=True, - order=self.order) - self.xmpp.register_feature('sm', - self._handle_sm_feature, - restart=True, - order=self.resume_order) - - self.xmpp.register_handler( - Callback('Stream Management Enabled', - MatchXPath(stanza.Enabled.tag_name()), - self._handle_enabled, - instream=True)) - - self.xmpp.register_handler( - Callback('Stream Management Resumed', - MatchXPath(stanza.Resumed.tag_name()), - self._handle_resumed, - instream=True)) - - self.xmpp.register_handler( - Callback('Stream Management Failed', - MatchXPath(stanza.Failed.tag_name()), - self._handle_failed, - instream=True)) - - self.xmpp.register_handler( - Callback('Stream Management Ack', - MatchXPath(stanza.Ack.tag_name()), - self._handle_ack, - instream=True)) - - self.xmpp.register_handler( - Callback('Stream Management Request Ack', - MatchXPath(stanza.RequestAck.tag_name()), - self._handle_request_ack, - instream=True)) - - self.xmpp.add_filter('in', self._handle_incoming) - self.xmpp.add_filter('out_sync', self._handle_outgoing) - - self.xmpp.add_event_handler('session_end', self.session_end) - - def plugin_end(self): - if self.xmpp.is_component: - return - - self.xmpp.unregister_feature('sm', self.order) - self.xmpp.unregister_feature('sm', self.resume_order) - self.xmpp.del_event_handler('session_end', self.session_end) - self.xmpp.del_filter('in', self._handle_incoming) - self.xmpp.del_filter('out_sync', self._handle_outgoing) - self.xmpp.remove_handler('Stream Management Enabled') - self.xmpp.remove_handler('Stream Management Resumed') - self.xmpp.remove_handler('Stream Management Failed') - self.xmpp.remove_handler('Stream Management Ack') - self.xmpp.remove_handler('Stream Management Request Ack') - self.xmpp.remove_stanza(stanza.Enable) - self.xmpp.remove_stanza(stanza.Enabled) - self.xmpp.remove_stanza(stanza.Resume) - self.xmpp.remove_stanza(stanza.Resumed) - self.xmpp.remove_stanza(stanza.Ack) - self.xmpp.remove_stanza(stanza.RequestAck) - - def session_end(self, event): - """Reset stream management state.""" - self.enabled.clear() - self.unacked_queue.clear() - self.sm_id = None - self.handled = 0 - self.seq = 0 - self.last_ack = 0 - - def send_ack(self): - """Send the current ack count to the server.""" - ack = stanza.Ack(self.xmpp) - with self.handled_lock: - ack['h'] = self.handled - self.xmpp.send_raw(str(ack), now=True) - - def request_ack(self, e=None): - """Request an ack from the server.""" - req = stanza.RequestAck(self.xmpp) - self.xmpp.send_queue.put(str(req)) - - def _handle_sm_feature(self, features): - """ - Enable or resume stream management. - - If no SM-ID is stored, and resource binding has taken place, - stream management will be enabled. - - If an SM-ID is known, and the server allows resumption, the - previous stream will be resumed. - """ - if 'stream_management' in self.xmpp.features: - # We've already negotiated stream management, - # so no need to do it again. - return False - if not self.sm_id: - if 'bind' in self.xmpp.features: - self.enabled.set() - enable = stanza.Enable(self.xmpp) - enable['resume'] = self.allow_resume - enable.send(now=True) - self.handled = 0 - elif self.sm_id and self.allow_resume: - self.enabled.set() - resume = stanza.Resume(self.xmpp) - resume['h'] = self.handled - resume['previd'] = self.sm_id - resume.send(now=True) - - # Wait for a response before allowing stream feature processing - # to continue. The actual result processing will be done in the - # _handle_resumed() or _handle_failed() methods. - waiter = Waiter('resumed_or_failed', - MatchMany([ - MatchXPath(stanza.Resumed.tag_name()), - MatchXPath(stanza.Failed.tag_name())])) - self.xmpp.register_handler(waiter) - result = waiter.wait() - if result is not None and result.name == 'resumed': - return True - return False - - def _handle_enabled(self, stanza): - """Save the SM-ID, if provided. - - Raises an :term:`sm_enabled` event. - """ - self.xmpp.features.add('stream_management') - if stanza['id']: - self.sm_id = stanza['id'] - self.xmpp.event('sm_enabled', stanza) - - def _handle_resumed(self, stanza): - """Finish resuming a stream by resending unacked stanzas. - - Raises a :term:`session_resumed` event. - """ - self.xmpp.features.add('stream_management') - self._handle_ack(stanza) - for id, stanza in self.unacked_queue: - self.xmpp.send(stanza, now=True, use_filters=False) - self.xmpp.session_started_event.set() - self.xmpp.event('session_resumed', stanza) - - def _handle_failed(self, stanza): - """ - Disable and reset any features used since stream management was - requested (tracked stanzas may have been sent during the interval - between the enable request and the enabled response). - - Raises an :term:`sm_failed` event. - """ - self.enabled.clear() - self.unacked_queue.clear() - self.xmpp.event('sm_failed', stanza) - - def _handle_ack(self, ack): - """Process a server ack by freeing acked stanzas from the queue. - - Raises a :term:`stanza_acked` event for each acked stanza. - """ - if ack['h'] == self.last_ack: - return - - with self.ack_lock: - num_acked = (ack['h'] - self.last_ack) % MAX_SEQ - num_unacked = len(self.unacked_queue) - log.debug("Ack: %s, Last Ack: %s, " + \ - "Unacked: %s, Num Acked: %s, " + \ - "Remaining: %s", - ack['h'], - self.last_ack, - num_unacked, - num_acked, - num_unacked - num_acked) - for x in range(num_acked): - seq, stanza = self.unacked_queue.popleft() - self.xmpp.event('stanza_acked', stanza) - self.last_ack = ack['h'] - - def _handle_request_ack(self, req): - """Handle an ack request by sending an ack.""" - self.send_ack() - - def _handle_incoming(self, stanza): - """Increment the handled counter for each inbound stanza.""" - if not self.enabled.is_set(): - return stanza - - if isinstance(stanza, (Message, Presence, Iq)): - with self.handled_lock: - # Sequence numbers are mod 2^32 - self.handled = (self.handled + 1) % MAX_SEQ - return stanza - - def _handle_outgoing(self, stanza): - """Store outgoing stanzas in a queue to be acked.""" - if not self.enabled.is_set(): - return stanza - - if isinstance(stanza, (Message, Presence, Iq)): - seq = None - with self.seq_lock: - # Sequence numbers are mod 2^32 - self.seq = (self.seq + 1) % MAX_SEQ - seq = self.seq - self.unacked_queue.append((seq, stanza)) - with self.window_counter_lock: - self.window_counter -= 1 - if self.window_counter == 0: - self.window_counter = self.window - self.request_ack() - return stanza diff --git a/sleekxmpp/plugins/xep_0199/__init__.py b/sleekxmpp/plugins/xep_0199/__init__.py deleted file mode 100644 index 5231a5b5..00000000 --- a/sleekxmpp/plugins/xep_0199/__init__.py +++ /dev/null @@ -1,20 +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. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0199.stanza import Ping -from sleekxmpp.plugins.xep_0199.ping import XEP_0199 - - -register_plugin(XEP_0199) - - -# Backwards compatibility for names -xep_0199 = XEP_0199 -xep_0199.sendPing = xep_0199.send_ping diff --git a/sleekxmpp/plugins/xep_0199/ping.py b/sleekxmpp/plugins/xep_0199/ping.py deleted file mode 100644 index 836ff4ae..00000000 --- a/sleekxmpp/plugins/xep_0199/ping.py +++ /dev/null @@ -1,186 +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 time -import logging - -from sleekxmpp.jid import JID -from sleekxmpp.stanza import Iq -from sleekxmpp.exceptions import IqError, IqTimeout -from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.matcher import StanzaPath -from sleekxmpp.xmlstream.handler import Callback -from sleekxmpp.plugins import BasePlugin -from sleekxmpp.plugins.xep_0199 import stanza, Ping - - -log = logging.getLogger(__name__) - - -class XEP_0199(BasePlugin): - - """ - XEP-0199: XMPP Ping - - Given that XMPP is based on TCP connections, it is possible for the - underlying connection to be terminated without the application's - awareness. Ping stanzas provide an alternative to whitespace based - keepalive methods for detecting lost connections. - - Also see . - - Attributes: - keepalive -- If True, periodically send ping requests - to the server. If a ping is not answered, - the connection will be reset. - interval -- Time in seconds between keepalive pings. - Defaults to 300 seconds. - timeout -- Time in seconds to wait for a ping response. - Defaults to 30 seconds. - Methods: - send_ping -- Send a ping to a given JID, returning the - round trip time. - """ - - name = 'xep_0199' - description = 'XEP-0199: XMPP Ping' - dependencies = set(['xep_0030']) - stanza = stanza - default_config = { - 'keepalive': False, - 'interval': 300, - 'timeout': 30 - } - - def plugin_init(self): - """ - Start the XEP-0199 plugin. - """ - - register_stanza_plugin(Iq, Ping) - - self.xmpp.register_handler( - Callback('Ping', - StanzaPath('iq@type=get/ping'), - self._handle_ping)) - - if self.keepalive: - self.xmpp.add_event_handler('session_start', - self.enable_keepalive, - threaded=True) - self.xmpp.add_event_handler('session_end', - self.disable_keepalive) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature=Ping.namespace) - self.xmpp.remove_handler('Ping') - if self.keepalive: - self.xmpp.del_event_handler('session_start', - self.enable_keepalive) - self.xmpp.del_event_handler('session_end', - self.disable_keepalive) - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature(Ping.namespace) - - def enable_keepalive(self, interval=None, timeout=None): - if interval: - self.interval = interval - if timeout: - self.timeout = timeout - - self.keepalive = True - self.xmpp.schedule('Ping keepalive', - self.interval, - self._keepalive, - repeat=True) - - def disable_keepalive(self, event=None): - self.xmpp.scheduler.remove('Ping keepalive') - - def _keepalive(self, event=None): - log.debug("Keepalive ping...") - try: - rtt = self.ping(self.xmpp.boundjid.host, timeout=self.timeout) - except IqTimeout: - log.debug("Did not recieve ping back in time." + \ - "Requesting Reconnect.") - self.xmpp.reconnect() - else: - log.debug('Keepalive RTT: %s' % rtt) - - def _handle_ping(self, iq): - """Automatically reply to ping requests.""" - log.debug("Pinged by %s", iq['from']) - iq.reply().send() - - def send_ping(self, jid, ifrom=None, block=True, timeout=None, callback=None): - """Send a ping request. - - Arguments: - jid -- The JID that will receive the ping. - ifrom -- Specifiy the sender JID. - block -- Indicate if execution should block until - a pong response is received. Defaults - to True. - timeout -- Time in seconds to wait for a response. - Defaults to self.timeout. - callback -- Optional handler to execute when a pong - is received. Useful in conjunction with - the option block=False. - """ - if not timeout: - timeout = self.timeout - - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['to'] = jid - iq['from'] = ifrom - iq.enable('ping') - - return iq.send(block=block, timeout=timeout, callback=callback) - - def ping(self, jid=None, ifrom=None, timeout=None): - """Send a ping request and calculate RTT. - - Arguments: - jid -- The JID that will receive the ping. - ifrom -- Specifiy the sender JID. - timeout -- Time in seconds to wait for a response. - Defaults to self.timeout. - """ - own_host = False - if not jid: - if self.xmpp.is_component: - jid = self.xmpp.server - else: - jid = self.xmpp.boundjid.host - jid = JID(jid) - if jid == self.xmpp.boundjid.host or \ - self.xmpp.is_component and jid == self.xmpp.server: - own_host = True - - if not timeout: - timeout = self.timeout - - start = time.time() - - log.debug('Pinging %s' % jid) - try: - self.send_ping(jid, ifrom=ifrom, timeout=timeout) - except IqError as e: - if own_host: - rtt = time.time() - start - log.debug('Pinged %s, RTT: %s', jid, rtt) - return rtt - else: - raise e - else: - rtt = time.time() - start - log.debug('Pinged %s, RTT: %s', jid, rtt) - return rtt diff --git a/sleekxmpp/plugins/xep_0199/stanza.py b/sleekxmpp/plugins/xep_0199/stanza.py deleted file mode 100644 index 6586a763..00000000 --- a/sleekxmpp/plugins/xep_0199/stanza.py +++ /dev/null @@ -1,36 +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 sleekxmpp -from sleekxmpp.xmlstream import ElementBase - - -class Ping(ElementBase): - - """ - Given that XMPP is based on TCP connections, it is possible for the - underlying connection to be terminated without the application's - awareness. Ping stanzas provide an alternative to whitespace based - keepalive methods for detecting lost connections. - - Example ping stanza: - - - - - Stanza Interface: - None - - Methods: - None - """ - - name = 'ping' - namespace = 'urn:xmpp:ping' - plugin_attrib = 'ping' - interfaces = set() diff --git a/sleekxmpp/plugins/xep_0202/__init__.py b/sleekxmpp/plugins/xep_0202/__init__.py deleted file mode 100644 index cdab3665..00000000 --- a/sleekxmpp/plugins/xep_0202/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -from sleekxmpp.plugins.base import register_plugin - -from sleekxmpp.plugins.xep_0202 import stanza -from sleekxmpp.plugins.xep_0202.stanza import EntityTime -from sleekxmpp.plugins.xep_0202.time import XEP_0202 - - -register_plugin(XEP_0202) - - -# Retain some backwards compatibility -xep_0202 = XEP_0202 diff --git a/sleekxmpp/plugins/xep_0202/stanza.py b/sleekxmpp/plugins/xep_0202/stanza.py deleted file mode 100644 index b6ccc960..00000000 --- a/sleekxmpp/plugins/xep_0202/stanza.py +++ /dev/null @@ -1,127 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - -import logging -import datetime as dt - -from sleekxmpp.xmlstream import ElementBase -from sleekxmpp.plugins import xep_0082 -from sleekxmpp.thirdparty import tzutc, tzoffset - - -class EntityTime(ElementBase): - - """ - The