Compare commits
366 Commits
1.2.5
...
slix-1.2.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
36824379c3 | ||
![]() |
a0a37c19ff | ||
![]() |
1b5fe57a5e | ||
![]() |
5da31db0c7 | ||
![]() |
f8cea760b6 | ||
![]() |
5ef01ecdd1 | ||
![]() |
62aafe0ee7 | ||
![]() |
cf3f36ac52 | ||
![]() |
b88d2ecd77 | ||
![]() |
e691850a2b | ||
![]() |
d4bff8dee6 | ||
![]() |
187c350805 | ||
![]() |
96d1c26f90 | ||
![]() |
46a90749f8 | ||
![]() |
0c63a4bbda | ||
![]() |
e4696e0471 | ||
![]() |
8217dc5239 | ||
![]() |
2586abc0d3 | ||
![]() |
28f84ab3d9 | ||
![]() |
813b45aded | ||
![]() |
3a9b45e4f2 | ||
![]() |
b8e091233e | ||
![]() |
0edeefd977 | ||
![]() |
6ba53cf1ff | ||
![]() |
d7758eb7f4 | ||
![]() |
125336aeee | ||
![]() |
7cd1cf32ae | ||
![]() |
d099e353a4 | ||
![]() |
1e4a301c6e | ||
![]() |
f53b12d227 | ||
![]() |
e2562dcccf | ||
![]() |
7b69ae3738 | ||
![]() |
ab6df235d7 | ||
![]() |
52cd8f4b22 | ||
![]() |
e28318c271 | ||
![]() |
39ee833c29 | ||
![]() |
9019e2bc71 | ||
![]() |
9208bf5bf1 | ||
![]() |
f0f1698e46 | ||
![]() |
eccd7f1c98 | ||
![]() |
2587d82af8 | ||
![]() |
7ea121b115 | ||
![]() |
bb81fbbdfc | ||
![]() |
1a00a08b7d | ||
![]() |
90ea2a3411 | ||
![]() |
8fc6814b6d | ||
![]() |
ffced0ed9a | ||
![]() |
e7248d9af9 | ||
![]() |
6b1a04f59d | ||
![]() |
4905407092 | ||
![]() |
bd6ec10939 | ||
![]() |
e15e6735f1 | ||
![]() |
67afd6a462 | ||
![]() |
2e2b97c53b | ||
![]() |
a35df7fe1f | ||
![]() |
fbc8562779 | ||
![]() |
b549db959a | ||
![]() |
d5188ac68a | ||
![]() |
ada9444bf8 | ||
![]() |
acc52fd935 | ||
![]() |
1100ff1feb | ||
![]() |
c17fc3a869 | ||
![]() |
4dba697075 | ||
![]() |
e42d651d7e | ||
![]() |
4305eddb4f | ||
![]() |
c2dc44cfd1 | ||
![]() |
5fc14de32e | ||
![]() |
d245558fd5 | ||
![]() |
9d45370e8a | ||
![]() |
cc1cc61d36 | ||
![]() |
c6740a4908 | ||
![]() |
55114bcffe | ||
![]() |
4fa5dedc47 | ||
![]() |
5525ef2285 | ||
![]() |
a7ac969215 | ||
![]() |
329cb5a9f8 | ||
![]() |
d9b47b33f5 | ||
![]() |
3582ac9941 | ||
![]() |
2a127a57a7 | ||
![]() |
7059400020 | ||
![]() |
0b14ef82d4 | ||
![]() |
83953af53d | ||
![]() |
110cf25c6d | ||
![]() |
f2bf6072ec | ||
![]() |
5f9abe2e0e | ||
![]() |
ea65b672e7 | ||
![]() |
93c705fb31 | ||
![]() |
0724f623bb | ||
![]() |
82e549c0e9 | ||
![]() |
1aa15792b4 | ||
![]() |
ffb2b6bc04 | ||
![]() |
27f98bf22c | ||
![]() |
3978078710 | ||
![]() |
00a0698720 | ||
![]() |
4a24f58be2 | ||
![]() |
da14ce16ec | ||
![]() |
18e5abb9dd | ||
![]() |
1a75b76916 | ||
![]() |
53b56899a0 | ||
![]() |
804b23d390 | ||
![]() |
04eaf52b1d | ||
![]() |
dc7fef1064 | ||
![]() |
488c433555 | ||
![]() |
9c5dd024b1 | ||
![]() |
6e61adf3db | ||
![]() |
041bd63864 | ||
![]() |
a366482551 | ||
![]() |
a721084f6e | ||
![]() |
1b4187fa56 | ||
![]() |
cf7a60705e | ||
![]() |
349b05b9b7 | ||
![]() |
9fbacf377a | ||
![]() |
2da9e35cbc | ||
![]() |
8adc8fa2ba | ||
![]() |
9efa909dfc | ||
![]() |
7f21fdbe26 | ||
![]() |
f9c7fa92ea | ||
![]() |
e75a160d52 | ||
![]() |
170bd51387 | ||
![]() |
abcec1e2d3 | ||
![]() |
eeab646bfa | ||
![]() |
2c69144189 | ||
![]() |
f54ebec654 | ||
![]() |
2ce931cb7a | ||
![]() |
84eddd2ed2 | ||
![]() |
2042e1a4d5 | ||
![]() |
be14f0cc52 | ||
![]() |
edd9199be8 | ||
![]() |
bb094cc649 | ||
![]() |
dbaa6ed952 | ||
![]() |
8c94d894ab | ||
![]() |
ffc7eac4dc | ||
![]() |
555fd6d926 | ||
![]() |
c024ac8f0b | ||
![]() |
f00177c0cf | ||
![]() |
d0ad25745a | ||
![]() |
55be23a6da | ||
![]() |
75ba283572 | ||
![]() |
f7164d35d2 | ||
![]() |
4afbb0322b | ||
![]() |
7bce1ecc8a | ||
![]() |
bbce16d526 | ||
![]() |
c29fc39ef1 | ||
![]() |
8335c08782 | ||
![]() |
224d7ae133 | ||
![]() |
04bff00171 | ||
![]() |
f3e31baf04 | ||
![]() |
9b25a7cf77 | ||
![]() |
7a908ac07b | ||
![]() |
92901637ec | ||
![]() |
3590b663ed | ||
![]() |
a33bde9cc3 | ||
![]() |
ac50fdccfc | ||
![]() |
a0c6bf15e9 | ||
![]() |
a2852eb249 | ||
![]() |
f1e6d6b0a9 | ||
![]() |
116a33ba51 | ||
![]() |
a8ac115310 | ||
![]() |
1345b7c1d0 | ||
![]() |
d60a652259 | ||
![]() |
61a7cecb31 | ||
![]() |
192b7e0349 | ||
![]() |
80b60fc048 | ||
![]() |
b8d7b9520c | ||
![]() |
0305ce66b7 | ||
![]() |
474405ab90 | ||
![]() |
4415d3be1a | ||
![]() |
058c530787 | ||
![]() |
766d0dfd40 | ||
![]() |
ac31913a65 | ||
![]() |
d34ddf33db | ||
![]() |
eb4e09b0ca | ||
![]() |
ce085bf4f4 | ||
![]() |
990113f8e7 | ||
![]() |
aa022204ee | ||
![]() |
c1f23b566b | ||
![]() |
45f7cb8bda | ||
![]() |
bdb1f66ac9 | ||
![]() |
842157a6cc | ||
![]() |
a63cc01482 | ||
![]() |
1bbb6f3ff9 | ||
![]() |
93894247a4 | ||
![]() |
16bb5e2537 | ||
![]() |
d19a6e05b2 | ||
![]() |
86e85f9835 | ||
![]() |
cc145d20b0 | ||
![]() |
881d9040c4 | ||
![]() |
1e77ea0944 | ||
![]() |
140f0885b2 | ||
![]() |
83f71a6610 | ||
![]() |
271343a32d | ||
![]() |
48857b0030 | ||
![]() |
1fe7f5f4e6 | ||
![]() |
d5b1904ebb | ||
![]() |
b6b0e82dec | ||
![]() |
632b7b4afe | ||
![]() |
81b7b2c190 | ||
![]() |
460de7d301 | ||
![]() |
69022c6db7 | ||
![]() |
0ef3fa2703 | ||
![]() |
8da269de88 | ||
![]() |
93ce318259 | ||
![]() |
997928de91 | ||
![]() |
83d00a5913 | ||
![]() |
bf5d7c83af | ||
![]() |
c66a4d4097 | ||
![]() |
e112e86475 | ||
![]() |
e034b31d6b | ||
![]() |
18a4978456 | ||
![]() |
17464b10a4 | ||
![]() |
6fb3ecd414 | ||
![]() |
c214e4f037 | ||
![]() |
2ee05d9616 | ||
![]() |
f795ac02e3 | ||
![]() |
6e8235544c | ||
![]() |
6e35948276 | ||
![]() |
4da870fd19 | ||
![]() |
cd7ff685fb | ||
![]() |
1e4944d47e | ||
![]() |
e68135f59f | ||
![]() |
6408c5a747 | ||
![]() |
115fe954ac | ||
![]() |
3d243f7da5 | ||
![]() |
ea5615f236 | ||
![]() |
69da1c1d7c | ||
![]() |
e85fa4203e | ||
![]() |
506ca69917 | ||
![]() |
8ac0ecdf40 | ||
![]() |
dbd8115557 | ||
![]() |
74b4ea20bf | ||
![]() |
11fbaa4241 | ||
![]() |
8fd0d7c993 | ||
![]() |
1450d36377 | ||
![]() |
06358d0665 | ||
![]() |
2b3b86e281 | ||
![]() |
92e4bc752a | ||
![]() |
ffb2e05f21 | ||
![]() |
1e2665df19 | ||
![]() |
4d063e287e | ||
![]() |
44f02fb3ab | ||
![]() |
f6b3a0c6cf | ||
![]() |
8b36e918e8 | ||
![]() |
9044807121 | ||
![]() |
24264d3a07 | ||
![]() |
8bc70264ef | ||
![]() |
957c635fb7 | ||
![]() |
4027927c6e | ||
![]() |
c16b862200 | ||
![]() |
a96f608469 | ||
![]() |
e1f25604ec | ||
![]() |
0fe057b5c3 | ||
![]() |
be76dda21d | ||
![]() |
ecd124dd06 | ||
![]() |
4a8951c4ee | ||
![]() |
8afba7de85 | ||
![]() |
1ce42d3a2f | ||
![]() |
2f4d811db4 | ||
![]() |
61127f521d | ||
![]() |
62eefdbd6a | ||
![]() |
225e07eb64 | ||
![]() |
1207c81ab5 | ||
![]() |
565da65ccd | ||
![]() |
47fbd4cead | ||
![]() |
1b9b4199e8 | ||
![]() |
b5930ca958 | ||
![]() |
063e73c0d2 | ||
![]() |
423974f90d | ||
![]() |
d261318e1a | ||
![]() |
d33cc00fe9 | ||
![]() |
5fcf08a415 | ||
![]() |
3c06568ed5 | ||
![]() |
27582f6fd2 | ||
![]() |
e328ff4833 | ||
![]() |
68e35e631a | ||
![]() |
ad8c76602b | ||
![]() |
b5c98ba99e | ||
![]() |
711f8dc6af | ||
![]() |
5b41fb98de | ||
![]() |
6da625dbdb | ||
![]() |
e862c47b8b | ||
![]() |
4a8fe56470 | ||
![]() |
7c3e61950d | ||
![]() |
61f89eef2e | ||
![]() |
06de587ed2 | ||
![]() |
49beb3ac08 | ||
![]() |
403462fdb8 | ||
![]() |
f22d8e67b4 | ||
![]() |
e1c944d723 | ||
![]() |
83442b9849 | ||
![]() |
edd6ffeb01 | ||
![]() |
5a8881000c | ||
![]() |
70839368c1 | ||
![]() |
9d8a2a1a7a | ||
![]() |
17174016ec | ||
![]() |
ed37174a2b | ||
![]() |
8660148960 | ||
![]() |
67ca2dd0f4 | ||
![]() |
882f984b26 | ||
![]() |
6175cbcd99 | ||
![]() |
476d76a533 | ||
![]() |
df68bb4896 | ||
![]() |
815e647c97 | ||
![]() |
ad70ffba59 | ||
![]() |
0e95015410 | ||
![]() |
35f33f1614 | ||
![]() |
c9f8ddff65 | ||
![]() |
f5ae98aaf1 | ||
![]() |
b92dac72f3 | ||
![]() |
073e85381a | ||
![]() |
afc939708f | ||
![]() |
aabec8b993 | ||
![]() |
e5e2fbb16b | ||
![]() |
3dd379cdf1 | ||
![]() |
a20582aba4 | ||
![]() |
09cdbf1b76 | ||
![]() |
ca306e7cec | ||
![]() |
1bf34f7fe6 | ||
![]() |
4144d60017 | ||
![]() |
7265682a4d | ||
![]() |
08c62a6bf1 | ||
![]() |
d61f1cd035 | ||
![]() |
1063feb33b | ||
![]() |
79f3c1ac8f | ||
![]() |
cdb9a6ff7e | ||
![]() |
a59148dfeb | ||
![]() |
a5c03b763a | ||
![]() |
3670d82f1c | ||
![]() |
07e46837d9 | ||
![]() |
fa21e262c7 | ||
![]() |
93934c7992 | ||
![]() |
73edd42774 | ||
![]() |
ab03ad54aa | ||
![]() |
2e571ac950 | ||
![]() |
6c15d65107 | ||
![]() |
e5af0597a6 | ||
![]() |
74117453b5 | ||
![]() |
5611b30022 | ||
![]() |
ede9dcd18f | ||
![]() |
d3b56a5d94 | ||
![]() |
f5d4334963 | ||
![]() |
5c769632e8 | ||
![]() |
373505f483 | ||
![]() |
a2cad40f91 | ||
![]() |
4328762076 | ||
![]() |
c2f6f07776 | ||
![]() |
5ab77c7452 | ||
![]() |
e94a73553d | ||
![]() |
577fd71472 | ||
![]() |
e5582694c0 | ||
![]() |
768136e493 | ||
![]() |
753cb3580e | ||
![]() |
60b050b82a | ||
![]() |
ad91a8cd5e | ||
![]() |
02f79fc94b | ||
![]() |
230a73fad2 | ||
![]() |
d94dd486fe | ||
![]() |
6ecc39b816 | ||
![]() |
9c240df9db | ||
![]() |
a918bf3a95 | ||
![]() |
9434ae267f | ||
![]() |
94187d215a | ||
![]() |
ef1c4368d0 | ||
![]() |
48def71d0c | ||
![]() |
c8c20fff71 | ||
![]() |
75a18b5ffe | ||
![]() |
ea3d39b50e |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,9 +6,10 @@ docs/_build/
|
||||
*.swp
|
||||
.tox/
|
||||
.coverage
|
||||
sleekxmpp.egg-info/
|
||||
slixmpp.egg-info/
|
||||
.ropeproject/
|
||||
4913
|
||||
*~
|
||||
.baboon/
|
||||
.DS_STORE
|
||||
.idea/
|
||||
|
10
.travis.yml
Normal file
10
.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.2"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
install:
|
||||
- "pip install ."
|
||||
script: testall.py
|
14
CONTRIBUTING.rst
Normal file
14
CONTRIBUTING.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
Contributing to the Slixmpp project
|
||||
===================================
|
||||
|
||||
To contribute, the preferred way is to commit your changes on some
|
||||
publicly-available git repository (on a fork `on github
|
||||
<https://github.com/poezio/slixmpp>`_ or on your own repository) and to
|
||||
notify the developers with either:
|
||||
- a ticket `on the bug tracker <https://dev.poez.io/new>`_
|
||||
- a pull request on github
|
||||
- a simple message on `the XMPP MUC <xmpp:slixmpp@muc.poez.io>`_
|
||||
|
||||
Even though Slixmpp’s github repository is just a read-only mirror, we can
|
||||
still be notified of the pull requests and fetch your mirror manually to
|
||||
integrate your changes.
|
5
INSTALL
5
INSTALL
@@ -1,5 +1,6 @@
|
||||
Pre-requisites:
|
||||
- Python 3.1 or 2.6
|
||||
- Python 3.4
|
||||
- Cython 0.22 and libidn, optionally (making JID faster by compiling the stringprep module)
|
||||
|
||||
Install:
|
||||
> python3 setup.py install
|
||||
@@ -9,4 +10,4 @@ Root install:
|
||||
|
||||
To test:
|
||||
> cd examples
|
||||
> python echo_client.py -v -j [USER@example.com] -p [PASSWORD]
|
||||
> python3 echo_client.py -d -j [USER@example.com] -p [PASSWORD]
|
||||
|
@@ -1,6 +1,7 @@
|
||||
include README.rst
|
||||
include LICENSE
|
||||
include testall.py
|
||||
include run_tests.py
|
||||
include slixmpp/stringprep.pyx
|
||||
recursive-include docs Makefile *.bat *.py *.rst *.css *.ttf *.png
|
||||
recursive-include examples *.py
|
||||
recursive-include tests *.py
|
||||
|
126
README.rst
126
README.rst
@@ -1,77 +1,21 @@
|
||||
SleekXMPP
|
||||
Slixmpp
|
||||
#########
|
||||
|
||||
SleekXMPP is an MIT licensed XMPP library for Python 2.6/3.1+,
|
||||
and is featured in examples in
|
||||
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
|
||||
by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived
|
||||
here from reading the Definitive Guide, please see the notes on updating
|
||||
the examples to the latest version of SleekXMPP.
|
||||
Slixmpp is an MIT licensed XMPP library for Python 3.4+. It is a fork of
|
||||
SleekXMPP.
|
||||
|
||||
SleekXMPP's design goals and philosphy are:
|
||||
Slixmpp's goals is to only rewrite the core of the library (the low level
|
||||
socket handling, the timers, the events dispatching) in order to remove all
|
||||
threads.
|
||||
|
||||
**Low number of dependencies**
|
||||
Installing and using SleekXMPP should be as simple as possible, without
|
||||
having to deal with long dependency chains.
|
||||
Building
|
||||
--------
|
||||
|
||||
As part of reducing the number of dependencies, some third party
|
||||
modules are included with SleekXMPP in the ``thirdparty`` directory.
|
||||
Imports from this module first try to import an existing installed
|
||||
version before loading the packaged version, when possible.
|
||||
|
||||
**Every XEP as a plugin**
|
||||
Following Python's "batteries included" approach, the goal is to
|
||||
provide support for all currently active XEPs (final and draft). Since
|
||||
adding XEP support is done through easy to create plugins, the hope is
|
||||
to also provide a solid base for implementing and creating experimental
|
||||
XEPs.
|
||||
|
||||
**Rewarding to work with**
|
||||
As much as possible, SleekXMPP should allow things to "just work" using
|
||||
sensible defaults and appropriate abstractions. XML can be ugly to work
|
||||
with, but it doesn't have to be that way.
|
||||
|
||||
|
||||
Get the Code
|
||||
------------
|
||||
|
||||
Get the latest stable version from PyPI::
|
||||
|
||||
pip install sleekxmpp
|
||||
|
||||
The latest source code for SleekXMPP may be found on `Github
|
||||
<http://github.com/fritzy/SleekXMPP>`_. Releases can be found in the
|
||||
``master`` branch, while the latest development version is in the
|
||||
``develop`` branch.
|
||||
|
||||
**Latest Release**
|
||||
- `1.2.5 <http://github.com/fritzy/SleekXMPP/zipball/1.2.5>`_
|
||||
|
||||
**Develop Releases**
|
||||
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
|
||||
|
||||
|
||||
Installing DNSPython
|
||||
---------------------
|
||||
If you are using Python3 and wish to use dnspython, you will have to checkout and
|
||||
install the ``python3`` branch::
|
||||
|
||||
git clone http://github.com/rthalley/dnspython
|
||||
cd dnspython
|
||||
git checkout python3
|
||||
python3 setup.py install
|
||||
|
||||
Discussion
|
||||
----------
|
||||
A mailing list and XMPP chat room are available for discussing and getting
|
||||
help with SleekXMPP.
|
||||
|
||||
**Mailing List**
|
||||
`SleekXMPP Discussion on Google Groups <http://groups.google.com/group/sleekxmpp-discussion>`_
|
||||
|
||||
**Chat**
|
||||
`sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_
|
||||
Slixmpp can make use of cython to improve performance on critical modules.
|
||||
To do that, **cython3** is necessary along with **libidn** headers.
|
||||
Otherwise, no compilation is needed. Building is done by running setup.py::
|
||||
|
||||
python3 setup.py build_ext --inplace
|
||||
|
||||
Documentation and Testing
|
||||
-------------------------
|
||||
@@ -83,22 +27,22 @@ be in ``docs/_build/html``::
|
||||
make html
|
||||
open _build/html/index.html
|
||||
|
||||
To run the test suite for SleekXMPP::
|
||||
To run the test suite for Slixmpp::
|
||||
|
||||
python testall.py
|
||||
python run_tests.py
|
||||
|
||||
|
||||
The SleekXMPP Boilerplate
|
||||
The Slixmpp Boilerplate
|
||||
-------------------------
|
||||
Projects using SleekXMPP tend to follow a basic pattern for setting up client/component
|
||||
connections and configuration. Here is the gist of the boilerplate needed for a SleekXMPP
|
||||
Projects using Slixmpp tend to follow a basic pattern for setting up client/component
|
||||
connections and configuration. Here is the gist of the boilerplate needed for a Slixmpp
|
||||
based project. See the documetation or examples directory for more detailed archetypes for
|
||||
SleekXMPP projects::
|
||||
Slixmpp projects::
|
||||
|
||||
import logging
|
||||
|
||||
from sleekxmpp import ClientXMPP
|
||||
from sleekxmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp import ClientXMPP
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
|
||||
|
||||
class EchoBot(ClientXMPP):
|
||||
@@ -144,7 +88,7 @@ SleekXMPP projects::
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Ideally use optparse or argparse to get JID,
|
||||
# Ideally use optparse or argparse to get JID,
|
||||
# password, and log level.
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
@@ -152,21 +96,37 @@ SleekXMPP projects::
|
||||
|
||||
xmpp = EchoBot('somejid@example.com', 'use_getpass')
|
||||
xmpp.connect()
|
||||
xmpp.process(block=True)
|
||||
xmpp.process(forever=True)
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
Slixmpp Credits
|
||||
---------------
|
||||
|
||||
**Maintainers:**
|
||||
- Florent Le Coz (`louiz@louiz.org <xmpp:louiz@louiz.org?message>`_),
|
||||
- Mathieu Pasquet (`mathieui@mathieui.net <xmpp:mathieui@mathieui.net?message>`_),
|
||||
|
||||
**Contributors:**
|
||||
- Emmanuel Gil Peyrot (`Link mauve <xmpp:linkmauve@linkmauve.fr?message>`_)
|
||||
- Sam Whited (`Sam Whited <mailto:sam@samwhited.com>`_)
|
||||
- Dan Sully (`Dan Sully <mailto:daniel@electricalrain.com>`_)
|
||||
- Gasper Zejn (`Gasper Zejn <mailto:zejn@kiberpipa.org>`_)
|
||||
- Krzysztof Kotlenga (`Krzysztof Kotlenga <mailto:pocek@users.sf.net>`_)
|
||||
- Tsukasa Hiiragi (`Tsukasa Hiiragi <mailto:bakalolka@gmail.com>`_)
|
||||
|
||||
Credits (SleekXMPP)
|
||||
-------------------
|
||||
|
||||
**Main Author:** Nathan Fritz
|
||||
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
|
||||
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
|
||||
`@fritzy <http://twitter.com/fritzy>`_
|
||||
|
||||
Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP
|
||||
<http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of
|
||||
<http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of
|
||||
the XMPP Council.
|
||||
|
||||
**Co-Author:** Lance Stout
|
||||
`lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,
|
||||
`lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,
|
||||
`@lancestout <http://twitter.com/lancestout>`_
|
||||
|
||||
**Contributors:**
|
||||
|
@@ -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:
|
||||
|
68
docs/_static/nature.css
vendored
68
docs/_static/nature.css
vendored
@@ -8,11 +8,11 @@
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 100%;
|
||||
@@ -34,18 +34,18 @@ div.bodywrapper {
|
||||
hr {
|
||||
border: 1px solid #B1B4B6;
|
||||
}
|
||||
|
||||
|
||||
div.document {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
|
||||
div.body {
|
||||
background-color: #ffffff;
|
||||
color: #3E4349;
|
||||
padding: 0 30px 30px 30px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
||||
div.footer {
|
||||
color: #555;
|
||||
width: 100%;
|
||||
@@ -53,12 +53,12 @@ div.footer {
|
||||
text-align: center;
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
|
||||
div.footer a {
|
||||
color: #444;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
div.related {
|
||||
background-color: #6BA81E;
|
||||
line-height: 32px;
|
||||
@@ -66,11 +66,11 @@ div.related {
|
||||
text-shadow: 0px 1px 0 #444;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
||||
div.related a {
|
||||
color: #E2F3CC;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar {
|
||||
font-size: 0.75em;
|
||||
line-height: 1.5em;
|
||||
@@ -79,7 +79,7 @@ div.sphinxsidebar {
|
||||
div.sphinxsidebarwrapper{
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar h3,
|
||||
div.sphinxsidebar h4 {
|
||||
font-family: Arial, sans-serif;
|
||||
@@ -95,30 +95,30 @@ div.sphinxsidebar h4 {
|
||||
div.sphinxsidebar h4{
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
div.sphinxsidebar p {
|
||||
color: #888;
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar p.topless {
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
margin: 10px 20px;
|
||||
padding: 0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #ccc;
|
||||
font-family: sans-serif;
|
||||
@@ -128,19 +128,19 @@ div.sphinxsidebar input {
|
||||
div.sphinxsidebar input[type=text]{
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
|
||||
a {
|
||||
color: #005B81;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
a:hover {
|
||||
color: #E32E00;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3,
|
||||
@@ -155,30 +155,30 @@ div.body h6 {
|
||||
padding: 5px 0 5px 10px;
|
||||
text-shadow: 0px 1px 0 white
|
||||
}
|
||||
|
||||
|
||||
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
|
||||
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
|
||||
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
|
||||
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
|
||||
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
|
||||
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
|
||||
|
||||
|
||||
a.headerlink {
|
||||
color: #c60f0f;
|
||||
font-size: 0.8em;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #c60f0f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
|
||||
div.admonition p.admonition-title + p {
|
||||
display: inline;
|
||||
}
|
||||
@@ -191,29 +191,29 @@ div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
|
||||
div.warning {
|
||||
background-color: #ffe4e4;
|
||||
border: 1px solid #f66;
|
||||
}
|
||||
|
||||
|
||||
p.admonition-title {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
|
||||
pre {
|
||||
padding: 10px;
|
||||
background-color: White;
|
||||
@@ -225,7 +225,7 @@ pre {
|
||||
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
|
||||
-moz-box-shadow: 1px 1px 1px #d8d8d8;
|
||||
}
|
||||
|
||||
|
||||
tt {
|
||||
background-color: #ecf0f3;
|
||||
color: #222;
|
||||
|
2
docs/_static/sphinxdoc.css
vendored
2
docs/_static/sphinxdoc.css
vendored
@@ -134,7 +134,7 @@ div.footer a {
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
p {
|
||||
p {
|
||||
margin: 0.8em 0 0.5em 0;
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
BaseXMPP
|
||||
========
|
||||
|
||||
.. module:: sleekxmpp.basexmpp
|
||||
.. module:: slixmpp.basexmpp
|
||||
|
||||
.. autoclass:: BaseXMPP
|
||||
:members:
|
||||
|
@@ -2,7 +2,7 @@
|
||||
ClientXMPP
|
||||
==========
|
||||
|
||||
.. module:: sleekxmpp.clientxmpp
|
||||
.. module:: slixmpp.clientxmpp
|
||||
|
||||
.. autoclass:: ClientXMPP
|
||||
:members:
|
||||
|
@@ -2,7 +2,7 @@
|
||||
ComponentXMPP
|
||||
=============
|
||||
|
||||
.. module:: sleekxmpp.componentxmpp
|
||||
.. module:: slixmpp.componentxmpp
|
||||
|
||||
.. autoclass:: ComponentXMPP
|
||||
:members:
|
||||
|
@@ -1,9 +1,9 @@
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
.. module:: sleekxmpp.exceptions
|
||||
.. module:: slixmpp.exceptions
|
||||
|
||||
|
||||
|
||||
.. autoexception:: XMPPError
|
||||
:members:
|
||||
|
||||
|
8
docs/api/stanza/iq.rst
Normal file
8
docs/api/stanza/iq.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
IQ Stanza
|
||||
=========
|
||||
|
||||
.. module:: slixmpp.stanza
|
||||
|
||||
.. autoclass:: Iq
|
||||
:members:
|
||||
|
7
docs/api/stanza/message.rst
Normal file
7
docs/api/stanza/message.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
Message Stanza
|
||||
==============
|
||||
|
||||
.. module:: slixmpp.stanza
|
||||
|
||||
.. autoclass:: Message
|
||||
:members:
|
8
docs/api/stanza/presence.rst
Normal file
8
docs/api/stanza/presence.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Presence Stanza
|
||||
===============
|
||||
|
||||
.. module:: slixmpp.stanza
|
||||
|
||||
.. autoclass:: Presence
|
||||
:members:
|
||||
|
8
docs/api/stanza/rootstanza.rst
Normal file
8
docs/api/stanza/rootstanza.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Root Stanza
|
||||
===========
|
||||
|
||||
.. module:: slixmpp.stanza.rootstanza
|
||||
|
||||
.. autoclass:: RootStanza
|
||||
:members:
|
||||
|
@@ -1,12 +0,0 @@
|
||||
.. module:: sleekxmpp.xmlstream.filesocket
|
||||
|
||||
.. _filesocket:
|
||||
|
||||
Python 2.6 File Socket Shims
|
||||
============================
|
||||
|
||||
.. autoclass:: FileSocket
|
||||
:members:
|
||||
|
||||
.. autoclass:: Socket26
|
||||
:members:
|
@@ -3,22 +3,26 @@ Stanza Handlers
|
||||
|
||||
The Basic Handler
|
||||
-----------------
|
||||
.. module:: sleekxmpp.xmlstream.handler.base
|
||||
.. module:: slixmpp.xmlstream.handler.base
|
||||
|
||||
.. autoclass:: BaseHandler
|
||||
:members:
|
||||
|
||||
Callback
|
||||
--------
|
||||
.. module:: sleekxmpp.xmlstream.handler.callback
|
||||
.. module:: slixmpp.xmlstream.handler
|
||||
|
||||
.. autoclass:: Callback
|
||||
:members:
|
||||
|
||||
CoroutineCallback
|
||||
-----------------
|
||||
|
||||
.. autoclass:: CoroutineCallback
|
||||
:members:
|
||||
|
||||
Waiter
|
||||
------
|
||||
.. module:: sleekxmpp.xmlstream.handler.waiter
|
||||
|
||||
.. autoclass:: Waiter
|
||||
:members:
|
||||
|
@@ -1,7 +1,7 @@
|
||||
Jabber IDs (JID)
|
||||
=================
|
||||
|
||||
.. module:: sleekxmpp.xmlstream.jid
|
||||
.. module:: slixmpp.jid
|
||||
|
||||
.. autoclass:: JID
|
||||
:members:
|
||||
|
@@ -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:
|
||||
|
@@ -1,11 +0,0 @@
|
||||
=========
|
||||
Scheduler
|
||||
=========
|
||||
|
||||
.. module:: sleekxmpp.xmlstream.scheduler
|
||||
|
||||
.. autoclass:: Task
|
||||
:members:
|
||||
|
||||
.. autoclass:: Scheduler
|
||||
:members:
|
@@ -4,9 +4,9 @@
|
||||
Stanza Objects
|
||||
==============
|
||||
|
||||
.. module:: sleekxmpp.xmlstream.stanzabase
|
||||
.. module:: slixmpp.xmlstream.stanzabase
|
||||
|
||||
The :mod:`~sleekmxpp.xmlstream.stanzabase` module provides a wrapper for the
|
||||
The :mod:`~slixmpp.xmlstream.stanzabase` module provides a wrapper for the
|
||||
standard :mod:`~xml.etree.ElementTree` module that makes working with XML
|
||||
less painful. Instead of having to manually move up and down an element
|
||||
tree and insert subelements and attributes, you can interact with an object
|
||||
@@ -52,17 +52,17 @@ elements of the original XML chunk.
|
||||
.. seealso::
|
||||
:ref:`create-stanza-interfaces`.
|
||||
|
||||
Because the :mod:`~sleekxmpp.xmlstream.stanzabase` module was developed
|
||||
Because the :mod:`~slixmpp.xmlstream.stanzabase` module was developed
|
||||
as part of an `XMPP <http://xmpp.org>`_ library, these chunks of XML are
|
||||
referred to as :term:`stanzas <stanza>`, and in SleekXMPP we refer to a
|
||||
referred to as :term:`stanzas <stanza>`, and in Slixmpp we refer to a
|
||||
subclass of :class:`ElementBase` which defines the interfaces needed for
|
||||
interacting with a given :term:`stanza` a :term:`stanza object`.
|
||||
|
||||
To make dealing with more complicated and nested :term:`stanzas <stanza>`
|
||||
or XML chunks easier, :term:`stanza objects <stanza object>` can be
|
||||
composed in two ways: as iterable child objects or as plugins. Iterable
|
||||
child stanzas, or :term:`substanzas`, are accessible through a special
|
||||
``'substanzas'`` interface. This option is useful for stanzas which
|
||||
child stanzas, or :term:`substanzas <substanza>`, are accessible through a
|
||||
special ``'substanzas'`` interface. This option is useful for stanzas which
|
||||
may contain more than one of the same kind of element. When there is
|
||||
only one child element, the plugin method is more useful. For plugins,
|
||||
a parent stanza object delegates one of its XML child elements to the
|
||||
@@ -72,7 +72,7 @@ plugin stanza object. Here is an example:
|
||||
|
||||
<iq type="result">
|
||||
<query xmlns="http://jabber.org/protocol/disco#info">
|
||||
<identity category="client" type="bot" name="SleekXMPP Bot" />
|
||||
<identity category="client" type="bot" name="Slixmpp Bot" />
|
||||
</query>
|
||||
</iq>
|
||||
|
||||
@@ -84,13 +84,13 @@ we can access the plugin as so::
|
||||
|
||||
>>> iq['disco_info']
|
||||
'<query xmlns="http://jabber.org/protocol/disco#info">
|
||||
<identity category="client" type="bot" name="SleekXMPP Bot" />
|
||||
<identity category="client" type="bot" name="Slixmpp Bot" />
|
||||
</query>'
|
||||
|
||||
We can then drill down through the plugin object's interfaces as desired::
|
||||
|
||||
>>> iq['disco_info']['identities']
|
||||
[('client', 'bot', 'SleekXMPP Bot')]
|
||||
[('client', 'bot', 'Slixmpp Bot')]
|
||||
|
||||
Plugins may also add new interfaces to the parent stanza object as if they
|
||||
had been defined by the parent directly, and can also override the behaviour
|
||||
@@ -101,7 +101,7 @@ of an interface defined by the parent.
|
||||
- :ref:`create-stanza-plugins`
|
||||
- :ref:`create-extension-plugins`
|
||||
- :ref:`override-parent-interfaces`
|
||||
|
||||
|
||||
|
||||
Registering Stanza Plugins
|
||||
--------------------------
|
||||
|
@@ -1,18 +1,18 @@
|
||||
.. module:: sleekxmpp.xmlstream.tostring
|
||||
.. module:: slixmpp.xmlstream.tostring
|
||||
|
||||
.. _tostring:
|
||||
|
||||
XML Serialization
|
||||
=================
|
||||
|
||||
Since the XML layer of SleekXMPP is based on :mod:`~xml.etree.ElementTree`,
|
||||
Since the XML layer of Slixmpp is based on :mod:`~xml.etree.ElementTree`,
|
||||
why not just use the built-in :func:`~xml.etree.ElementTree.tostring`
|
||||
method? The answer is that using that method produces ugly results when
|
||||
using namespaces. The :func:`tostring()` method used here intelligently
|
||||
hides namespaces when able and does not introduce excessive namespace
|
||||
prefixes::
|
||||
|
||||
>>> from sleekxmpp.xmlstream.tostring import tostring
|
||||
>>> from slixmpp.xmlstream.tostring import tostring
|
||||
>>> from xml.etree import cElementTree as ET
|
||||
>>> xml = ET.fromstring('<foo xmlns="bar"><baz /></foo>')
|
||||
>>> ET.tostring(xml)
|
||||
@@ -25,10 +25,10 @@ produce unexpected results depending on how the :func:`tostring()` method
|
||||
is invoked. For example, when sending XML on the wire, the main XMPP
|
||||
stanzas with their namespace of ``jabber:client`` will not include the
|
||||
namespace because that is already declared by the stream header. But, if
|
||||
you create a :class:`~sleekxmpp.stanza.message.Message` instance and dump
|
||||
you create a :class:`~slixmpp.stanza.message.Message` instance and dump
|
||||
it to the terminal, the ``jabber:client`` namespace will appear.
|
||||
|
||||
.. autofunction:: tostring
|
||||
.. autofunction:: slixmpp.xmlstream.tostring
|
||||
|
||||
Escaping Special Characters
|
||||
---------------------------
|
||||
@@ -43,4 +43,5 @@ In the future, the use of CDATA sections may be allowed to reduce the
|
||||
size of escaped text or for when other XMPP processing agents do not
|
||||
undertand these entities.
|
||||
|
||||
.. autofunction:: xml_escape
|
||||
..
|
||||
autofunction:: xml_escape
|
||||
|
@@ -2,9 +2,7 @@
|
||||
XML Stream
|
||||
==========
|
||||
|
||||
.. module:: sleekxmpp.xmlstream.xmlstream
|
||||
|
||||
.. autoexception:: RestartStream
|
||||
.. module:: slixmpp.xmlstream.xmlstream
|
||||
|
||||
.. autoclass:: XMLStream
|
||||
:members:
|
||||
|
@@ -1,9 +1,9 @@
|
||||
.. index:: XMLStream, BaseXMPP, ClientXMPP, ComponentXMPP
|
||||
|
||||
SleekXMPP Architecture
|
||||
Slixmpp Architecture
|
||||
======================
|
||||
|
||||
The core of SleekXMPP is contained in four classes: ``XMLStream``,
|
||||
The core of Slixmpp is contained in four classes: ``XMLStream``,
|
||||
``BaseXMPP``, ``ClientXMPP``, and ``ComponentXMPP``. Along side this
|
||||
stack is a library for working with XML objects that eliminates most
|
||||
of the tedium of creating/manipulating XML.
|
||||
@@ -17,28 +17,27 @@ of the tedium of creating/manipulating XML.
|
||||
|
||||
The Foundation: XMLStream
|
||||
-------------------------
|
||||
:class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic
|
||||
:class:`~slixmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic
|
||||
class whose purpose is to read and write from a bi-directional XML stream.
|
||||
It also allows for callback functions to execute when XML matching given
|
||||
patterns is received; these callbacks are also referred to as :term:`stream
|
||||
handlers <stream handler>`. The class also provides a basic eventing system
|
||||
which can be triggered either manually or on a timed schedule.
|
||||
|
||||
The Main Threads
|
||||
~~~~~~~~~~~~~~~~
|
||||
:class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` instances run using at
|
||||
least three background threads: the send thread, the read thread, and the
|
||||
scheduler thread. The send thread is in charge of monitoring the send queue
|
||||
and writing text to the outgoing XML stream. The read thread pulls text off
|
||||
of the incoming XML stream and stores the results in an event queue. The
|
||||
scheduler thread is used to emit events after a given period of time.
|
||||
The event loop
|
||||
~~~~~~~~~~~~~~
|
||||
:class:`~slixmpp.xmlstream.xmlstream.XMLStream` instances inherit the
|
||||
:class:`asyncio.BaseProtocol` class, and therefore do not have to handle
|
||||
reads and writes directly, but receive data through
|
||||
:meth:`~slixmpp.xmlstream.xmlstream.XMLStream.data_received` and write
|
||||
data in the socket transport.
|
||||
|
||||
Additionally, the main event processing loop may be executed in its
|
||||
own thread if SleekXMPP is being used in the background for another
|
||||
application.
|
||||
Upon receiving data, :term:`stream handlers <stream handler>` are run
|
||||
immediately, except if they are coroutines, in which case they are
|
||||
scheduled using :meth:`asyncio.async`.
|
||||
|
||||
Short-lived threads may also be spawned as requested for threaded
|
||||
:term:`event handlers <event handler>`.
|
||||
:term:`Event handlers <event handler>` (which are called inside
|
||||
:term:`stream handlers <stream handler>`) work the same way.
|
||||
|
||||
How XML Text is Turned into Action
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -53,7 +52,7 @@ when this bit of XML is received (with an assumed namespace of
|
||||
</message>
|
||||
|
||||
|
||||
1. **Convert XML strings into objects.**
|
||||
#. **Convert XML strings into objects.**
|
||||
|
||||
Incoming text is parsed and converted into XML objects (using
|
||||
ElementTree) which are then wrapped into what are referred to as
|
||||
@@ -61,95 +60,69 @@ when this bit of XML is received (with an assumed namespace of
|
||||
new object is determined using a map of namespaced element names to
|
||||
classes.
|
||||
|
||||
Our incoming XML is thus turned into a :class:`~sleekxmpp.stanza.Message`
|
||||
Our incoming XML is thus turned into a :class:`~slixmpp.stanza.Message`
|
||||
:term:`stanza object` because the namespaced element name
|
||||
``{jabber:client}message`` is associated with the class
|
||||
:class:`~sleekxmpp.stanza.Message`.
|
||||
:class:`~slixmpp.stanza.Message`.
|
||||
|
||||
2. **Match stanza objects to callbacks.**
|
||||
#. **Match stanza objects to callbacks.**
|
||||
|
||||
These objects are then compared against the stored patterns associated
|
||||
with the registered callback handlers. For each match, a copy of the
|
||||
:term:`stanza object` is paired with a reference to the handler and
|
||||
placed into the event queue.
|
||||
with the registered callback handlers.
|
||||
|
||||
Our :class:`~sleekxmpp.stanza.Message` object is thus paired with the message stanza handler
|
||||
:meth:`BaseXMPP._handle_message` to create the tuple::
|
||||
Each handler matching our :term:`stanza object` is then added to a list.
|
||||
|
||||
('stanza', stanza_obj, handler)
|
||||
#. **Processing callbacks**
|
||||
|
||||
3. **Process the event queue.**
|
||||
Every handler in the list is then called with the :term:`stanza object`
|
||||
as a parameter; if the handler is a
|
||||
:class:`~slixmpp.xmlstream.handler.CoroutineCallback`
|
||||
then it will be scheduled in the event loop using :meth:`asyncio.async`
|
||||
instead of run.
|
||||
|
||||
The event queue is the heart of SleekXMPP. Nearly every action that
|
||||
takes place is first inserted into this queue, whether that be received
|
||||
stanzas, custom events, or scheduled events.
|
||||
|
||||
When the stanza is pulled out of the event queue with an associated
|
||||
callback, the callback function is executed with the stanza as its only
|
||||
parameter.
|
||||
|
||||
.. warning::
|
||||
The callback, aka :term:`stream handler`, is executed in the main event
|
||||
processing thread. If the handler blocks, event processing will also
|
||||
block.
|
||||
|
||||
4. **Raise Custom Events**
|
||||
#. **Raise Custom Events**
|
||||
|
||||
Since a :term:`stream handler` shouldn't block, if extensive processing
|
||||
for a stanza is required (such as needing to send and receive an
|
||||
:class:`~sleekxmpp.stanza.Iq` stanza), then custom events must be used.
|
||||
:class:`~slixmpp.stanza.Iq` stanza), then custom events must be used.
|
||||
These events are not explicitly tied to the incoming XML stream and may
|
||||
be raised at any time. Importantly, these events may be handled in their
|
||||
own thread.
|
||||
be raised at any time.
|
||||
|
||||
When the event is raised, a copy of the stanza is created for each
|
||||
handler registered for the event. In contrast to :term:`stream handlers
|
||||
<stream handler>`, these functions are referred to as :term:`event
|
||||
handlers <event handler>`. Each stanza/handler pair is then put into the
|
||||
event queue.
|
||||
|
||||
.. note::
|
||||
It is possible to skip the event queue and process an event immediately
|
||||
by using ``direct=True`` when raising the event.
|
||||
In contrast to :term:`stream handlers <stream handler>`, these functions
|
||||
are referred to as :term:`event handlers <event handler>`.
|
||||
|
||||
The code for :meth:`BaseXMPP._handle_message` follows this pattern, and
|
||||
raises a ``'message'`` event::
|
||||
raises a ``'message'`` event
|
||||
|
||||
self.event('message', msg)
|
||||
.. code-block:: python
|
||||
|
||||
The event call then places the message object back into the event queue
|
||||
paired with an :term:`event handler`::
|
||||
self.event('message', msg)
|
||||
|
||||
('event', 'message', msg_copy1, custom_event_handler_1)
|
||||
('event', 'message', msg_copy2, custom_evetn_handler_2)
|
||||
#. **Process Custom Events**
|
||||
|
||||
5. **Process Custom Events**
|
||||
|
||||
The stanza and :term:`event handler` are then pulled from the event
|
||||
queue, and the handler is executed, passing the stanza as its only
|
||||
argument. If the handler was registered as threaded, then a new thread
|
||||
will be spawned for it.
|
||||
The :term:`event handlers <event handler>` are then executed, passing
|
||||
the stanza as the only argument.
|
||||
|
||||
.. note::
|
||||
Events may be raised without needing :term:`stanza objects <stanza object>`.
|
||||
For example, you could use ``self.event('custom', {'a': 'b'})``.
|
||||
You don't even need any arguments: ``self.event('no_parameters')``.
|
||||
Events may be raised without needing :term:`stanza objects <stanza object>`.
|
||||
For example, you could use ``self.event('custom', {'a': 'b'})``.
|
||||
You don't even need any arguments: ``self.event('no_parameters')``.
|
||||
However, every event handler MUST accept at least one argument.
|
||||
|
||||
Finally, after a long trek, our message is handed off to the user's
|
||||
custom handler in order to do awesome stuff::
|
||||
|
||||
msg.reply()
|
||||
msg['body'] = "Hey! This is awesome!"
|
||||
msg.send()
|
||||
reply = msg.reply()
|
||||
reply['body'] = "Hey! This is awesome!"
|
||||
reply.send()
|
||||
|
||||
|
||||
.. index:: BaseXMPP, XMLStream
|
||||
|
||||
Raising XMPP Awareness: BaseXMPP
|
||||
--------------------------------
|
||||
While :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` attempts to shy away
|
||||
from anything too XMPP specific, :class:`~sleekxmpp.basexmpp.BaseXMPP`'s
|
||||
While :class:`~slixmpp.xmlstream.xmlstream.XMLStream` attempts to shy away
|
||||
from anything too XMPP specific, :class:`~slixmpp.basexmpp.BaseXMPP`'s
|
||||
sole purpose is to provide foundational support for sending and receiving
|
||||
XMPP stanzas. This support includes registering the basic message,
|
||||
presence, and iq stanzas, methods for creating and sending stanzas, and
|
||||
@@ -157,14 +130,14 @@ default handlers for incoming messages and keeping track of presence
|
||||
notifications.
|
||||
|
||||
The plugin system for adding new XEP support is also maintained by
|
||||
:class:`~sleekxmpp.basexmpp.BaseXMPP`.
|
||||
:class:`~slixmpp.basexmpp.BaseXMPP`.
|
||||
|
||||
.. index:: ClientXMPP, BaseXMPP
|
||||
|
||||
ClientXMPP
|
||||
----------
|
||||
:class:`~sleekxmpp.clientxmpp.ClientXMPP` extends
|
||||
:class:`~sleekxmpp.clientxmpp.BaseXMPP` with additional logic for connecting
|
||||
:class:`~slixmpp.clientxmpp.ClientXMPP` extends
|
||||
:class:`~slixmpp.clientxmpp.BaseXMPP` with additional logic for connecting
|
||||
to an XMPP server by performing DNS lookups. It also adds support for stream
|
||||
features such as STARTTLS and SASL.
|
||||
|
||||
@@ -172,6 +145,6 @@ features such as STARTTLS and SASL.
|
||||
|
||||
ComponentXMPP
|
||||
-------------
|
||||
:class:`~sleekxmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of
|
||||
:class:`~sleekxmpp.basexmpp.BaseXMPP` that implements the component handshake
|
||||
:class:`~slixmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of
|
||||
:class:`~slixmpp.basexmpp.BaseXMPP` that implements the component handshake
|
||||
protocol.
|
||||
|
18
docs/conf.py
18
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
|
||||
@@ -48,9 +48,9 @@ copyright = u'2011, Nathan Fritz, Lance Stout'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0'
|
||||
release = '1.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -105,7 +105,7 @@ html_theme = 'haiku'
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
html_title = 'SleekXMPP'
|
||||
html_title = 'slixmpp'
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
html_short_title = '%s Documentation' % release
|
||||
@@ -168,7 +168,7 @@ html_additional_pages = {
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'SleekXMPPdoc'
|
||||
htmlhelp_basename = 'Slixmppdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
@@ -182,7 +182,7 @@ htmlhelp_basename = 'SleekXMPPdoc'
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'SleekXMPP.tex', u'SleekXMPP Documentation',
|
||||
('index', 'Slixmpp.tex', u'Slixmpp Documentation',
|
||||
u'Nathan Fritz, Lance Stout', 'manual'),
|
||||
]
|
||||
|
||||
@@ -215,8 +215,8 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'sleekxmpp', u'SleekXMPP Documentation',
|
||||
('index', 'slixmpp', u'Slixmpp Documentation',
|
||||
[u'Nathan Fritz, Lance Stout'], 1)
|
||||
]
|
||||
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.2', 'python-objects.inv')}
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.4', 'python-objects.inv')}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
.. _create-plugin:
|
||||
|
||||
Creating a SleekXMPP Plugin
|
||||
Creating a Slixmpp Plugin
|
||||
===========================
|
||||
|
||||
One of the goals of SleekXMPP is to provide support for every draft or final
|
||||
XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, SleekXMPP has a
|
||||
One of the goals of Slixmpp is to provide support for every draft or final
|
||||
XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, Slixmpp has a
|
||||
plugin mechanism for adding the functionalities required by each XEP. But even
|
||||
though plugins were made to quickly implement and prototype the official XMPP
|
||||
extensions, there is no reason you can't create your own plugin to implement
|
||||
@@ -14,11 +14,11 @@ This guide will help walk you through the steps to
|
||||
implement a rudimentary version of `XEP-0077 In-band
|
||||
Registration <http://xmpp.org/extensions/xep-0077.html>`_. In-band registration
|
||||
was implemented in example 14-6 (page 223) of `XMPP: The Definitive
|
||||
Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no SleekXMPP
|
||||
Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no Slixmpp
|
||||
plugin for XEP-0077 at the time of writing. We will partially fix that issue
|
||||
here by turning the example implementation from *XMPP: The Definitive Guide*
|
||||
into a plugin. Again, note that this will not a complete implementation, and a
|
||||
different, more robust, official plugin for XEP-0077 may be added to SleekXMPP
|
||||
different, more robust, official plugin for XEP-0077 may be added to Slixmpp
|
||||
in the future.
|
||||
|
||||
.. note::
|
||||
@@ -29,10 +29,10 @@ in the future.
|
||||
|
||||
First Steps
|
||||
-----------
|
||||
Every plugin inherits from the class :mod:`base_plugin <sleekxmpp.plugins.base.base_plugin>`,
|
||||
Every plugin inherits from the class :mod:`BasePlugin <slixmpp.plugins.base.BasePlugin`,
|
||||
and must include a ``plugin_init`` method. While the
|
||||
plugins distributed with SleekXMPP must be placed in the plugins directory
|
||||
``sleekxmpp/plugins`` to be loaded, custom plugins may be loaded from any
|
||||
plugins distributed with Slixmpp must be placed in the plugins directory
|
||||
``slixmpp/plugins`` to be loaded, custom plugins may be loaded from any
|
||||
module. To do so, use the following form when registering the plugin:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -40,9 +40,9 @@ module. To do so, use the following form when registering the plugin:
|
||||
self.register_plugin('myplugin', module=mod_containing_my_plugin)
|
||||
|
||||
The plugin name must be the same as the plugin's class name.
|
||||
|
||||
|
||||
Now, we can open our favorite text editors and create ``xep_0077.py`` in
|
||||
``SleekXMPP/sleekxmpp/plugins``. We want to do some basic house-keeping and
|
||||
``Slixmpp/slixmpp/plugins``. We want to do some basic house-keeping and
|
||||
declare the name and description of the XEP we are implementing. If you
|
||||
are creating your own custom plugin, you don't need to include the ``xep``
|
||||
attribute.
|
||||
@@ -50,15 +50,15 @@ attribute.
|
||||
.. code-block:: python
|
||||
|
||||
"""
|
||||
Creating a SleekXMPP Plugin
|
||||
Creating a Slixmpp Plugin
|
||||
|
||||
This is a minimal implementation of XEP-0077 to serve
|
||||
as a tutorial for creating SleekXMPP plugins.
|
||||
as a tutorial for creating Slixmpp plugins.
|
||||
"""
|
||||
|
||||
from sleekxmpp.plugins.base import base_plugin
|
||||
from slixmpp.plugins.base import BasePlugin
|
||||
|
||||
class xep_0077(base_plugin):
|
||||
class xep_0077(BasePlugin):
|
||||
"""
|
||||
XEP-0077 In-Band Registration
|
||||
"""
|
||||
@@ -68,7 +68,7 @@ attribute.
|
||||
self.xep = "0077"
|
||||
|
||||
Now that we have a basic plugin, we need to edit
|
||||
``sleekxmpp/plugins/__init__.py`` to include our new plugin by adding
|
||||
``slixmpp/plugins/__init__.py`` to include our new plugin by adding
|
||||
``'xep_0077'`` to the ``__all__`` declaration.
|
||||
|
||||
Interacting with Other Plugins
|
||||
@@ -81,20 +81,20 @@ call in a method named ``post_init`` which will be called once the plugin has
|
||||
been loaded; by doing so we advertise that we can do registrations only after we
|
||||
finish activating the plugin.
|
||||
|
||||
The ``post_init`` method needs to call ``base_plugin.post_init(self)``
|
||||
The ``post_init`` method needs to call ``BasePlugin.post_init(self)``
|
||||
which will mark that ``post_init`` has been called for the plugin. Once the
|
||||
SleekXMPP object begins processing, ``post_init`` will be called on any plugins
|
||||
Slixmpp object begins processing, ``post_init`` will be called on any plugins
|
||||
that have not already run ``post_init``. This allows you to register plugins and
|
||||
their dependencies without needing to worry about the order in which you do so.
|
||||
|
||||
**Note:** by adding this call we have introduced a dependency on the XEP-0030
|
||||
plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. SleekXMPP
|
||||
plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. Slixmpp
|
||||
does not automatically load plugin dependencies for you.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def post_init(self):
|
||||
base_plugin.post_init(self)
|
||||
BasePlugin.post_init(self)
|
||||
self.xmpp['xep_0030'].add_feature("jabber:iq:register")
|
||||
|
||||
Creating Custom Stanza Objects
|
||||
@@ -141,7 +141,7 @@ behaviour:
|
||||
**Note:** The accessor methods currently use title case, and not camel case.
|
||||
Thus if you need to access an item named ``"methodName"`` you will need to
|
||||
use ``getMethodname``. This naming convention might change to full camel
|
||||
case in a future version of SleekXMPP.
|
||||
case in a future version of Slixmpp.
|
||||
|
||||
* ``sub_interfaces``
|
||||
A subset of ``interfaces``, but these keys map to the text of any
|
||||
@@ -156,8 +156,8 @@ behaviour:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
|
||||
from sleekxmpp import Iq
|
||||
from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
|
||||
from slixmpp import Iq
|
||||
|
||||
class Registration(ElementBase):
|
||||
namespace = 'jabber:iq:register'
|
||||
@@ -209,7 +209,7 @@ registration to our ``plugin_init`` method.
|
||||
|
||||
Also, we need to associate our ``Registration`` class with IQ stanzas;
|
||||
that requires the use of the ``register_stanza_plugin`` function (in
|
||||
``sleekxmpp.xmlstream.stanzabase``) which takes the class of a parent stanza
|
||||
``slixmpp.xmlstream.stanzabase``) which takes the class of a parent stanza
|
||||
type followed by the substanza type. In our case, the parent stanza is an IQ
|
||||
stanza, and the substanza is our registration query.
|
||||
|
||||
@@ -347,7 +347,7 @@ method ``setForm`` which will take the names of the fields we wish to include.
|
||||
# Add a blank field
|
||||
reg.addField(field)
|
||||
|
||||
iq.reply().setPayload(reg.xml)
|
||||
iq.reply().set_payload(reg.xml)
|
||||
iq.send()
|
||||
|
||||
Note how we are able to access our ``Registration`` stanza object with
|
||||
@@ -421,7 +421,7 @@ to the IQ reply.
|
||||
...
|
||||
|
||||
def _sendError(self, iq, code, error_type, name, text=''):
|
||||
iq.reply().setPayload(iq['register'].xml)
|
||||
iq.reply().set_payload(iq['register'].xml)
|
||||
iq.error()
|
||||
iq['error']['code'] = code
|
||||
iq['error']['type'] = error_type
|
||||
@@ -464,7 +464,7 @@ component examples below for how to respond to this event.
|
||||
if self.backend.register(iq['from'].bare, iq['register']):
|
||||
# Successful registration
|
||||
self.xmpp.event('registered_user', iq)
|
||||
iq.reply().setPayload(iq['register'].xml)
|
||||
iq.reply().set_payload(iq['register'].xml)
|
||||
iq.send()
|
||||
else:
|
||||
# Conflicting registration
|
||||
@@ -484,15 +484,15 @@ and that we specified the form fields we wish to use with
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import sleekxmpp.componentxmpp
|
||||
import slixmpp.componentxmpp
|
||||
|
||||
class Example(sleekxmpp.componentxmpp.ComponentXMPP):
|
||||
class Example(slixmpp.componentxmpp.ComponentXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888)
|
||||
slixmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888)
|
||||
|
||||
self.registerPlugin('xep_0030')
|
||||
self.registerPlugin('xep_0077')
|
||||
self.register_plugin('xep_0030')
|
||||
self.register_plugin('xep_0077')
|
||||
self.plugin['xep_0077'].setForm('username', 'password')
|
||||
|
||||
self.add_event_handler("registered_user", self.reg)
|
||||
@@ -500,11 +500,11 @@ and that we specified the form fields we wish to use with
|
||||
|
||||
def reg(self, iq):
|
||||
msg = "Welcome! %s" % iq['register']['username']
|
||||
self.sendMessage(iq['from'], msg, mfrom=self.fulljid)
|
||||
self.send_message(iq['from'], msg, mfrom=self.fulljid)
|
||||
|
||||
def unreg(self, iq):
|
||||
msg = "Bye! %s" % iq['register']['username']
|
||||
self.sendMessage(iq['from'], msg, mfrom=self.fulljid)
|
||||
self.send_message(iq['from'], msg, mfrom=self.fulljid)
|
||||
|
||||
**Congratulations!** We now have a basic, functioning implementation of
|
||||
XEP-0077.
|
||||
@@ -517,17 +517,17 @@ with some additional registration fields implemented.
|
||||
.. code-block:: python
|
||||
|
||||
"""
|
||||
Creating a SleekXMPP Plugin
|
||||
Creating a Slixmpp Plugin
|
||||
|
||||
This is a minimal implementation of XEP-0077 to serve
|
||||
as a tutorial for creating SleekXMPP plugins.
|
||||
as a tutorial for creating Slixmpp plugins.
|
||||
"""
|
||||
|
||||
from sleekxmpp.plugins.base import base_plugin
|
||||
from sleekxmpp.xmlstream.handler.callback import Callback
|
||||
from sleekxmpp.xmlstream.matcher.xpath import MatchXPath
|
||||
from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
|
||||
from sleekxmpp import Iq
|
||||
from slixmpp.plugins.base import BasePlugin
|
||||
from slixmpp.xmlstream.handler.callback import Callback
|
||||
from slixmpp.xmlstream.matcher.xpath import MatchXPath
|
||||
from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
|
||||
from slixmpp import Iq
|
||||
import copy
|
||||
|
||||
|
||||
@@ -535,9 +535,9 @@ with some additional registration fields implemented.
|
||||
namespace = 'jabber:iq:register'
|
||||
name = 'query'
|
||||
plugin_attrib = 'register'
|
||||
interfaces = set(('username', 'password', 'email', 'nick', 'name',
|
||||
'first', 'last', 'address', 'city', 'state', 'zip',
|
||||
'phone', 'url', 'date', 'misc', 'text', 'key',
|
||||
interfaces = set(('username', 'password', 'email', 'nick', 'name',
|
||||
'first', 'last', 'address', 'city', 'state', 'zip',
|
||||
'phone', 'url', 'date', 'misc', 'text', 'key',
|
||||
'registered', 'remove', 'instructions'))
|
||||
sub_interfaces = interfaces
|
||||
|
||||
@@ -589,7 +589,7 @@ with some additional registration fields implemented.
|
||||
def unregister(self, jid):
|
||||
del self.users[jid]
|
||||
|
||||
class xep_0077(base_plugin):
|
||||
class xep_0077(BasePlugin):
|
||||
"""
|
||||
XEP-0077 In-Band Registration
|
||||
"""
|
||||
@@ -608,7 +608,7 @@ with some additional registration fields implemented.
|
||||
register_stanza_plugin(Iq, Registration)
|
||||
|
||||
def post_init(self):
|
||||
base_plugin.post_init(self)
|
||||
BasePlugin.post_init(self)
|
||||
self.xmpp['xep_0030'].add_feature("jabber:iq:register")
|
||||
|
||||
def __handleRegistration(self, iq):
|
||||
@@ -634,8 +634,9 @@ with some additional registration fields implemented.
|
||||
if self.backend.register(iq['from'].bare, iq['register']):
|
||||
# Successful registration
|
||||
self.xmpp.event('registered_user', iq)
|
||||
iq.reply().setPayload(iq['register'].xml)
|
||||
iq.send()
|
||||
reply = iq.reply()
|
||||
reply.set_payload(iq['register'].xml)
|
||||
reply.send()
|
||||
else:
|
||||
# Conflicting registration
|
||||
self._sendError(iq, '409', 'cancel', 'conflict',
|
||||
@@ -666,14 +667,16 @@ with some additional registration fields implemented.
|
||||
# Add a blank field
|
||||
reg.addField(field)
|
||||
|
||||
iq.reply().setPayload(reg.xml)
|
||||
iq.send()
|
||||
reply = iq.reply()
|
||||
reply.set_payload(reg.xml)
|
||||
reply.send()
|
||||
|
||||
def _sendError(self, iq, code, error_type, name, text=''):
|
||||
iq.reply().setPayload(iq['register'].xml)
|
||||
iq.error()
|
||||
iq['error']['code'] = code
|
||||
iq['error']['type'] = error_type
|
||||
iq['error']['condition'] = name
|
||||
iq['error']['text'] = text
|
||||
iq.send()
|
||||
reply = iq.reply()
|
||||
reply.set_payload(iq['register'].xml)
|
||||
reply.error()
|
||||
reply['error']['code'] = code
|
||||
reply['error']['type'] = error_type
|
||||
reply['error']['condition'] = name
|
||||
reply['error']['text'] = text
|
||||
reply.send()
|
||||
|
47
docs/differences.rst
Normal file
47
docs/differences.rst
Normal file
@@ -0,0 +1,47 @@
|
||||
.. _differences:
|
||||
|
||||
Differences from SleekXMPP
|
||||
==========================
|
||||
|
||||
**Python 3.4+ only**
|
||||
slixmpp will only work on python 3.4 and above.
|
||||
|
||||
**Stanza copies**
|
||||
The same stanza object is given through all the handlers; a handler that
|
||||
edits the stanza object should make its own copy.
|
||||
|
||||
**Replies**
|
||||
Because stanzas are not copied anymore,
|
||||
:meth:`Stanza.reply() <.StanzaBase.reply>` calls
|
||||
(for :class:`IQs <.Iq>`, :class:`Messages <.Message>`, etc)
|
||||
now return a new object instead of editing the stanza object
|
||||
in-place.
|
||||
|
||||
**Block and threaded arguments**
|
||||
All the functions that had a ``threaded=`` or ``block=`` argument
|
||||
do not have it anymore. Also, :meth:`.Iq.send` **does not block
|
||||
anymore**.
|
||||
|
||||
**Coroutine facilities**
|
||||
**See** :ref:`using_asyncio`
|
||||
|
||||
If an event handler is a coroutine, it will be called asynchronously
|
||||
in the event loop instead of inside the event caller.
|
||||
|
||||
A CoroutineCallback class has been added to create coroutine stream
|
||||
handlers, which will be also handled in the event loop.
|
||||
|
||||
The :class:`~.slixmpp.stanza.Iq` object’s :meth:`~.slixmpp.stanza.Iq.send`
|
||||
method now **always** return a :class:`~.asyncio.Future` which result will be set
|
||||
to the IQ reply when it is received, or to ``None`` if the IQ is not of
|
||||
type ``get`` or ``set``.
|
||||
|
||||
Many plugins (WIP) calls which retrieve information also return the same
|
||||
future.
|
||||
|
||||
**Architectural differences**
|
||||
slixmpp does not have an event queue anymore, and instead processes
|
||||
handlers directly after receiving the XML stanza.
|
||||
|
||||
.. note::
|
||||
If you find something that doesn’t work but should, please report it.
|
@@ -6,33 +6,33 @@ Event Index
|
||||
|
||||
connected
|
||||
- **Data:** ``{}``
|
||||
- **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream`
|
||||
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
|
||||
|
||||
Signal that a connection has been made with the XMPP server, but a session
|
||||
has not yet been established.
|
||||
|
||||
connection_failed
|
||||
- **Data:** ``{}`` or ``Failure Stanza`` if available
|
||||
- **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream`
|
||||
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
|
||||
|
||||
Signal that a connection can not be established after number of attempts.
|
||||
|
||||
changed_status
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem`
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.roster.item.RosterItem`
|
||||
|
||||
Triggered when a presence stanza is received from a JID with a show type
|
||||
different than the last presence stanza from the same JID.
|
||||
|
||||
changed_subscription
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
Triggered whenever a presence stanza with a type of ``subscribe``,
|
||||
``subscribed``, ``unsubscribe``, or ``unsubscribed`` is received.
|
||||
|
||||
Note that if the values ``xmpp.auto_authorize`` and ``xmpp.auto_subscribe``
|
||||
are set to ``True`` or ``False``, and not ``None``, then SleekXMPP will
|
||||
are set to ``True`` or ``False``, and not ``None``, then Slixmpp will
|
||||
either accept or reject all subscription requests before your event handlers
|
||||
are called. Set these values to ``None`` if you wish to make more complex
|
||||
subscription decisions.
|
||||
@@ -58,20 +58,20 @@ Event Index
|
||||
- **Source:**
|
||||
|
||||
disco_info
|
||||
- **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoInfo`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoInfo`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
|
||||
|
||||
Triggered whenever a ``disco#info`` result stanza is received.
|
||||
|
||||
disco_items
|
||||
- **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoItems`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoItems`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
|
||||
|
||||
Triggered whenever a ``disco#items`` result stanza is received.
|
||||
|
||||
disconnected
|
||||
- **Data:** ``{}``
|
||||
- **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream`
|
||||
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
|
||||
|
||||
Signal that the connection with the XMPP server has been lost.
|
||||
|
||||
@@ -81,33 +81,33 @@ Event Index
|
||||
|
||||
failed_auth
|
||||
- **Data:** ``{}``
|
||||
- **Source:** :py:class:`~sleekxmpp.ClientXMPP`, :py:class:`~sleekxmpp.plugins.xep_0078.xep_0078`
|
||||
- **Source:** :py:class:`~slixmpp.ClientXMPP`, :py:class:`~slixmpp.plugins.xep_0078.xep_0078`
|
||||
|
||||
Signal that the server has rejected the provided login credentials.
|
||||
|
||||
gmail_notify
|
||||
- **Data:** ``{}``
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify`
|
||||
|
||||
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
|
||||
|
||||
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
|
||||
|
||||
gmail_messages
|
||||
- **Data:** :py:class:`~sleekxmpp.Iq`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Iq`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
|
||||
|
||||
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
|
||||
|
||||
got_online
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem`
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.roster.item.RosterItem`
|
||||
|
||||
If a presence stanza is received from a JID which was previously marked as
|
||||
offline, and the presence has a show type of '``chat``', '``dnd``', '``away``',
|
||||
or '``xa``', then this event is triggered as well.
|
||||
|
||||
got_offline
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem`
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.roster.item.RosterItem`
|
||||
|
||||
Signal that an unavailable presence stanza has been received from a JID.
|
||||
|
||||
@@ -116,25 +116,25 @@ Event Index
|
||||
- **Source:**
|
||||
|
||||
groupchat_direct_invite
|
||||
- **Data:** :py:class:`~sleekxmpp.Message`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0249.direct`
|
||||
- **Data:** :py:class:`~slixmpp.Message`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0249.direct`
|
||||
|
||||
groupchat_message
|
||||
- **Data:** :py:class:`~sleekxmpp.Message`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Message`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
|
||||
|
||||
Triggered whenever a message is received from a multi-user chat room.
|
||||
|
||||
groupchat_presence
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
|
||||
|
||||
Triggered whenever a presence stanza is received from a user in a multi-user chat room.
|
||||
|
||||
groupchat_subject
|
||||
- **Data:** :py:class:`~sleekxmpp.Message`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Message`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
|
||||
|
||||
Triggered whenever the subject of a multi-user chat room is changed, or announced when joining a room.
|
||||
|
||||
killed
|
||||
@@ -146,21 +146,28 @@ Event Index
|
||||
- **Source:**
|
||||
|
||||
message
|
||||
- **Data:** :py:class:`~sleekxmpp.Message`
|
||||
- **Source:** :py:class:`BaseXMPP <sleekxmpp.BaseXMPP>`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Message`
|
||||
- **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>`
|
||||
|
||||
Makes the contents of message stanzas available whenever one is received. Be
|
||||
sure to check the message type in order to handle error messages.
|
||||
|
||||
message_error
|
||||
- **Data:** :py:class:`~slixmpp.Message`
|
||||
- **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>`
|
||||
|
||||
Makes the contents of message stanzas available whenever one is received.
|
||||
Only handler messages with an ``error`` type.
|
||||
|
||||
message_form
|
||||
- **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
|
||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
|
||||
|
||||
Currently the same as :term:`message_xform`.
|
||||
|
||||
message_xform
|
||||
- **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
|
||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
|
||||
|
||||
Triggered whenever a data form is received inside a message.
|
||||
|
||||
@@ -181,95 +188,95 @@ Event Index
|
||||
- **Source:**
|
||||
|
||||
presence_available
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``available``' is received.
|
||||
|
||||
presence_error
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``error``' is received.
|
||||
|
||||
presence_form
|
||||
- **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`
|
||||
- **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
|
||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
|
||||
|
||||
This event is present in the XEP-0004 plugin code, but is currently not used.
|
||||
|
||||
presence_probe
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``probe``' is received.
|
||||
|
||||
presence_subscribe
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``subscribe``' is received.
|
||||
|
||||
presence_subscribed
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``subscribed``' is received.
|
||||
|
||||
presence_unavailable
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``unavailable``' is received.
|
||||
|
||||
presence_unsubscribe
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``unsubscribe``' is received.
|
||||
|
||||
presence_unsubscribed
|
||||
- **Data:** :py:class:`~sleekxmpp.Presence`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.Presence`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
||||
A presence stanza with a type of '``unsubscribed``' is received.
|
||||
|
||||
roster_update
|
||||
- **Data:** :py:class:`~sleekxmpp.stanza.Roster`
|
||||
- **Source:** :py:class:`~sleekxmpp.ClientXMPP`
|
||||
|
||||
- **Data:** :py:class:`~slixmpp.stanza.Roster`
|
||||
- **Source:** :py:class:`~slixmpp.ClientXMPP`
|
||||
|
||||
An IQ result containing roster entries is received.
|
||||
|
||||
sent_presence
|
||||
- **Data:** ``{}``
|
||||
- **Source:** :py:class:`~sleekxmpp.roster.multi.Roster`
|
||||
|
||||
- **Source:** :py:class:`~slixmpp.roster.multi.Roster`
|
||||
|
||||
Signal that an initial presence stanza has been written to the XML stream.
|
||||
|
||||
session_end
|
||||
- **Data:** ``{}``
|
||||
- **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream`
|
||||
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
|
||||
|
||||
Signal that a connection to the XMPP server has been lost and the current
|
||||
stream session has ended. Currently equivalent to :term:`disconnected`, but
|
||||
future implementation of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
|
||||
will distinguish the two events.
|
||||
implementations of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
|
||||
distinguish between the two events.
|
||||
|
||||
Plugins that maintain session-based state should clear themselves when
|
||||
this event is fired.
|
||||
|
||||
session_start
|
||||
- **Data:** ``{}``
|
||||
- **Source:** :py:class:`ClientXMPP <sleekxmpp.ClientXMPP>`,
|
||||
:py:class:`ComponentXMPP <sleekxmpp.ComponentXMPP>`
|
||||
:py:class:`XEP-0078 <sleekxmpp.plugins.xep_0078>`
|
||||
- **Source:** :py:class:`ClientXMPP <slixmpp.ClientXMPP>`,
|
||||
:py:class:`ComponentXMPP <slixmpp.ComponentXMPP>`
|
||||
:py:class:`XEP-0078 <slixmpp.plugins.xep_0078>`
|
||||
|
||||
Signal that a connection to the XMPP server has been made and a session has been established.
|
||||
|
||||
socket_error
|
||||
- **Data:** ``Socket`` exception object
|
||||
- **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream`
|
||||
- **Source:** :py:class:`~slixmpp.xmlstream.XMLstream`
|
||||
|
||||
stream_error
|
||||
- **Data:** :py:class:`~sleekxmpp.stanza.StreamError`
|
||||
- **Source:** :py:class:`~sleekxmpp.BaseXMPP`
|
||||
- **Data:** :py:class:`~slixmpp.stanza.StreamError`
|
||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||
|
@@ -5,24 +5,16 @@ Create and Run a Server Component
|
||||
=================================
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
If you have not yet installed SleekXMPP, do so now by either checking out a version
|
||||
from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
|
||||
or ``easy_install``.
|
||||
If you have not yet installed Slixmpp, do so now by either checking out a version
|
||||
with `Git <http://git.poez.io/slixmpp>`_.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install sleekxmpp # Or: easy_install sleekxmpp
|
||||
|
||||
|
||||
Many XMPP applications eventually graduate to requiring to run as a server
|
||||
component in order to meet scalability requirements. To demonstrate how to
|
||||
Many XMPP applications eventually graduate to requiring to run as a server
|
||||
component in order to meet scalability requirements. To demonstrate how to
|
||||
turn an XMPP client bot into a component, we'll turn the echobot example
|
||||
(:ref:`echobot`) into a component version.
|
||||
|
||||
@@ -30,7 +22,7 @@ The first difference is that we will add an additional import statement:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from sleekxmpp.componentxmpp import ComponentXMPP
|
||||
from slixmpp.componentxmpp import ComponentXMPP
|
||||
|
||||
Likewise, we will change the bot's class definition to match:
|
||||
|
||||
@@ -48,7 +40,7 @@ a MUC component, the following could be used:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
muc = ComponentXMPP('muc.sleekxmpp.com', '******', 'sleekxmpp.com', 5555)
|
||||
muc = ComponentXMPP('muc.slixmpp.com', '******', 'slixmpp.com', 5555)
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -62,10 +54,10 @@ with presence.
|
||||
The other, main difference with components is that the
|
||||
``'from'`` value for every stanza must be explicitly set, since
|
||||
components may send stanzas from multiple JIDs. To do so,
|
||||
the :meth:`~sleekxmpp.basexmpp.BaseXMPP.send_message()` and
|
||||
:meth:`~sleekxmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters
|
||||
the :meth:`~slixmpp.basexmpp.BaseXMPP.send_message()` and
|
||||
:meth:`~slixmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters
|
||||
``mfrom`` and ``pfrom``, respectively. For any method that uses
|
||||
:class:`~sleekxmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used.
|
||||
:class:`~slixmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used.
|
||||
|
||||
|
||||
Final Product
|
||||
|
@@ -1,25 +1,17 @@
|
||||
.. _echobot:
|
||||
|
||||
===============================
|
||||
SleekXMPP Quickstart - Echo Bot
|
||||
Slixmpp Quickstart - Echo Bot
|
||||
===============================
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
|
||||
If you have not yet installed SleekXMPP, do so now by either checking out a version
|
||||
from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
|
||||
or ``easy_install``.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install sleekxmpp # Or: easy_install sleekxmpp
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
If you have not yet installed Slixmpp, do so now by either checking out a version
|
||||
with `Git <http://git.poez.io/slixmpp>`_.
|
||||
|
||||
As a basic starting project, we will create an echo bot which will reply to any
|
||||
messages sent to it. We will also go through adding some basic command line configuration
|
||||
@@ -44,11 +36,12 @@ To get started, here is a brief outline of the structure that the final project
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import asyncio
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
|
||||
import sleekxmpp
|
||||
import slixmpp
|
||||
|
||||
'''Here we will create out echo bot class'''
|
||||
|
||||
@@ -59,24 +52,6 @@ To get started, here is a brief outline of the structure that the final project
|
||||
|
||||
'''Finally, we connect the bot and start listening for messages'''
|
||||
|
||||
Default Encoding
|
||||
----------------
|
||||
XMPP requires support for UTF-8 and so SleekXMPP must use UTF-8 as well. In
|
||||
Python3 this is simple because Unicode is the default string type. For Python2.6+
|
||||
the situation is not as easy because standard strings are simply byte arrays and
|
||||
use ASCII. We can get Python to use UTF-8 as the default encoding by including:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
|
||||
.. warning::
|
||||
|
||||
Until we are able to ensure that SleekXMPP will always use Unicode in Python2.6+, this
|
||||
may cause issues embedding SleekXMPP into other applications which assume ASCII encoding.
|
||||
|
||||
Creating the EchoBot Class
|
||||
--------------------------
|
||||
|
||||
@@ -85,30 +60,30 @@ clients. Since our echo bot will only be responding to a few people, and won't n
|
||||
to remember thousands of users, we will use a client connection. A client connection
|
||||
is the same type that you use with your standard IM client such as Pidgin or Psi.
|
||||
|
||||
SleekXMPP comes with a :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` class
|
||||
which we can extend to add our message echoing feature. :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>`
|
||||
Slixmpp comes with a :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` class
|
||||
which we can extend to add our message echoing feature. :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>`
|
||||
requires the parameters ``jid`` and ``password``, so we will let our ``EchoBot`` class accept those
|
||||
as well.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class EchoBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
class EchoBot(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(EchoBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
Handling Session Start
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
The XMPP spec requires clients to broadcast its presence and retrieve its roster (buddy list) once
|
||||
it connects and establishes a session with the XMPP server. Until these two tasks are completed,
|
||||
some servers may not deliver or send messages or presence notifications to the client. So we now
|
||||
need to be sure that we retrieve our roster and send an initial presence once the session has
|
||||
need to be sure that we retrieve our roster and send an initial presence once the session has
|
||||
started. To do that, we will register an event handler for the :term:`session_start` event.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(EchoBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.add_event_handler('session_start', self.start)
|
||||
|
||||
@@ -132,8 +107,8 @@ Our event handler, like every event handler, accepts a single parameter which ty
|
||||
that was received that caused the event. In this case, ``event`` will just be an empty dictionary since
|
||||
there is no associated data.
|
||||
|
||||
Our first task of sending an initial presence is done using :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>`.
|
||||
Calling :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest
|
||||
Our first task of sending an initial presence is done using :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>`.
|
||||
Calling :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest
|
||||
stanza allowed in XMPP:
|
||||
|
||||
.. code-block:: xml
|
||||
@@ -141,17 +116,17 @@ stanza allowed in XMPP:
|
||||
<presence />
|
||||
|
||||
|
||||
The second requirement is fulfilled using :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>`, which
|
||||
The second requirement is fulfilled using :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>`, which
|
||||
will send an IQ stanza requesting the roster to the server and then wait for the response. You may be wondering
|
||||
what :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return
|
||||
what :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return
|
||||
value. The roster data is saved by an internal handler to ``self.roster``, and in the case of a :class:`ClientXMPP
|
||||
<sleekxmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and
|
||||
<slixmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and
|
||||
``self.client_roster`` is that ``self.roster`` supports storing roster information for multiple JIDs, which is useful
|
||||
for components, whereas ``self.client_roster`` stores roster data for just the client's JID.)
|
||||
|
||||
It is possible for a timeout to occur while waiting for the server to respond, which can happen if the
|
||||
network is excessively slow or the server is no longer responding. In that case, an :class:`IQTimeout
|
||||
<sleekxmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <sleekxmpp.exceptions.IQError>` exception can
|
||||
<slixmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <slixmpp.exceptions.IQError>` exception can
|
||||
be raised if the request contained bad data or requested the roster for the wrong user. In either case, you can wrap the
|
||||
``get_roster()`` call in a ``try``/``except`` block to retry the roster retrieval process.
|
||||
|
||||
@@ -178,7 +153,7 @@ whenever a messsage is received.
|
||||
.. code-block:: python
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(EchoBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.add_event_handler('session_start', self.start)
|
||||
self.add_event_handler('message', self.message)
|
||||
@@ -198,10 +173,10 @@ or ``chat``. (Other potential types are ``error``, ``headline``, and ``groupchat
|
||||
|
||||
Let's take a closer look at the ``.reply()`` method used above. For message stanzas,
|
||||
``.reply()`` accepts the parameter ``body`` (also as the first positional argument),
|
||||
which is then used as the value of the ``<body />`` element of the message.
|
||||
which is then used as the value of the ``<body />`` element of the message.
|
||||
Setting the appropriate ``to`` JID is also handled by ``.reply()``.
|
||||
|
||||
Another way to have sent the reply message would be to use :meth:`send_message <sleekxmpp.basexmpp.BaseXMPP.send_message>`,
|
||||
Another way to have sent the reply message would be to use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`,
|
||||
which is a convenience method for generating and sending a message based on the values passed to it. If we were to use
|
||||
this method, the above code would look as so:
|
||||
|
||||
@@ -229,20 +204,20 @@ Whichever method you choose to use, the results in action will look like this:
|
||||
XMPP does not require stanzas sent by a client to include a ``from`` attribute, and
|
||||
leaves that responsibility to the XMPP server. However, if a sent stanza does
|
||||
include a ``from`` attribute, it must match the full JID of the client or some
|
||||
servers will reject it. SleekXMPP thus leaves out the ``from`` attribute when replying
|
||||
servers will reject it. Slixmpp thus leaves out the ``from`` attribute when replying
|
||||
using a client connection.
|
||||
|
||||
Command Line Arguments and Logging
|
||||
----------------------------------
|
||||
|
||||
While this isn't part of SleekXMPP itself, we do want our echo bot program to be able
|
||||
While this isn't part of Slixmpp itself, we do want our echo bot program to be able
|
||||
to accept a JID and password from the command line instead of hard coding them. We will
|
||||
use the ``optparse`` module for this, though there are several alternative methods, including
|
||||
the newer ``argparse`` module.
|
||||
|
||||
We want to accept three parameters: the JID for the echo bot, its password, and a flag for
|
||||
displaying the debugging logs. We also want these to be optional parameters, since passing
|
||||
a password directly through the command line can be a security risk.
|
||||
a password directly through the command line can be a security risk.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -303,21 +278,21 @@ the ``EchoBot.__init__`` method instead.
|
||||
|
||||
.. note::
|
||||
|
||||
If you are using the OpenFire server, you will need to include an additional
|
||||
If you are using the OpenFire server, you will need to include an additional
|
||||
configuration step. OpenFire supports a different version of SSL than what
|
||||
most servers and SleekXMPP support.
|
||||
most servers and Slixmpp support.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
import ssl
|
||||
xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
Now we're ready to connect and begin echoing messages. If you have the package
|
||||
``dnspython`` installed, then the :meth:`sleekxmpp.clientxmpp.ClientXMPP` method
|
||||
``aiodns`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method
|
||||
will perform a DNS query to find the appropriate server to connect to for the
|
||||
given JID. If you do not have ``dnspython``, then SleekXMPP will attempt to
|
||||
given JID. If you do not have ``aiodns``, then Slixmpp will attempt to
|
||||
connect to the hostname used by the JID, unless an address tuple is supplied
|
||||
to :meth:`sleekxmpp.clientxmpp.ClientXMPP`.
|
||||
to :meth:`slixmpp.clientxmpp.ClientXMPP`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -330,35 +305,19 @@ to :meth:`sleekxmpp.clientxmpp.ClientXMPP`.
|
||||
else:
|
||||
print('Unable to connect')
|
||||
|
||||
.. note::
|
||||
|
||||
For Google Talk users withouth ``dnspython`` installed, the above code
|
||||
should look like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# .. option parsing & echo bot configuration
|
||||
|
||||
if xmpp.connect(('talk.google.com', 5222)):
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print('Unable to connect')
|
||||
|
||||
To begin responding to messages, you'll see we called :meth:`sleekxmpp.basexmpp.BaseXMPP.process`
|
||||
To begin responding to messages, you'll see we called :meth:`slixmpp.basexmpp.BaseXMPP.process`
|
||||
which will start the event handling, send queue, and XML reader threads. It will also call
|
||||
the :meth:`sleekxmpp.plugins.base.base_plugin.post_init` method on all registered plugins. By
|
||||
passing ``block=True`` to :meth:`sleekxmpp.basexmpp.BaseXMPP.process` we are running the
|
||||
main processing loop in the main thread of execution. The :meth:`sleekxmpp.basexmpp.BaseXMPP.process`
|
||||
call will not return until after SleekXMPP disconnects. If you need to run the client in the background
|
||||
the :meth:`slixmpp.plugins.base.BasePlugin.post_init` method on all registered plugins. By
|
||||
passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the
|
||||
main processing loop in the main thread of execution. The :meth:`slixmpp.basexmpp.BaseXMPP.process`
|
||||
call will not return until after Slixmpp disconnects. If you need to run the client in the background
|
||||
for another program, use ``block=False`` to spawn the processing loop in its own thread.
|
||||
|
||||
.. note::
|
||||
.. note::
|
||||
|
||||
Before 1.0, controlling the blocking behaviour of :meth:`sleekxmpp.basexmpp.BaseXMPP.process` was
|
||||
Before 1.0, controlling the blocking behaviour of :meth:`slixmpp.basexmpp.BaseXMPP.process` was
|
||||
done via the ``threaded`` argument. This arrangement was a source of confusion because some users
|
||||
interpreted that as controlling whether or not SleekXMPP used threads at all, instead of how
|
||||
interpreted that as controlling whether or not Slixmpp used threads at all, instead of how
|
||||
the processing loop itself was spawned.
|
||||
|
||||
The statements ``xmpp.process(threaded=False)`` and ``xmpp.process(block=True)`` are equivalent.
|
||||
@@ -370,7 +329,7 @@ The Final Product
|
||||
-----------------
|
||||
|
||||
Here then is what the final result should look like after working through the guide above. The code
|
||||
can also be found in the SleekXMPP `examples directory <http://github.com/fritzy/SleekXMPP/tree/master/examples>`_.
|
||||
can also be found in the Slixmpp `examples directory <http://git.poez.io/slixmpp/tree/examples>`_.
|
||||
|
||||
.. compound::
|
||||
|
||||
|
@@ -1,17 +1,17 @@
|
||||
Send/Receive IQ Stanzas
|
||||
=======================
|
||||
|
||||
Unlike :class:`~sleekxmpp.stanza.message.Message` and
|
||||
:class:`~sleekxmpp.stanza.presence.Presence` stanzas which only use
|
||||
text data for basic usage, :class:`~sleekxmpp.stanza.iq.Iq` stanzas
|
||||
Unlike :class:`~slixmpp.stanza.message.Message` and
|
||||
:class:`~slixmpp.stanza.presence.Presence` stanzas which only use
|
||||
text data for basic usage, :class:`~slixmpp.stanza.iq.Iq` stanzas
|
||||
require using XML payloads, and generally entail creating a new
|
||||
SleekXMPP plugin to provide the necessary convenience methods to
|
||||
Slixmpp plugin to provide the necessary convenience methods to
|
||||
make working with them easier.
|
||||
|
||||
Basic Use
|
||||
---------
|
||||
|
||||
XMPP's use of :class:`~sleekxmpp.stanza.iq.Iq` stanzas is built around
|
||||
XMPP's use of :class:`~slixmpp.stanza.iq.Iq` stanzas is built around
|
||||
namespaced ``<query />`` elements. For clients, just sending the
|
||||
empty ``<query />`` element will suffice for retrieving information. For
|
||||
example, a very basic implementation of service discovery would just
|
||||
@@ -26,18 +26,18 @@ need to be able to send:
|
||||
Creating Iq Stanzas
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
SleekXMPP provides built-in support for creating basic :class:`~sleekxmpp.stanza.iq.Iq`
|
||||
Slixmpp provides built-in support for creating basic :class:`~slixmpp.stanza.iq.Iq`
|
||||
stanzas this way. The relevant methods are:
|
||||
|
||||
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq`
|
||||
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_get`
|
||||
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_set`
|
||||
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_result`
|
||||
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_error`
|
||||
* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_query`
|
||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq`
|
||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_get`
|
||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_set`
|
||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_result`
|
||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_error`
|
||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_query`
|
||||
|
||||
These methods all follow the same pattern: create or modify an existing
|
||||
:class:`~sleekxmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based
|
||||
These methods all follow the same pattern: create or modify an existing
|
||||
:class:`~slixmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based
|
||||
on the method name, and finally add a ``<query />`` element with the given
|
||||
namespace. For example, to produce the query above, you would use:
|
||||
|
||||
@@ -50,14 +50,14 @@ namespace. For example, to produce the query above, you would use:
|
||||
Sending Iq Stanzas
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once an :class:`~sleekxmpp.stanza.iq.Iq` stanza is created, sending it
|
||||
over the wire is done using its :meth:`~sleekxmpp.stanza.iq.Iq.send()`
|
||||
Once an :class:`~slixmpp.stanza.iq.Iq` stanza is created, sending it
|
||||
over the wire is done using its :meth:`~slixmpp.stanza.iq.Iq.send()`
|
||||
method, like any other stanza object. However, there are a few extra
|
||||
options to control how to wait for the query's response.
|
||||
|
||||
These options are:
|
||||
|
||||
* ``block``: The default behaviour is that :meth:`~sleekxmpp.stanza.iq.Iq.send()`
|
||||
* ``block``: The default behaviour is that :meth:`~slixmpp.stanza.iq.Iq.send()`
|
||||
will block until a response is received and the response stanza will be the
|
||||
return value. Setting ``block`` to ``False`` will cause the call to return
|
||||
immediately. In which case, you will need to arrange some way to capture
|
||||
@@ -74,7 +74,7 @@ These options are:
|
||||
To change the timeout for a single call, the ``timeout`` parameter works:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
iq.send(timeout=60)
|
||||
|
||||
* ``callback``: When not using a blocking call, using the ``callback``
|
||||
@@ -85,16 +85,16 @@ These options are:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cb_name = iq.send(callback=self.a_callback)
|
||||
cb_name = iq.send(callback=self.a_callback)
|
||||
|
||||
# ... later if we need to cancel
|
||||
self.remove_handler(cb_name)
|
||||
|
||||
Properly working with :class:`~sleekxmpp.stanza.iq.Iq` stanzas requires
|
||||
Properly working with :class:`~slixmpp.stanza.iq.Iq` stanzas requires
|
||||
handling the intended, normal flow, error responses, and timed out
|
||||
requests. To make this easier, two exceptions may be thrown by
|
||||
:meth:`~sleekxmpp.stanza.iq.Iq.send()`: :exc:`~sleekxmpp.exceptions.IqError`
|
||||
and :exc:`~sleekxmpp.exceptions.IqTimeout`. These exceptions only
|
||||
:meth:`~slixmpp.stanza.iq.Iq.send()`: :exc:`~slixmpp.exceptions.IqError`
|
||||
and :exc:`~slixmpp.exceptions.IqTimeout`. These exceptions only
|
||||
apply to the default, blocking calls.
|
||||
|
||||
.. code-block:: python
|
||||
@@ -110,7 +110,7 @@ apply to the default, blocking calls.
|
||||
pass
|
||||
|
||||
If you do not care to distinguish between errors and timeouts, then you
|
||||
can combine both cases with a generic :exc:`~sleekxmpp.exceptions.XMPPError`
|
||||
can combine both cases with a generic :exc:`~slixmpp.exceptions.XMPPError`
|
||||
exception:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -124,24 +124,24 @@ exception:
|
||||
Advanced Use
|
||||
------------
|
||||
|
||||
Going beyond the basics provided by SleekXMPP requires building at least a
|
||||
rudimentary SleekXMPP plugin to create a :term:`stanza object` for
|
||||
interfacting with the :class:`~sleekxmpp.stanza.iq.Iq` payload.
|
||||
Going beyond the basics provided by Slixmpp requires building at least a
|
||||
rudimentary Slixmpp plugin to create a :term:`stanza object` for
|
||||
interfacting with the :class:`~slixmpp.stanza.iq.Iq` payload.
|
||||
|
||||
.. seealso::
|
||||
|
||||
* :ref:`create-plugin`
|
||||
* :ref:`work-with-stanzas`
|
||||
* :ref:`using-handlers-matchers`
|
||||
|
||||
|
||||
The typical way to respond to :class:`~sleekxmpp.stanza.iq.Iq` requests is
|
||||
|
||||
The typical way to respond to :class:`~slixmpp.stanza.iq.Iq` requests is
|
||||
to register stream handlers. As an example, suppose we create a stanza class
|
||||
named ``CustomXEP`` which uses the XML element ``<query xmlns="custom-xep" />``,
|
||||
and has a :attr:`~sleekxmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value
|
||||
and has a :attr:`~slixmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value
|
||||
of ``custom_xep``.
|
||||
|
||||
There are two types of incoming :class:`~sleekxmpp.stanza.iq.Iq` requests:
|
||||
There are two types of incoming :class:`~slixmpp.stanza.iq.Iq` requests:
|
||||
``get`` and ``set``. You can register a handler that will accept both and then
|
||||
filter by type as needed, as so:
|
||||
|
||||
@@ -167,7 +167,7 @@ filter by type as needed, as so:
|
||||
|
||||
If you want to filter out query types beforehand, you can adjust the matching
|
||||
filter by using ``@type=get`` or ``@type=set`` if you are using the recommended
|
||||
:class:`~sleekxmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher.
|
||||
:class:`~slixmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@@ -7,21 +7,13 @@ Mulit-User Chat (MUC) Bot
|
||||
.. note::
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
If you have not yet installed SleekXMPP, do so now by either checking out a version
|
||||
from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
|
||||
or ``easy_install``.
|
||||
If you have not yet installed Slixmpp, do so now by either checking out a version
|
||||
from `Git <http://git.poez.io/slixmpp>`_.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install sleekxmpp # Or: easy_install sleekxmpp
|
||||
|
||||
|
||||
Now that you've got the basic gist of using SleekXMPP by following the
|
||||
Now that you've got the basic gist of using Slixmpp by following the
|
||||
echobot example (:ref:`echobot`), we can use one of the bundled plugins
|
||||
to create a very popular XMPP starter project: a `Multi-User Chat`_
|
||||
(MUC) bot. Our bot will login to an XMPP server, join an MUC chat room
|
||||
@@ -36,7 +28,7 @@ Joining The Room
|
||||
|
||||
As usual, our code will be based on the pattern explained in :ref:`echobot`.
|
||||
To start, we create an ``MUCBot`` class based on
|
||||
:class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and which accepts
|
||||
:class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and which accepts
|
||||
parameters for the JID of the MUC room to join, and the nick that the
|
||||
bot will use inside the chat room. We also register an
|
||||
:term:`event handler` for the :term:`session_start` event.
|
||||
@@ -44,12 +36,12 @@ bot will use inside the chat room. We also register an
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import sleekxmpp
|
||||
import slixmpp
|
||||
|
||||
class MUCBot(sleekxmpp.ClientXMPP):
|
||||
class MUCBot(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password, room, nick):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.room = room
|
||||
self.nick = nick
|
||||
@@ -71,17 +63,17 @@ has been established:
|
||||
def start(self, event):
|
||||
self.get_roster()
|
||||
self.send_presence()
|
||||
self.plugin['xep_0045'].joinMUC(self.room,
|
||||
self.nick,
|
||||
wait=True)
|
||||
self.plugin['xep_0045'].join_muc(self.room,
|
||||
self.nick,
|
||||
wait=True)
|
||||
|
||||
Note that as in :ref:`echobot`, we need to include send an initial presence and request
|
||||
the roster. Next, we want to join the group chat, so we call the
|
||||
``joinMUC`` method of the MUC plugin.
|
||||
``join_muc`` method of the MUC plugin.
|
||||
|
||||
.. note::
|
||||
|
||||
The :attr:`plugin <sleekxmpp.basexmpp.BaseXMPP.plugin>` attribute is
|
||||
The :attr:`plugin <slixmpp.basexmpp.BaseXMPP.plugin>` attribute is
|
||||
dictionary that maps to instances of plugins that we have previously
|
||||
registered, by their names.
|
||||
|
||||
@@ -115,7 +107,7 @@ event inside the bot's ``__init__`` function.
|
||||
.. code-block:: python
|
||||
|
||||
def __init__(self, jid, password, room, nick):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.room = room
|
||||
self.nick = nick
|
||||
@@ -159,7 +151,7 @@ event so it's a good idea to register an event handler for it.
|
||||
.. code-block:: python
|
||||
|
||||
def __init__(self, jid, password, room, nick):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.room = room
|
||||
self.nick = nick
|
||||
|
@@ -5,19 +5,17 @@ Enable HTTP Proxy Support
|
||||
=========================
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
In some instances, you may wish to route XMPP traffic through
|
||||
an HTTP proxy, probably to get around restrictive firewalls.
|
||||
SleekXMPP provides support for basic HTTP proxying with DIGEST
|
||||
Slixmpp provides support for basic HTTP proxying with DIGEST
|
||||
authentication.
|
||||
|
||||
Enabling proxy support is done in two steps. The first is to instruct SleekXMPP
|
||||
Enabling proxy support is done in two steps. The first is to instruct Slixmpp
|
||||
to use a proxy, and the second is to configure the proxy details:
|
||||
|
||||
.. code-block:: python
|
||||
|
@@ -2,31 +2,29 @@ Sign in, Send a Message, and Disconnect
|
||||
=======================================
|
||||
|
||||
.. note::
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
|
||||
A common use case for SleekXMPP is to send one-off messages from
|
||||
time to time. For example, one use case could be sending out a notice when
|
||||
If you have any issues working through this quickstart guide
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
A common use case for Slixmpp is to send one-off messages from
|
||||
time to time. For example, one use case could be sending out a notice when
|
||||
a shell script finishes a task.
|
||||
|
||||
We will create our one-shot bot based on the pattern explained in :ref:`echobot`. To
|
||||
start, we create a client class based on :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and
|
||||
start, we create a client class based on :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and
|
||||
register a handler for the :term:`session_start` event. We will also accept parameters
|
||||
for the JID that will receive our message, and the string content of the message.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import sleekxmpp
|
||||
import slixmpp
|
||||
|
||||
|
||||
class SendMsgBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
class SendMsgBot(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password, recipient, msg):
|
||||
super(SendMsgBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.recipient = recipient
|
||||
self.msg = msg
|
||||
@@ -38,7 +36,7 @@ for the JID that will receive our message, and the string content of the message
|
||||
self.get_roster()
|
||||
|
||||
Note that as in :ref:`echobot`, we need to include send an initial presence and request
|
||||
the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <sleekxmpp.basexmpp.BaseXMPP.send_message>`.
|
||||
the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -48,12 +46,12 @@ the roster. Next, we want to send our message, and to do that we will use :meth:
|
||||
|
||||
self.send_message(mto=self.recipient, mbody=self.msg)
|
||||
|
||||
Finally, we need to disconnect the client using :meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>`.
|
||||
Finally, we need to disconnect the client using :meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>`.
|
||||
Now, sent stanzas are placed in a queue to pass them to the send thread. If we were to call
|
||||
:meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible
|
||||
:meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible
|
||||
for the client to disconnect before the send queue is processed and the message is actually
|
||||
sent on the wire. To ensure that our message is processed, we use
|
||||
:meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>`.
|
||||
sent on the wire. To ensure that our message is processed, we use
|
||||
:meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -68,7 +66,7 @@ sent on the wire. To ensure that our message is processed, we use
|
||||
.. warning::
|
||||
|
||||
If you happen to be adding stanzas to the send queue faster than the send thread
|
||||
can process them, then :meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>`
|
||||
can process them, then :meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`
|
||||
will block and not disconnect.
|
||||
|
||||
Final Product
|
||||
|
@@ -9,21 +9,20 @@ Glossary
|
||||
stream handler
|
||||
A callback function that accepts stanza objects pulled directly
|
||||
from the XML stream. A stream handler is encapsulated in a
|
||||
object that includes a :term:`Matcher` object, and which provides
|
||||
additional semantics. For example, the ``Waiter`` handler wrapper
|
||||
blocks thread execution until a matching stanza is received.
|
||||
object that includes a :class:`Matcher <.MatcherBase>` object, and
|
||||
which provides additional semantics. For example, the
|
||||
:class:`.Waiter` handler wrapper blocks thread execution until a
|
||||
matching stanza is received.
|
||||
|
||||
event handler
|
||||
A callback function that responds to events raised by
|
||||
``XMLStream.event``. An event handler may be marked as
|
||||
threaded, allowing it to execute outside of the main processing
|
||||
loop.
|
||||
:meth:`.XMLStream.event`.
|
||||
|
||||
stanza object
|
||||
Informally may refer both to classes which extend ``ElementBase``
|
||||
or ``StanzaBase``, and to objects of such classes.
|
||||
Informally may refer both to classes which extend :class:`.ElementBase`
|
||||
or :class:`.StanzaBase`, and to objects of such classes.
|
||||
|
||||
A stanza object is a wrapper for an XML object which exposes ``dict``
|
||||
A stanza object is a wrapper for an XML object which exposes :class:`dict`
|
||||
like interfaces which may be assigned to, read from, or deleted.
|
||||
|
||||
stanza plugin
|
||||
|
@@ -18,7 +18,7 @@ Working with service discovery is about creating and querying these nodes.
|
||||
According to XEP-0030, a node may contain three types of information:
|
||||
identities, features, and items. (Further, extensible, information types are
|
||||
defined in `XEP-0128 <http://xmpp.org/extensions/xep-0128.html>`_, but they are
|
||||
not yet implemented by SleekXMPP.) SleekXMPP provides methods to configure each
|
||||
not yet implemented by Slixmpp.) Slixmpp provides methods to configure each
|
||||
of these node attributes.
|
||||
|
||||
Configuring Service Discovery
|
||||
@@ -61,7 +61,7 @@ operation using these stanzas without doing any complex operations such as
|
||||
checking an ACL, etc.
|
||||
|
||||
You may find it necessary at some point to revert a particular node or JID to
|
||||
using the default, static handlers. To do so, use the method ``make_static()``.
|
||||
using the default, static handlers. To do so, use the method ``restore_defaults()``.
|
||||
You may also elect to only convert a given set of actions instead.
|
||||
|
||||
Creating a Node Handler
|
||||
@@ -119,7 +119,7 @@ the same order as expected using positional arguments.
|
||||
|
||||
xmpp['xep_0030'].add_identity(category='client',
|
||||
itype='bot',
|
||||
name='Sleek',
|
||||
name='Slixmpp',
|
||||
node='foo',
|
||||
jid=xmpp.boundjid.full,
|
||||
lang='no')
|
||||
@@ -159,10 +159,10 @@ item itself, and the JID and node that will own the item.
|
||||
.. note::
|
||||
|
||||
In this case, the owning JID and node are provided with the
|
||||
parameters ``ijid`` and ``node``.
|
||||
parameters ``ijid`` and ``node``.
|
||||
|
||||
Peforming Disco Queries
|
||||
-----------------------
|
||||
Performing Disco Queries
|
||||
------------------------
|
||||
The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs
|
||||
and their nodes for disco information. Since these methods are wrappers for
|
||||
sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()``
|
||||
@@ -172,11 +172,10 @@ the `XEP-0059 <http://xmpp.org/extensions/xep-0059.html>`_ plug-in.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
info = self['xep_0030'].get_info(jid='foo@example.com',
|
||||
node='bar',
|
||||
ifrom='baz@mycomponent.example.com',
|
||||
block=True,
|
||||
timeout=30)
|
||||
info = yield from self['xep_0030'].get_info(jid='foo@example.com',
|
||||
node='bar',
|
||||
ifrom='baz@mycomponent.example.com',
|
||||
timeout=30)
|
||||
|
||||
items = self['xep_0030'].get_info(jid='foo@example.com',
|
||||
node='bar',
|
||||
@@ -197,5 +196,5 @@ a full Iq stanza.
|
||||
|
||||
info = self['xep_0030'].get_info(node='foo', local=True)
|
||||
items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com',
|
||||
node='bar',
|
||||
node='bar',
|
||||
local=True)
|
||||
|
112
docs/index.rst
112
docs/index.rst
@@ -1,49 +1,36 @@
|
||||
SleekXMPP
|
||||
Slixmpp
|
||||
#########
|
||||
|
||||
.. sidebar:: Get the Code
|
||||
|
||||
.. code-block:: sh
|
||||
The latest source code for Slixmpp may be found on the `Git repo
|
||||
<http://git.poez.io/slixmpp>`_. ::
|
||||
|
||||
pip install sleekxmpp
|
||||
git clone git://git.poez.io/slixmpp
|
||||
|
||||
The latest source code for SleekXMPP may be found on `Github
|
||||
<http://github.com/fritzy/SleekXMPP>`_. Releases can be found in the
|
||||
``master`` branch, while the latest development version is in the
|
||||
``develop`` branch.
|
||||
|
||||
**Latest Stable Release**
|
||||
- `1.0 <http://github.com/fritzy/SleekXMPP/zipball/1.0>`_
|
||||
|
||||
**Develop Releases**
|
||||
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
|
||||
|
||||
|
||||
A mailing list and XMPP chat room are available for discussing and getting
|
||||
help with SleekXMPP.
|
||||
|
||||
**Mailing List**
|
||||
`SleekXMPP Discussion on Google Groups <http://groups.google.com/group/sleekxmpp-discussion>`_
|
||||
An XMPP chat room is available for discussing and getting help with slixmpp.
|
||||
|
||||
**Chat**
|
||||
`sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_
|
||||
`slixmpp@muc.poez.io <xmpp:slixmpp@muc.poez.io?join>`_
|
||||
|
||||
**Reporting bugs**
|
||||
You can report bugs at http://dev.louiz.org/projects/slixmpp/issues.
|
||||
|
||||
SleekXMPP is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+,
|
||||
and is featured in examples in
|
||||
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
|
||||
by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived
|
||||
here from reading the Definitive Guide, please see the notes on updating
|
||||
the examples to the latest version of SleekXMPP.
|
||||
.. note::
|
||||
slixmpp is a friendly fork of `SleekXMPP <https://github.com/fritzy/SleekXMPP>`_
|
||||
which goal is to use asyncio instead of threads to handle networking. See
|
||||
:ref:`differences`.
|
||||
|
||||
SleekXMPP's design goals and philosphy are:
|
||||
Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 3.4+,
|
||||
|
||||
Slixmpp's design goals and philosphy are:
|
||||
|
||||
**Low number of dependencies**
|
||||
Installing and using SleekXMPP should be as simple as possible, without
|
||||
Installing and using Slixmpp should be as simple as possible, without
|
||||
having to deal with long dependency chains.
|
||||
|
||||
As part of reducing the number of dependencies, some third party
|
||||
modules are included with SleekXMPP in the ``thirdparty`` directory.
|
||||
modules are included with Slixmpp in the ``thirdparty`` directory.
|
||||
Imports from this module first try to import an existing installed
|
||||
version before loading the packaged version, when possible.
|
||||
|
||||
@@ -55,19 +42,20 @@ SleekXMPP's design goals and philosphy are:
|
||||
XEPs.
|
||||
|
||||
**Rewarding to work with**
|
||||
As much as possible, SleekXMPP should allow things to "just work" using
|
||||
As much as possible, Slixmpp should allow things to "just work" using
|
||||
sensible defaults and appropriate abstractions. XML can be ugly to work
|
||||
with, but it doesn't have to be that way.
|
||||
|
||||
Here's your first SleekXMPP Bot:
|
||||
|
||||
Here's your first Slixmpp Bot:
|
||||
--------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from sleekxmpp import ClientXMPP
|
||||
from sleekxmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp import ClientXMPP
|
||||
|
||||
|
||||
class EchoBot(ClientXMPP):
|
||||
@@ -85,27 +73,13 @@ Here's your first SleekXMPP Bot:
|
||||
# Here's how to access plugins once you've registered them:
|
||||
# self['xep_0030'].add_feature('echo_demo')
|
||||
|
||||
# If you are working with an OpenFire server, you will
|
||||
# need to use a different SSL version:
|
||||
# import ssl
|
||||
# self.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
def session_start(self, event):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
|
||||
# Most get_*/set_* methods from plugins use Iq stanzas, which
|
||||
# can generate IqError and IqTimeout exceptions
|
||||
#
|
||||
# try:
|
||||
# self.get_roster()
|
||||
# except IqError as err:
|
||||
# logging.error('There was an error getting the roster')
|
||||
# logging.error(err.iq['error']['condition'])
|
||||
# self.disconnect()
|
||||
# except IqTimeout:
|
||||
# logging.error('Server is taking too long to respond')
|
||||
# self.disconnect()
|
||||
# are sent asynchronously. You can almost always provide a
|
||||
# callback that will be executed when the reply is received.
|
||||
|
||||
def message(self, msg):
|
||||
if msg['type'] in ('chat', 'normal'):
|
||||
@@ -113,7 +87,7 @@ Here's your first SleekXMPP Bot:
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Ideally use optparse or argparse to get JID,
|
||||
# Ideally use optparse or argparse to get JID,
|
||||
# password, and log level.
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
@@ -121,15 +95,24 @@ Here's your first SleekXMPP Bot:
|
||||
|
||||
xmpp = EchoBot('somejid@example.com', 'use_getpass')
|
||||
xmpp.connect()
|
||||
xmpp.process(block=True)
|
||||
xmpp.process()
|
||||
|
||||
|
||||
To read if you come from SleekXMPP
|
||||
----------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
differences
|
||||
using_asyncio
|
||||
|
||||
|
||||
Getting Started (with Examples)
|
||||
-------------------------------
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
|
||||
getting_started/echobot
|
||||
getting_started/sendlogout
|
||||
getting_started/component
|
||||
@@ -144,8 +127,7 @@ Tutorials, FAQs, and How To Guides
|
||||
----------------------------------
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
faq
|
||||
|
||||
xeps
|
||||
xmpp_tdg
|
||||
howto/stanzas
|
||||
@@ -156,12 +138,12 @@ Tutorials, FAQs, and How To Guides
|
||||
|
||||
Plugin Guides
|
||||
~~~~~~~~~~~~~
|
||||
.. toctree::
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
guide_xep_0030
|
||||
|
||||
SleekXMPP Architecture and Design
|
||||
Slixmpp Architecture and Design
|
||||
---------------------------------
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
@@ -173,7 +155,7 @@ API Reference
|
||||
-------------
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
event_index
|
||||
api/clientxmpp
|
||||
api/componentxmpp
|
||||
@@ -184,9 +166,7 @@ API Reference
|
||||
api/xmlstream/handler
|
||||
api/xmlstream/matcher
|
||||
api/xmlstream/xmlstream
|
||||
api/xmlstream/scheduler
|
||||
api/xmlstream/tostring
|
||||
api/xmlstream/filesocket
|
||||
|
||||
Core Stanzas
|
||||
~~~~~~~~~~~~
|
||||
@@ -197,8 +177,6 @@ Core Stanzas
|
||||
api/stanza/message
|
||||
api/stanza/presence
|
||||
api/stanza/iq
|
||||
api/stanza/error
|
||||
api/stanza/stream_error
|
||||
|
||||
Plugins
|
||||
~~~~~~~
|
||||
@@ -220,8 +198,14 @@ Additional Info
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
Credits
|
||||
-------
|
||||
SleekXMPP Credits
|
||||
-----------------
|
||||
|
||||
.. note::
|
||||
Those people made SleekXMPP, so you should not bother them if
|
||||
you have an issue with slixmpp. But it’s still fair to credit
|
||||
them for their work.
|
||||
|
||||
|
||||
**Main Author:** `Nathan Fritz <http://andyet.net/team/fritzy>`_
|
||||
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
.. _license:
|
||||
.. _license:
|
||||
|
||||
License (MIT)
|
||||
=============
|
||||
|
@@ -95,9 +95,9 @@ if "%1" == "qthelp" (
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SleekXMPP.qhcp
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Slixmpp.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SleekXMPP.ghc
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Slixmpp.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
|
148
docs/using_asyncio.rst
Normal file
148
docs/using_asyncio.rst
Normal file
@@ -0,0 +1,148 @@
|
||||
.. _using_asyncio:
|
||||
|
||||
=============
|
||||
Using asyncio
|
||||
=============
|
||||
|
||||
Block on IQ sending
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:meth:`.Iq.send` now returns a :class:`~.Future` so you can easily block with:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
result = yield from iq.send()
|
||||
|
||||
.. warning::
|
||||
|
||||
If the reply is an IQ with an ``error`` type, this will raise an
|
||||
:class:`.IqError`, and if it timeouts, it will raise an
|
||||
:class:`.IqTimeout`. Don't forget to catch it.
|
||||
|
||||
You can still use callbacks instead.
|
||||
|
||||
XEP plugin integration
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The same changes from the SleekXMPP API apply, so you can do:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
iq_info = yield from self.xmpp['xep_0030'].get_info(jid)
|
||||
|
||||
But the following will only return a Future:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
iq_info = self.xmpp['xep_0030'].get_info(jid)
|
||||
|
||||
|
||||
Callbacks, Event Handlers, and Stream Handlers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
IQ callbacks and :term:`Event Handlers <event handler>` can be coroutine
|
||||
functions; in this case, they will be scheduled in the event loop using
|
||||
:meth:`.asyncio.async` and not ran immediately.
|
||||
|
||||
A :class:`.CoroutineCallback` class has been added as well for
|
||||
:term:`Stream Handlers <stream handler>`, which will use
|
||||
:meth:`.asyncio.async` to schedule the callback.
|
||||
|
||||
Running the event loop
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:meth:`.XMLStream.process` is only a thin wrapper on top of
|
||||
``loop.run_forever()`` (if ``timeout`` is provided then it will
|
||||
only run for this amount of time, and if ``forever`` is False it will
|
||||
run until disconnection).
|
||||
|
||||
Therefore you can handle the event loop in any way you like
|
||||
instead of using ``process()``.
|
||||
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
Blocking until the session is established
|
||||
-----------------------------------------
|
||||
|
||||
This code blocks until the XMPP session is fully established, which
|
||||
can be useful to make sure external events aren’t triggering XMPP
|
||||
callbacks while everything is not ready.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio, slixmpp
|
||||
|
||||
client = slixmpp.ClientXMPP('jid@example', 'password')
|
||||
client.connected_event = asyncio.Event()
|
||||
callback = lambda _: client.connected_event.set()
|
||||
client.add_event_handler('session_start', callback)
|
||||
client.connect()
|
||||
loop.run_until_complete(event.wait())
|
||||
# do some other stuff before running the event loop, e.g.
|
||||
# loop.run_until_complete(httpserver.init())
|
||||
client.process()
|
||||
|
||||
|
||||
Use with other asyncio-based libraries
|
||||
--------------------------------------
|
||||
|
||||
This code interfaces with aiohttp to retrieve two pages asynchronously
|
||||
when the session is established, and then send the HTML content inside
|
||||
a simple <message>.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio, aiohttp, slixmpp
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_pythonorg(event):
|
||||
req = yield from aiohttp.request('get', 'http://www.python.org')
|
||||
text = yield from req.text
|
||||
client.send_message(mto='jid2@example', mbody=text)
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_asyncioorg(event):
|
||||
req = yield from aiohttp.request('get', 'http://www.asyncio.org')
|
||||
text = yield from req.text
|
||||
client.send_message(mto='jid3@example', mbody=text)
|
||||
|
||||
client = slixmpp.ClientXMPP('jid@example', 'password')
|
||||
client.add_event_handler('session_start', get_pythonorg)
|
||||
client.add_event_handler('session_start', get_asyncioorg)
|
||||
client.connect()
|
||||
client.process()
|
||||
|
||||
|
||||
Blocking Iq
|
||||
-----------
|
||||
|
||||
This client checks (via XEP-0092) the software used by every entity it
|
||||
receives a message from. After this, it sends a message to a specific
|
||||
JID indicating its findings.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio, slixmpp
|
||||
|
||||
class ExampleClient(slixmpp.ClientXMPP):
|
||||
def __init__(self, *args, **kwargs):
|
||||
slixmpp.ClientXMPP.__init__(self, *args, **kwargs)
|
||||
self.register_plugin('xep_0092')
|
||||
self.add_event_handler('message', self.on_message)
|
||||
|
||||
@asyncio.coroutine
|
||||
def on_message(self, event):
|
||||
# You should probably handle IqError and IqTimeout exceptions here
|
||||
# but this is an example.
|
||||
version = yield from self['xep_0092'].get_version(message['from'])
|
||||
text = "%s sent me a message, he runs %s" % (message['from'],
|
||||
version['software_version']['name'])
|
||||
self.send_message(mto='master@example.tld', mbody=text)
|
||||
|
||||
client = ExampleClient('jid@example', 'password')
|
||||
client.connect()
|
||||
client.process()
|
||||
|
||||
|
@@ -4,9 +4,9 @@ Supported XEPS
|
||||
======= ============================= ================
|
||||
XEP Description Notes
|
||||
======= ============================= ================
|
||||
`0004`_ Data forms
|
||||
`0009`_ Jabber RPC
|
||||
`0012`_ Last Activity
|
||||
`0004`_ Data forms
|
||||
`0009`_ Jabber RPC
|
||||
`0012`_ Last Activity
|
||||
`0030`_ Service Discovery
|
||||
`0033`_ Extended Stanza Addressing
|
||||
`0045`_ Multi-User Chat (MUC) Client-side only
|
||||
|
@@ -1,20 +1,20 @@
|
||||
Following *XMPP: The Definitive Guide*
|
||||
======================================
|
||||
|
||||
SleekXMPP was featured in the first edition of the O'Reilly book
|
||||
Slixmpp was featured in the first edition of the O'Reilly book
|
||||
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271/>`_
|
||||
by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code
|
||||
for the book's examples can be found at http://github.com/remko/xmpp-tdg. An
|
||||
updated version of the source code, maintained to stay current with the latest
|
||||
SleekXMPP release, is available at http://github.com/legastero/xmpp-tdg.
|
||||
Slixmpp release, is available at http://github.com/legastero/xmpp-tdg.
|
||||
|
||||
However, since publication, SleekXMPP has advanced from version 0.2.1 to version
|
||||
However, since publication, Slixmpp has advanced from version 0.2.1 to version
|
||||
1.0 and there have been several major API changes. The most notable is the
|
||||
introduction of :term:`stanza objects <stanza object>` which have simplified and
|
||||
standardized interactions with the XMPP XML stream.
|
||||
|
||||
What follows is a walk-through of *The Definitive Guide* highlighting the
|
||||
changes needed to make the code examples work with version 1.0 of SleekXMPP.
|
||||
changes needed to make the code examples work with version 1.0 of Slixmpp.
|
||||
These changes have been kept to a minimum to preserve the correlation with
|
||||
the book's explanations, so be aware that some code may not use current best
|
||||
practices.
|
||||
@@ -36,7 +36,7 @@ Updated Code
|
||||
.. code-block:: python
|
||||
|
||||
def handleIncomingMessage(self, message):
|
||||
self.xmpp.sendMessage(message["from"], message["body"])
|
||||
self.xmpp.send_message(message["from"], message["body"])
|
||||
|
||||
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ |
|
||||
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_
|
||||
@@ -47,7 +47,7 @@ Example 14-1. (Page 215)
|
||||
**CheshiR IM bot implementation.**
|
||||
|
||||
The main event handling method in the Bot class is meant to process both message
|
||||
events and presence update events. With the new changes in SleekXMPP 1.0,
|
||||
events and presence update events. With the new changes in Slixmpp 1.0,
|
||||
extracting a CheshiR status "message" from both types of stanzas
|
||||
requires accessing different attributes. In the case of a message stanza, the
|
||||
``"body"`` attribute would contain the CheshiR message. For a presence event,
|
||||
@@ -72,21 +72,21 @@ Updated Code
|
||||
.. code-block:: python
|
||||
|
||||
def handleIncomingXMPPEvent(self, event):
|
||||
msgLocations = {sleekxmpp.stanza.presence.Presence: "status",
|
||||
sleekxmpp.stanza.message.Message: "body"}
|
||||
msgLocations = {slixmpp.stanza.presence.Presence: "status",
|
||||
slixmpp.stanza.message.Message: "body"}
|
||||
|
||||
message = event[msgLocations[type(event)]]
|
||||
user = self.backend.getUserFromJID(event["from"].jid)
|
||||
if user is not None:
|
||||
self.backend.addMessageFromUser(message, user)
|
||||
|
||||
|
||||
def handleMessageAddedToBackend(self, message) :
|
||||
body = message.user + ": " + message.text
|
||||
htmlBody = "<p><a href='%(uri)s'>%(user)s</a>: %(message)s</p>" % {
|
||||
"uri": self.url + "/" + message.user,
|
||||
"user" : message.user, "message" : message.text }
|
||||
for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
|
||||
self.xmpp.sendMessage(subscriberJID, body, mhtml=htmlBody)
|
||||
self.xmpp.send_message(subscriberJID, body, mhtml=htmlBody)
|
||||
|
||||
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ |
|
||||
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_
|
||||
@@ -102,7 +102,7 @@ Example 14-3. (Page 217)
|
||||
|
||||
The main difference for the configurable IM bot is the handling for the
|
||||
data form in ``handleConfigurationCommand``. The test for equality
|
||||
with the string ``"1"`` is no longer required; SleekXMPP converts
|
||||
with the string ``"1"`` is no longer required; Slixmpp converts
|
||||
boolean data form fields to the values ``True`` and ``False``
|
||||
automatically.
|
||||
|
||||
@@ -145,7 +145,7 @@ Example 14-4. (Page 220)
|
||||
|
||||
Like several previous examples, a needed change is to replace
|
||||
``subscription["from"]`` with ``subscription["from"].jid`` because the
|
||||
``BaseXMPP`` method ``makePresence`` requires the JID to be a string.
|
||||
``BaseXMPP`` method ``make_presence`` requires the JID to be a string.
|
||||
|
||||
A correction needs to be made in ``handleXMPPPresenceProbe`` because a line was
|
||||
left out of the original implementation; the variable ``user`` is undefined. The
|
||||
@@ -154,7 +154,7 @@ JID of the user can be extracted from the presence stanza's ``from`` attribute.
|
||||
Since this implementation of CheshiR uses an XMPP component, it must
|
||||
include a ``from`` attribute in all messages that it sends. Adding the
|
||||
``from`` attribute is done by including ``mfrom=self.xmpp.jid`` in calls to
|
||||
``self.xmpp.sendMessage``.
|
||||
``self.xmpp.send_message``.
|
||||
|
||||
Updated Code
|
||||
~~~~~~~~~~~~
|
||||
@@ -162,19 +162,19 @@ Updated Code
|
||||
.. code-block:: python
|
||||
|
||||
def handleXMPPPresenceProbe(self, event) :
|
||||
self.xmpp.sendPresence(pto = event["from"])
|
||||
self.xmpp.send_presence(pto = event["from"])
|
||||
|
||||
def handleXMPPPresenceSubscription(self, subscription) :
|
||||
if subscription["type"] == "subscribe" :
|
||||
userJID = subscription["from"].jid
|
||||
self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribed")
|
||||
self.xmpp.sendPresence(pto = userJID)
|
||||
self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribe")
|
||||
self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribed")
|
||||
self.xmpp.send_presence(pto = userJID)
|
||||
self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribe")
|
||||
|
||||
def handleMessageAddedToBackend(self, message) :
|
||||
body = message.user + ": " + message.text
|
||||
for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
|
||||
self.xmpp.sendMessage(subscriberJID, body, mfrom=self.xmpp.jid)
|
||||
self.xmpp.send_message(subscriberJID, body, mfrom=self.xmpp.jid)
|
||||
|
||||
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ |
|
||||
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_
|
||||
@@ -192,7 +192,7 @@ After applying the changes from Example 14-4 above, the registrable component
|
||||
implementation should work correctly.
|
||||
|
||||
.. tip::
|
||||
To see how to implement in-band registration as a SleekXMPP plugin,
|
||||
To see how to implement in-band registration as a Slixmpp plugin,
|
||||
see the tutorial :ref:`tutorial-create-plugin`.
|
||||
|
||||
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_ |
|
||||
@@ -203,13 +203,13 @@ Example 14-7. (Page 225)
|
||||
**Extended CheshiR IM server component implementation.**
|
||||
|
||||
.. note::
|
||||
Since the CheshiR examples build on each other, see previous
|
||||
Since the CheshiR examples build on each other, see previous
|
||||
sections for corrections to code that is not marked as new in the book
|
||||
example.
|
||||
|
||||
While the final code example can look daunting with all of the changes
|
||||
made, it requires very few modifications to work with the latest version of
|
||||
SleekXMPP. Most differences are the result of CheshiR's backend functions
|
||||
Slixmpp. Most differences are the result of CheshiR's backend functions
|
||||
expecting JIDs to be strings so that they can be stripped to bare JIDs. To
|
||||
resolve these, use the ``jid`` attribute of the JID objects. Also,
|
||||
references to ``"message"`` and ``"jid"`` attributes need to
|
||||
@@ -239,11 +239,11 @@ Updated Code
|
||||
userJID = subscription["from"].jid
|
||||
user = self.backend.getUserFromJID(userJID)
|
||||
contactJID = subscription["to"]
|
||||
self.xmpp.sendPresenceSubscription(
|
||||
self.xmpp.send_presence_subscription(
|
||||
pfrom=contactJID, pto=userJID, ptype="subscribed", pnick=user)
|
||||
self.sendPresenceOfContactToUser(contactJID=contactJID, userJID=userJID)
|
||||
if contactJID == self.componentDomain :
|
||||
self.sendAllContactSubscriptionRequestsToUser(userJID)
|
||||
|
||||
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ |
|
||||
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_
|
||||
`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_
|
||||
|
@@ -1,53 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Implementation of xeps for Internet of Things
|
||||
http://wiki.xmpp.org/web/Tech_pages/IoT_systems
|
||||
Copyright (C) 2013 Sustainable Innovation, Joachim.lindborg@sust.se
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
# This can be used when you are in a test environment and need to make paths right
|
||||
sys.path=['/Users/jocke/Dropbox/06_dev/SleekXMPP']+sys.path
|
||||
|
||||
import logging
|
||||
import unittest
|
||||
import distutils.core
|
||||
import datetime
|
||||
|
||||
from glob import glob
|
||||
from os.path import splitext, basename, join as pjoin
|
||||
from optparse import OptionParser
|
||||
from os.path import basename, join as pjoin
|
||||
from argparse import ArgumentParser
|
||||
from urllib import urlopen
|
||||
from getpass import getpass
|
||||
|
||||
import sleekxmpp
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
from slixmpp.plugins.xep_0323.device import Device
|
||||
|
||||
from sleekxmpp.plugins.xep_0323.device import Device
|
||||
#from slixmpp.exceptions import IqError, IqTimeout
|
||||
|
||||
#from sleekxmpp.exceptions import IqError, IqTimeout
|
||||
|
||||
class IoT_TestDevice(sleekxmpp.ClientXMPP):
|
||||
class IoT_TestDevice(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple IoT device that can act as server or client
|
||||
"""
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
self.add_event_handler("session_start", self.session_start)
|
||||
self.add_event_handler("message", self.message)
|
||||
self.device=None
|
||||
@@ -125,47 +107,44 @@ if __name__ == '__main__':
|
||||
#
|
||||
# "client" an IoT device or other party that would like to get data from another device
|
||||
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
optp.add_option('-t', '--pingto', help='set jid to ping',
|
||||
action='store', type='string', dest='pingjid',
|
||||
default=None)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
parser.add_argument("-t", "--pingto", help="set jid to ping",
|
||||
action="store", type="string", dest="pingjid",
|
||||
default=None)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
# IoT test
|
||||
optp.add_option("-c", "--sensorjid", dest="sensorjid",
|
||||
help="Another device to call for data on", default=None)
|
||||
optp.add_option("-n", "--nodeid", dest="nodeid",
|
||||
help="I am a device get ready to be called", default=None)
|
||||
parser.add_argument("-c", "--sensorjid", dest="sensorjid",
|
||||
help="Another device to call for data on", default=None)
|
||||
parser.add_argument("-n", "--nodeid", dest="nodeid",
|
||||
help="I am a device get ready to be called", default=None)
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
|
||||
xmpp = IoT_TestDevice(opts.jid,opts.password)
|
||||
xmpp = IoT_TestDevice(args.jid,args.password)
|
||||
xmpp.register_plugin('xep_0030')
|
||||
#xmpp['xep_0030'].add_feature(feature='urn:xmpp:iot:sensordata',
|
||||
# node=None,
|
||||
@@ -173,31 +152,31 @@ if __name__ == '__main__':
|
||||
xmpp.register_plugin('xep_0323')
|
||||
xmpp.register_plugin('xep_0325')
|
||||
|
||||
if opts.nodeid:
|
||||
if args.nodeid:
|
||||
|
||||
# xmpp['xep_0030'].add_feature(feature='urn:xmpp:sn',
|
||||
# node=opts.nodeid,
|
||||
# node=args.nodeid,
|
||||
# jid=xmpp.boundjid.full)
|
||||
|
||||
myDevice = TheDevice(opts.nodeid);
|
||||
myDevice = TheDevice(args.nodeid);
|
||||
# myDevice._add_field(name="Relay", typename="numeric", unit="Bool");
|
||||
myDevice._add_field(name="Temperature", typename="numeric", unit="C");
|
||||
myDevice._add_field(name="Temperature", typename="numeric", unit="C")
|
||||
myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
|
||||
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
|
||||
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
|
||||
|
||||
xmpp['xep_0323'].register_node(nodeId=opts.nodeid, device=myDevice, commTimeout=10);
|
||||
xmpp['xep_0323'].register_node(nodeId=args.nodeid, device=myDevice, commTimeout=10);
|
||||
xmpp.beClientOrServer(server=True)
|
||||
while not(xmpp.testForRelease()):
|
||||
xmpp.connect()
|
||||
xmpp.process(block=True)
|
||||
logging.debug("lost connection")
|
||||
if opts.sensorjid:
|
||||
if args.sensorjid:
|
||||
logging.debug("will try to call another device for data")
|
||||
xmpp.beClientOrServer(server=False,clientJID=opts.sensorjid)
|
||||
xmpp.beClientOrServer(server=False,clientJID=args.sensorjid)
|
||||
xmpp.connect()
|
||||
xmpp.process(block=True)
|
||||
logging.debug("ready ending")
|
||||
|
||||
else:
|
||||
print "noopp didn't happen"
|
||||
print("noopp didn't happen")
|
||||
|
||||
|
@@ -1,41 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class CommandBot(sleekxmpp.ClientXMPP):
|
||||
class CommandBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that provides a basic
|
||||
A simple Slixmpp bot that provides a basic
|
||||
adhoc command.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
@@ -79,7 +68,7 @@ class CommandBot(sleekxmpp.ClientXMPP):
|
||||
session. Additional, custom data may be saved
|
||||
here to persist across handler callbacks.
|
||||
"""
|
||||
form = self['xep_0004'].makeForm('form', 'Greeting')
|
||||
form = self['xep_0004'].make_form('form', 'Greeting')
|
||||
form['instructions'] = 'Send a custom greeting to a JID'
|
||||
form.addField(var='greeting',
|
||||
ftype='text-single',
|
||||
@@ -143,62 +132,42 @@ class CommandBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the CommandBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = CommandBot(opts.jid, opts.password)
|
||||
xmpp = CommandBot(args.jid, args.password)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0050') # Adhoc Commands
|
||||
xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency':15})
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,41 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class CommandUserBot(sleekxmpp.ClientXMPP):
|
||||
class CommandUserBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that uses the adhoc command
|
||||
A simple Slixmpp bot that uses the adhoc command
|
||||
provided by the adhoc_provider.py example.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, other, greeting):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.command_provider = other
|
||||
self.greeting = greeting
|
||||
@@ -105,7 +94,7 @@ class CommandUserBot(sleekxmpp.ClientXMPP):
|
||||
# label="Your greeting" />
|
||||
# </x>
|
||||
|
||||
form = self['xep_0004'].makeForm(ftype='submit')
|
||||
form = self['xep_0004'].make_form(ftype='submit')
|
||||
form.addField(var='greeting',
|
||||
value=session['greeting'])
|
||||
|
||||
@@ -142,69 +131,49 @@ class CommandUserBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-o", "--other", dest="other",
|
||||
help="JID providing commands")
|
||||
optp.add_option("-g", "--greeting", dest="greeting",
|
||||
help="Greeting")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-o", "--other", dest="other",
|
||||
help="JID providing commands")
|
||||
parser.add_argument("-g", "--greeting", dest="greeting",
|
||||
help="Greeting")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.other is None:
|
||||
opts.other = raw_input("JID Providing Commands: ")
|
||||
if opts.greeting is None:
|
||||
opts.greeting = raw_input("Greeting: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.other is None:
|
||||
args.other = input("JID Providing Commands: ")
|
||||
if args.greeting is None:
|
||||
args.greeting = input("Greeting: ")
|
||||
|
||||
# Setup the CommandBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = CommandUserBot(opts.jid, opts.password, opts.other, opts.greeting)
|
||||
xmpp = CommandUserBot(args.jid, args.password, args.other, args.greeting)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0050') # Adhoc Commands
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,41 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class AdminCommands(sleekxmpp.ClientXMPP):
|
||||
class AdminCommands(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that uses admin commands to
|
||||
A simple Slixmpp bot that uses admin commands to
|
||||
add a new user to a server.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, command):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.command = command
|
||||
|
||||
@@ -81,13 +70,13 @@ class AdminCommands(sleekxmpp.ClientXMPP):
|
||||
for var, field in form['fields'].items():
|
||||
if var != 'FORM_TYPE':
|
||||
if field['type'] == 'boolean':
|
||||
answers[var] = raw_input('%s (y/n): ' % field['label'])
|
||||
answers[var] = input('%s (y/n): ' % field['label'])
|
||||
if answers[var].lower() in ('1', 'true', 'y', 'yes'):
|
||||
answers[var] = '1'
|
||||
else:
|
||||
answers[var] = '0'
|
||||
else:
|
||||
answers[var] = raw_input('%s: ' % field['label'])
|
||||
answers[var] = input('%s: ' % field['label'])
|
||||
else:
|
||||
answers['FORM_TYPE'] = field['value']
|
||||
form['type'] = 'submit'
|
||||
@@ -116,63 +105,43 @@ class AdminCommands(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-c", "--command", dest="command",
|
||||
help="admin command to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-c", "--command", dest="command",
|
||||
help="admin command to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.command is None:
|
||||
opts.command = raw_input("Admin command: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.command is None:
|
||||
args.command = input("Admin command: ")
|
||||
|
||||
# Setup the CommandBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = AdminCommands(opts.jid, opts.password, opts.command)
|
||||
xmpp = AdminCommands(args.jid, args.password, args.command)
|
||||
xmpp.register_plugin('xep_0133') # Service Administration
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
100
examples/confirm_answer.py
Executable file
100
examples/confirm_answer.py
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2015 Emmanuel Gil Peyrot
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp import asyncio
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AnswerConfirm(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic client demonstrating how to confirm or deny an HTTP request.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, trusted):
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.add_event_handler("http_confirm", self.confirm)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
def start(self, *args):
|
||||
self.make_presence().send()
|
||||
|
||||
def prompt(self, stanza):
|
||||
confirm = stanza['confirm']
|
||||
print('Received confirm request %s from %s to access %s using '
|
||||
'method %s' % (
|
||||
confirm['id'], stanza['from'], confirm['url'],
|
||||
confirm['method'])
|
||||
)
|
||||
result = input("Do you accept (y/N)? ")
|
||||
return 'y' == result.lower()
|
||||
|
||||
def confirm(self, stanza):
|
||||
if self.prompt(stanza):
|
||||
reply = stanza.reply()
|
||||
else:
|
||||
reply = stanza.reply()
|
||||
reply.enable('error')
|
||||
reply['error']['type'] = 'auth'
|
||||
reply['error']['code'] = '401'
|
||||
reply['error']['condition'] = 'not-authorized'
|
||||
reply.append(stanza['confirm'])
|
||||
reply.send()
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-q","--quiet", help="set logging to ERROR",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.ERROR,
|
||||
default=logging.INFO)
|
||||
parser.add_argument("-d","--debug", help="set logging to DEBUG",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.DEBUG,
|
||||
default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
# Other options.
|
||||
parser.add_argument("-t", "--trusted", nargs='*',
|
||||
help="List of trusted JIDs")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
xmpp = AnswerConfirm(args.jid, args.password, args.trusted)
|
||||
xmpp.register_plugin('xep_0070')
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
125
examples/confirm_ask.py
Executable file
125
examples/confirm_ask.py
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2015 Emmanuel Gil Peyrot
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import logging
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import XMPPError, IqError
|
||||
from slixmpp import asyncio
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AskConfirm(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic client asking an entity if they confirm the access to an HTTP URL.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, recipient, id, url, method):
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.recipient = recipient
|
||||
self.id = id
|
||||
self.url = url
|
||||
self.method = method
|
||||
|
||||
# Will be used to set the proper exit code.
|
||||
self.confirmed = asyncio.Future()
|
||||
|
||||
self.add_event_handler("session_start", self.start)
|
||||
self.add_event_handler("message", self.start)
|
||||
self.add_event_handler("http_confirm_message", self.confirm)
|
||||
|
||||
def confirm(self, message):
|
||||
print(message)
|
||||
if message['confirm']['id'] == self.id:
|
||||
if message['type'] == 'error':
|
||||
self.confirmed.set_result(False)
|
||||
else:
|
||||
self.confirmed.set_result(True)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
log.info('Sending confirm request %s to %s who wants to access %s using '
|
||||
'method %s...' % (self.id, self.recipient, self.url, self.method))
|
||||
try:
|
||||
confirmed = yield from self['xep_0070'].ask_confirm(self.recipient,
|
||||
id=self.id,
|
||||
url=self.url,
|
||||
method=self.method,
|
||||
message='Plz say yes or no for {method} {url} ({id}).')
|
||||
if isinstance(confirmed, slixmpp.Message):
|
||||
confirmed = yield from self.confirmed
|
||||
else:
|
||||
confirmed = True
|
||||
except IqError:
|
||||
confirmed = False
|
||||
if confirmed:
|
||||
print('Confirmed')
|
||||
else:
|
||||
print('Denied')
|
||||
self.disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-q","--quiet", help="set logging to ERROR",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.ERROR,
|
||||
default=logging.INFO)
|
||||
parser.add_argument("-d","--debug", help="set logging to DEBUG",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.DEBUG,
|
||||
default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
# Other options.
|
||||
parser.add_argument("-r", "--recipient", required=True,
|
||||
help="Recipient JID")
|
||||
parser.add_argument("-i", "--id", required=True,
|
||||
help="id TODO")
|
||||
parser.add_argument("-u", "--url", required=True,
|
||||
help="URL the user tried to access")
|
||||
parser.add_argument("-m", "--method", required=True,
|
||||
help="HTTP method used")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
xmpp = AskConfirm(args.jid, args.password, args.recipient, args.id,
|
||||
args.url, args.method)
|
||||
xmpp.register_plugin('xep_0070')
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
xmpp.connect()
|
||||
xmpp.process(forever=False)
|
||||
sys.exit(0 if xmpp.confirmed else 1)
|
@@ -1,48 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
import slixmpp
|
||||
|
||||
from sleekxmpp import ClientXMPP, Iq
|
||||
from sleekxmpp.exceptions import IqError, IqTimeout, XMPPError
|
||||
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||
from sleekxmpp.xmlstream.handler import Callback
|
||||
from sleekxmpp.xmlstream.matcher import StanzaPath
|
||||
from slixmpp import ClientXMPP, Iq
|
||||
from slixmpp.exceptions import IqError, IqTimeout, XMPPError
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import StanzaPath
|
||||
from stanza import Action
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class ActionBot(sleekxmpp.ClientXMPP):
|
||||
class ActionBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that receives a custom stanza
|
||||
A simple Slixmpp bot that receives a custom stanza
|
||||
from another client.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
@@ -57,8 +46,7 @@ class ActionBot(sleekxmpp.ClientXMPP):
|
||||
self._handle_action))
|
||||
|
||||
self.add_event_handler('custom_action',
|
||||
self._handle_action_event,
|
||||
threaded=True)
|
||||
self._handle_action_event)
|
||||
|
||||
register_stanza_plugin(Iq, Action)
|
||||
|
||||
@@ -88,10 +76,6 @@ class ActionBot(sleekxmpp.ClientXMPP):
|
||||
def _handle_action_event(self, iq):
|
||||
"""
|
||||
Respond to the custom action event.
|
||||
|
||||
Since one of the actions is to disconnect, this
|
||||
event handler needs to be run in threaded mode, by
|
||||
using `threaded=True` in the `add_event_handler` call.
|
||||
"""
|
||||
method = iq['action']['method']
|
||||
param = iq['action']['param']
|
||||
@@ -112,62 +96,42 @@ class ActionBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the CommandBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = ActionBot(opts.jid, opts.password)
|
||||
xmpp = ActionBot(args.jid, args.password)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0050') # Adhoc Commands
|
||||
xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency':15})
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,46 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp import Iq
|
||||
from sleekxmpp.exceptions import XMPPError
|
||||
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||
import slixmpp
|
||||
from slixmpp import Iq
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
|
||||
from stanza import Action
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class ActionUserBot(sleekxmpp.ClientXMPP):
|
||||
class ActionUserBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that sends a custom action stanza
|
||||
A simple Slixmpp bot that sends a custom action stanza
|
||||
to another client.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, other):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.action_provider = other
|
||||
|
||||
@@ -49,7 +38,7 @@ class ActionUserBot(sleekxmpp.ClientXMPP):
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
self.add_event_handler("message", self.message)
|
||||
|
||||
register_stanza_plugin(Iq, Action)
|
||||
@@ -93,10 +82,8 @@ class ActionUserBot(sleekxmpp.ClientXMPP):
|
||||
iq2['type'] = 'set'
|
||||
iq2['action']['method'] = 'bye'
|
||||
iq2.send(block=False)
|
||||
|
||||
# The wait=True delays the disconnect until the queue
|
||||
# of stanzas to be sent becomes empty.
|
||||
self.disconnect(wait=True)
|
||||
|
||||
self.disconnect()
|
||||
except XMPPError:
|
||||
print('There was an error sending the custom action.')
|
||||
|
||||
@@ -111,65 +98,45 @@ class ActionUserBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-o", "--other", dest="other",
|
||||
help="JID providing custom stanza")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-o", "--other", dest="other",
|
||||
help="JID providing custom stanza")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.other is None:
|
||||
opts.other = raw_input("JID Providing custom stanza: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.other is None:
|
||||
args.other = input("JID Providing custom stanza: ")
|
||||
|
||||
# Setup the CommandBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = ActionUserBot(opts.jid, opts.password, opts.other)
|
||||
xmpp = ActionUserBot(args.jid, args.password, args.other)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0050') # Adhoc Commands
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,30 +1,30 @@
|
||||
from sleekxmpp.xmlstream import ElementBase
|
||||
from slixmpp.xmlstream import ElementBase
|
||||
|
||||
class Action(ElementBase):
|
||||
|
||||
"""
|
||||
A stanza class for XML content of the form:
|
||||
|
||||
<action xmlns="sleekxmpp:custom:actions">
|
||||
<action xmlns="slixmpp:custom:actions">
|
||||
<method>X</method>
|
||||
<param>X</param>
|
||||
<status>X</status>
|
||||
</action>
|
||||
"""
|
||||
|
||||
|
||||
#: The `name` field refers to the basic XML tag name of the
|
||||
#: stanza. Here, the tag name will be 'action'.
|
||||
name = 'action'
|
||||
|
||||
#: The namespace of the main XML tag.
|
||||
namespace = 'sleekxmpp:custom:actions'
|
||||
namespace = 'slixmpp:custom:actions'
|
||||
|
||||
#: The `plugin_attrib` value is the name that can be used
|
||||
#: with a parent stanza to access this stanza. For example
|
||||
#: from an Iq stanza object, accessing:
|
||||
#:
|
||||
#:
|
||||
#: iq['action']
|
||||
#:
|
||||
#:
|
||||
#: would reference an Action object, and will even create
|
||||
#: an Action object and append it to the Iq stanza if
|
||||
#: one doesn't already exist.
|
||||
@@ -49,8 +49,8 @@ class Action(ElementBase):
|
||||
#: the sub_interfaces set. For example, here all interfaces
|
||||
#: are marked as sub_interfaces, and so the XML produced will
|
||||
#: look like:
|
||||
#:
|
||||
#: <action xmlns="sleekxmpp:custom:actions">
|
||||
#:
|
||||
#: <action xmlns="slixmpp:custom:actions">
|
||||
#: <method>foo</method>
|
||||
#: </action>
|
||||
sub_interfaces = interfaces
|
||||
|
@@ -1,35 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.exceptions import IqError, IqTimeout
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp.xmlstream.asyncio import asyncio
|
||||
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class Disco(sleekxmpp.ClientXMPP):
|
||||
class Disco(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A demonstration for using basic service discovery.
|
||||
@@ -42,7 +31,7 @@ class Disco(sleekxmpp.ClientXMPP):
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, target_jid, target_node='', get=''):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# Using service discovery requires the XEP-0030 plugin.
|
||||
self.register_plugin('xep_0030')
|
||||
@@ -63,8 +52,9 @@ class Disco(sleekxmpp.ClientXMPP):
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -86,22 +76,16 @@ class Disco(sleekxmpp.ClientXMPP):
|
||||
|
||||
try:
|
||||
if self.get in self.info_types:
|
||||
# By using block=True, the result stanza will be
|
||||
# returned. Execution will block until the reply is
|
||||
# received. Non-blocking options would be to listen
|
||||
# for the disco_info event, or passing a handler
|
||||
# function using the callback parameter.
|
||||
info = self['xep_0030'].get_info(jid=self.target_jid,
|
||||
node=self.target_node,
|
||||
block=True)
|
||||
elif self.get in self.items_types:
|
||||
info = yield from self['xep_0030'].get_info(jid=self.target_jid,
|
||||
node=self.target_node)
|
||||
if self.get in self.items_types:
|
||||
# The same applies from above. Listen for the
|
||||
# disco_items event or pass a callback function
|
||||
# if you need to process a non-blocking request.
|
||||
items = self['xep_0030'].get_items(jid=self.target_jid,
|
||||
node=self.target_node,
|
||||
block=True)
|
||||
else:
|
||||
items = yield from self['xep_0030'].get_items(jid=self.target_jid,
|
||||
node=self.target_node)
|
||||
if self.get not in self.info_types and self.get not in self.items_types:
|
||||
logging.error("Invalid disco request type.")
|
||||
return
|
||||
except IqError as e:
|
||||
@@ -136,69 +120,42 @@ class Disco(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
optp.version = '%%prog 0.1'
|
||||
optp.usage = "Usage: %%prog [options] %s <jid> [<node>]" % \
|
||||
'all|info|items|identities|features'
|
||||
parser = ArgumentParser(description=Disco.__doc__)
|
||||
|
||||
optp.add_option('-q','--quiet', help='set logging to ERROR',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-d','--debug', help='set logging to DEBUG',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-v','--verbose', help='set logging to COMM',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=5,
|
||||
default=logging.ERROR)
|
||||
parser.add_argument("-q","--quiet", help="set logging to ERROR",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
parser.add_argument("-d","--debug", help="set logging to DEBUG",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
opts,args = optp.parse_args()
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("query", choices=["all", "info", "items", "identities", "features"])
|
||||
parser.add_argument("target_jid")
|
||||
parser.add_argument("node", nargs='?')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if len(args) < 2:
|
||||
optp.print_help()
|
||||
exit()
|
||||
|
||||
if len(args) == 2:
|
||||
args = (args[0], args[1], '')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the Disco browser.
|
||||
xmpp = Disco(opts.jid, opts.password, args[1], args[2], args[0])
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
xmpp = Disco(args.jid, args.password, args.target_jid, args.node, args.query)
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process(forever=False)
|
||||
|
@@ -1,33 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
import threading
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.exceptions import XMPPError
|
||||
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp import asyncio
|
||||
|
||||
|
||||
FILE_TYPES = {
|
||||
@@ -37,23 +25,29 @@ FILE_TYPES = {
|
||||
}
|
||||
|
||||
|
||||
class AvatarDownloader(sleekxmpp.ClientXMPP):
|
||||
class AvatarDownloader(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic script for downloading the avatars for a user's contacts.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
self.add_event_handler("changed_status", self.wait_for_presences)
|
||||
|
||||
self.add_event_handler('vcard_avatar_update', self.on_vcard_avatar)
|
||||
self.add_event_handler('avatar_metadata_publish', self.on_avatar)
|
||||
|
||||
self.received = set()
|
||||
self.presences_received = threading.Event()
|
||||
self.presences_received = asyncio.Event()
|
||||
self.roster_received = asyncio.Event()
|
||||
|
||||
def roster_received_cb(self, event):
|
||||
self.roster_received.set()
|
||||
self.presences_received.clear()
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -68,16 +62,20 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
|
||||
data.
|
||||
"""
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
self.get_roster(callback=self.roster_received_cb)
|
||||
|
||||
print('Waiting for presence updates...\n')
|
||||
self.presences_received.wait(15)
|
||||
self.disconnect(wait=True)
|
||||
yield from self.roster_received.wait()
|
||||
print('Roster received')
|
||||
yield from self.presences_received.wait()
|
||||
self.disconnect()
|
||||
|
||||
@asyncio.coroutine
|
||||
def on_vcard_avatar(self, pres):
|
||||
print("Received vCard avatar update from %s" % pres['from'].bare)
|
||||
try:
|
||||
result = self['xep_0054'].get_vcard(pres['from'], cached=True)
|
||||
result = yield from self['xep_0054'].get_vcard(pres['from'].bare, cached=True,
|
||||
timeout=5)
|
||||
except XMPPError:
|
||||
print("Error retrieving avatar for %s" % pres['from'])
|
||||
return
|
||||
@@ -88,16 +86,18 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
|
||||
pres['from'].bare,
|
||||
pres['vcard_temp_update']['photo'],
|
||||
filetype)
|
||||
with open(filename, 'w+') as img:
|
||||
with open(filename, 'wb+') as img:
|
||||
img.write(avatar['BINVAL'])
|
||||
|
||||
@asyncio.coroutine
|
||||
def on_avatar(self, msg):
|
||||
print("Received avatar update from %s" % msg['from'])
|
||||
metadata = msg['pubsub_event']['items']['item']['avatar_metadata']
|
||||
for info in metadata['items']:
|
||||
if not info['url']:
|
||||
try:
|
||||
result = self['xep_0084'].retrieve_avatar(msg['from'], info['id'])
|
||||
result = yield from self['xep_0084'].retrieve_avatar(msg['from'].bare, info['id'],
|
||||
timeout=5)
|
||||
except XMPPError:
|
||||
print("Error retrieving avatar for %s" % msg['from'])
|
||||
return
|
||||
@@ -106,7 +106,7 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
|
||||
|
||||
filetype = FILE_TYPES.get(metadata['type'], 'png')
|
||||
filename = 'avatar_%s_%s.%s' % (msg['from'].bare, info['id'], filetype)
|
||||
with open(filename, 'w+') as img:
|
||||
with open(filename, 'wb+') as img:
|
||||
img.write(avatar['value'])
|
||||
else:
|
||||
# We could retrieve the avatar via HTTP, etc here instead.
|
||||
@@ -117,6 +117,7 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
|
||||
Wait to receive updates from all roster contacts.
|
||||
"""
|
||||
self.received.add(pres['from'].bare)
|
||||
print((len(self.received), len(self.client_roster.keys())))
|
||||
if len(self.received) >= len(self.client_roster.keys()):
|
||||
self.presences_received.set()
|
||||
else:
|
||||
@@ -125,60 +126,40 @@ class AvatarDownloader(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
optp.add_option('-q','--quiet', help='set logging to ERROR',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-d','--debug', help='set logging to DEBUG',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-v','--verbose', help='set logging to COMM',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=5,
|
||||
default=logging.ERROR)
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-q","--quiet", help="set logging to ERROR",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
parser.add_argument("-d","--debug", help="set logging to DEBUG",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
opts,args = optp.parse_args()
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
xmpp = AvatarDownloader(opts.jid, opts.password)
|
||||
xmpp = AvatarDownloader(args.jid, args.password)
|
||||
xmpp.register_plugin('xep_0054')
|
||||
xmpp.register_plugin('xep_0153')
|
||||
xmpp.register_plugin('xep_0084')
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,41 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class EchoBot(sleekxmpp.ClientXMPP):
|
||||
class EchoBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that will echo messages it
|
||||
A simple Slixmpp bot that will echo messages it
|
||||
receives, along with a short thank you message.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
@@ -83,75 +72,42 @@ class EchoBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser(description=EchoBot.__doc__)
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the EchoBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = EchoBot(opts.jid, opts.password)
|
||||
xmpp = EchoBot(args.jid, args.password)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0060') # PubSub
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# If you are connecting to Facebook and wish to use the
|
||||
# X-FACEBOOK-PLATFORM authentication mechanism, you will need
|
||||
# your API key and an access token. Then you'll set:
|
||||
# xmpp.credentials['api_key'] = 'THE_API_KEY'
|
||||
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
|
||||
|
||||
# If you are connecting to MSN, then you will need an
|
||||
# access token, and it does not matter what JID you
|
||||
# specify other than that the domain is 'messenger.live.com',
|
||||
# so '_@messenger.live.com' will work. You can specify
|
||||
# the access token as so:
|
||||
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,37 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.componentxmpp import ComponentXMPP
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
from slixmpp.componentxmpp import ComponentXMPP
|
||||
|
||||
|
||||
class EchoComponent(ComponentXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP component that echoes messages.
|
||||
A simple Slixmpp component that echoes messages.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, secret, server, port):
|
||||
@@ -67,56 +56,50 @@ class EchoComponent(ComponentXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser(description=EchoComponent.__doc__)
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-s", "--server", dest="server",
|
||||
help="server to connect to")
|
||||
optp.add_option("-P", "--port", dest="port",
|
||||
help="port to connect to")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-s", "--server", dest="server",
|
||||
help="server to connect to")
|
||||
parser.add_argument("-P", "--port", dest="port",
|
||||
help="port to connect to")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Component JID: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.server is None:
|
||||
opts.server = raw_input("Server: ")
|
||||
if opts.port is None:
|
||||
opts.port = int(raw_input("Port: "))
|
||||
if args.jid is None:
|
||||
args.jid = input("Component JID: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.server is None:
|
||||
args.server = input("Server: ")
|
||||
if args.port is None:
|
||||
args.port = int(input("Port: "))
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
# Setup the EchoComponent and register plugins. Note that while plugins
|
||||
# may have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = EchoComponent(opts.jid, opts.password, opts.server, opts.port)
|
||||
xmpp.registerPlugin('xep_0030') # Service Discovery
|
||||
xmpp.registerPlugin('xep_0004') # Data Forms
|
||||
xmpp.registerPlugin('xep_0060') # PubSub
|
||||
xmpp.registerPlugin('xep_0199') # XMPP Ping
|
||||
xmpp = EchoComponent(args.jid, args.password, args.server, args.port)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0060') # PubSub
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,46 +1,34 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
import slixmpp
|
||||
|
||||
import ssl
|
||||
from sleekxmpp.xmlstream import cert
|
||||
from slixmpp.xmlstream import cert
|
||||
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class GTalkBot(sleekxmpp.ClientXMPP):
|
||||
class GTalkBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A demonstration of using SleekXMPP with accounts from a Google Apps
|
||||
A demonstration of using Slixmpp with accounts from a Google Apps
|
||||
account with a custom domain, because it requires custom certificate
|
||||
validation.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
@@ -104,62 +92,42 @@ class GTalkBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the GTalkBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = GTalkBot(opts.jid, opts.password)
|
||||
xmpp = GTalkBot(args.jid, args.password)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0060') # PubSub
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
97
examples/http_over_xmpp.py
Normal file
97
examples/http_over_xmpp.py
Normal file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Implementation of HTTP over XMPP transport
|
||||
http://xmpp.org/extensions/xep-0332.html
|
||||
Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
|
||||
This file is part of slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp import ClientXMPP
|
||||
|
||||
from optparse import OptionParser
|
||||
import logging
|
||||
import getpass
|
||||
|
||||
|
||||
class HTTPOverXMPPClient(ClientXMPP):
|
||||
def __init__(self, jid, password):
|
||||
ClientXMPP.__init__(self, jid, password)
|
||||
self.register_plugin('xep_0332') # HTTP over XMPP Transport
|
||||
self.add_event_handler(
|
||||
'session_start', self.session_start, threaded=True
|
||||
)
|
||||
self.add_event_handler('http_request', self.http_request_received)
|
||||
self.add_event_handler('http_response', self.http_response_received)
|
||||
|
||||
def http_request_received(self, iq):
|
||||
pass
|
||||
|
||||
def http_response_received(self, iq):
|
||||
print('HTTP Response Received : %s' % iq)
|
||||
print('From : %s' % iq['from'])
|
||||
print('To : %s' % iq['to'])
|
||||
print('Type : %s' % iq['type'])
|
||||
print('Headers : %s' % iq['resp']['headers'])
|
||||
print('Code : %s' % iq['resp']['code'])
|
||||
print('Message : %s' % iq['resp']['message'])
|
||||
print('Data : %s' % iq['resp']['data'])
|
||||
|
||||
def session_start(self, event):
|
||||
# TODO: Fill in the blanks
|
||||
self['xep_0332'].send_request(
|
||||
to='?', method='?', resource='?', headers={}
|
||||
)
|
||||
self.disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
#
|
||||
# NOTE: To run this example, fill up the blanks in session_start() and
|
||||
# use the following command.
|
||||
#
|
||||
# ./http_over_xmpp.py -J <jid> -P <pwd> -i <ip> -p <port> [-v]
|
||||
#
|
||||
|
||||
parser = OptionParser()
|
||||
|
||||
# Output verbosity options.
|
||||
parser.add_option(
|
||||
'-v', '--verbose', help='set logging to DEBUG', action='store_const',
|
||||
dest='loglevel', const=logging.DEBUG, default=logging.ERROR
|
||||
)
|
||||
|
||||
# JID and password options.
|
||||
parser.add_option('-J', '--jid', dest='jid', help='JID')
|
||||
parser.add_option('-P', '--password', dest='password', help='Password')
|
||||
|
||||
# XMPP server ip and port options.
|
||||
parser.add_option(
|
||||
'-i', '--ipaddr', dest='ipaddr',
|
||||
help='IP Address of the XMPP server', default=None
|
||||
)
|
||||
parser.add_option(
|
||||
'-p', '--port', dest='port',
|
||||
help='Port of the XMPP server', default=None
|
||||
)
|
||||
|
||||
opts, args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = input('Username: ')
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass('Password: ')
|
||||
|
||||
xmpp = HTTPOverXMPPClient(opts.jid, opts.password)
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,45 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class IBBReceiver(sleekxmpp.ClientXMPP):
|
||||
class IBBReceiver(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic example of creating and using an in-band bytestream.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
def __init__(self, jid, password, filename):
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.register_plugin('xep_0030') # Service Discovery
|
||||
self.register_plugin('xep_0047', {
|
||||
'auto_accept': True
|
||||
}) # In-band Bytestreams
|
||||
self.file = open(filename, 'wb')
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
@@ -48,8 +34,9 @@ class IBBReceiver(sleekxmpp.ClientXMPP):
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
self.add_event_handler("ibb_stream_start", self.stream_opened, threaded=True)
|
||||
self.add_event_handler("ibb_stream_start", self.stream_opened)
|
||||
self.add_event_handler("ibb_stream_data", self.stream_data)
|
||||
self.add_event_handler("ibb_stream_end", self.stream_closed)
|
||||
|
||||
def start(self, event):
|
||||
"""
|
||||
@@ -67,81 +54,59 @@ class IBBReceiver(sleekxmpp.ClientXMPP):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
|
||||
def accept_stream(self, iq):
|
||||
"""
|
||||
Check that it is ok to accept a stream request.
|
||||
|
||||
Controlling stream acceptance can be done via either:
|
||||
- setting 'auto_accept' to False in the plugin
|
||||
configuration. The default is True.
|
||||
- setting 'accept_stream' to a function which accepts
|
||||
an Iq stanza as its argument, like this one.
|
||||
|
||||
The accept_stream function will be used if it exists, and the
|
||||
auto_accept value will be used otherwise.
|
||||
"""
|
||||
return True
|
||||
|
||||
def stream_opened(self, stream):
|
||||
print('Stream opened: %s from %s' % (stream.sid, stream.peer_jid))
|
||||
|
||||
# You could run a loop reading from the stream using stream.recv(),
|
||||
# or use the ibb_stream_data event.
|
||||
def stream_data(self, stream):
|
||||
self.file.write(stream.read())
|
||||
|
||||
def stream_data(self, event):
|
||||
print(event['data'])
|
||||
def stream_closed(self, stream):
|
||||
print('Stream closed: %s from %s' % (stream.sid, stream.peer_jid))
|
||||
self.file.close()
|
||||
self.disconnect()
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-o", "--out", dest="filename",
|
||||
help="file to save to")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.filename is None:
|
||||
args.filename = input("File path: ")
|
||||
|
||||
xmpp = IBBReceiver(opts.jid, opts.password)
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
# Setup the IBBReceiver and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = IBBReceiver(args.jid, args.password, args.filename)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0047', {
|
||||
'auto_accept': True
|
||||
}) # In-band Bytestreams
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process(forever=False)
|
||||
|
@@ -1,43 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import asyncio
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
|
||||
|
||||
class IBBSender(sleekxmpp.ClientXMPP):
|
||||
class IBBSender(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic example of creating and using an in-band bytestream.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, receiver, filename):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
def __init__(self, jid, password, receiver, filename, use_messages=False):
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.receiver = receiver
|
||||
self.filename = filename
|
||||
|
||||
self.file = open(filename, 'rb')
|
||||
self.use_messages = use_messages
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
@@ -46,6 +39,7 @@ class IBBSender(sleekxmpp.ClientXMPP):
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -62,84 +56,70 @@ class IBBSender(sleekxmpp.ClientXMPP):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
|
||||
# For the purpose of demonstration, we'll set a very small block
|
||||
# size. The default block size is 4096. We'll also use a window
|
||||
# allowing sending multiple blocks at a time; in this case, three
|
||||
# block transfers may be in progress at any time.
|
||||
stream = self['xep_0047'].open_stream(self.receiver)
|
||||
try:
|
||||
# Open the IBB stream in which to write to.
|
||||
stream = yield from self['xep_0047'].open_stream(self.receiver, use_messages=self.use_messages)
|
||||
|
||||
with open(self.filename) as f:
|
||||
data = f.read()
|
||||
stream.sendall(data)
|
||||
# If you want to send in-memory bytes, use stream.sendall() instead.
|
||||
yield from stream.sendfile(self.file, timeout=10)
|
||||
|
||||
# And finally close the stream.
|
||||
yield from stream.close(timeout=10)
|
||||
except (IqError, IqTimeout):
|
||||
print('File transfer errored')
|
||||
else:
|
||||
print('File transfer finished')
|
||||
finally:
|
||||
self.file.close()
|
||||
self.disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-r", "--receiver", dest="receiver",
|
||||
help="JID to use")
|
||||
optp.add_option("-f", "--file", dest="filename",
|
||||
help="JID to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-r", "--receiver", dest="receiver",
|
||||
help="JID of the receiver")
|
||||
parser.add_argument("-f", "--file", dest="filename",
|
||||
help="file to send")
|
||||
parser.add_argument("-m", "--use-messages", action="store_true",
|
||||
help="use messages instead of iqs for file transfer")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.receiver is None:
|
||||
opts.receiver = raw_input("Receiver: ")
|
||||
if opts.filename is None:
|
||||
opts.filename = raw_input("File path: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.receiver is None:
|
||||
args.receiver = input("Receiver: ")
|
||||
if args.filename is None:
|
||||
args.filename = input("File path: ")
|
||||
|
||||
# Setup the EchoBot and register plugins. Note that while plugins may
|
||||
# Setup the IBBSender and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = IBBSender(opts.jid, opts.password, opts.receiver, opts.filename)
|
||||
xmpp = IBBSender(args.jid, args.password, args.receiver, args.filename, args.use_messages)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0047') # In-band Bytestreams
|
||||
xmpp.register_plugin('xep_0060') # PubSub
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process(forever=False)
|
||||
|
@@ -1,68 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("--oldjid", dest="old_jid",
|
||||
help="JID of the old account")
|
||||
optp.add_option("--oldpassword", dest="old_password",
|
||||
help="password of the old account")
|
||||
parser.add_argument("--oldjid", dest="old_jid",
|
||||
help="JID of the old account")
|
||||
parser.add_argument("--oldpassword", dest="old_password",
|
||||
help="password of the old account")
|
||||
|
||||
optp.add_option("--newjid", dest="new_jid",
|
||||
help="JID of the old account")
|
||||
optp.add_option("--newpassword", dest="new_password",
|
||||
help="password of the old account")
|
||||
parser.add_argument("--newjid", dest="new_jid",
|
||||
help="JID of the old account")
|
||||
parser.add_argument("--newpassword", dest="new_password",
|
||||
help="password of the old account")
|
||||
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.old_jid is None:
|
||||
opts.old_jid = raw_input("Old JID: ")
|
||||
if opts.old_password is None:
|
||||
opts.old_password = getpass.getpass("Old Password: ")
|
||||
if args.old_jid is None:
|
||||
args.old_jid = input("Old JID: ")
|
||||
if args.old_password is None:
|
||||
args.old_password = getpass("Old Password: ")
|
||||
|
||||
if opts.new_jid is None:
|
||||
opts.new_jid = raw_input("New JID: ")
|
||||
if opts.new_password is None:
|
||||
opts.new_password = getpass.getpass("New Password: ")
|
||||
if args.new_jid is None:
|
||||
args.new_jid = input("New JID: ")
|
||||
if args.new_password is None:
|
||||
args.new_password = getpass("New Password: ")
|
||||
|
||||
|
||||
old_xmpp = sleekxmpp.ClientXMPP(opts.old_jid, opts.old_password)
|
||||
old_xmpp = slixmpp.ClientXMPP(args.old_jid, args.old_password)
|
||||
|
||||
# If you are connecting to Facebook and wish to use the
|
||||
# X-FACEBOOK-PLATFORM authentication mechanism, you will need
|
||||
@@ -98,7 +85,7 @@ if not roster:
|
||||
print('No roster to migrate')
|
||||
sys.exit()
|
||||
|
||||
new_xmpp = sleekxmpp.ClientXMPP(opts.new_jid, opts.new_password)
|
||||
new_xmpp = slixmpp.ClientXMPP(args.new_jid, args.new_password)
|
||||
def on_session2(event):
|
||||
new_xmpp.get_roster()
|
||||
new_xmpp.send_presence()
|
||||
@@ -113,8 +100,8 @@ def on_session2(event):
|
||||
new_xmpp.update_roster(jid,
|
||||
name = item['name'],
|
||||
groups = item['groups'])
|
||||
new_xmpp.disconnect()
|
||||
new_xmpp.disconnect()
|
||||
new_xmpp.add_event_handler('session_start', on_session2)
|
||||
|
||||
if new_xmpp.connect():
|
||||
new_xmpp.process(block=True)
|
||||
new_xmpp.connect()
|
||||
new_xmpp.process()
|
||||
|
108
examples/muc.py
108
examples/muc.py
@@ -1,42 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class MUCBot(sleekxmpp.ClientXMPP):
|
||||
class MUCBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that will greets those
|
||||
A simple Slixmpp bot that will greets those
|
||||
who enter the room, and acknowledge any messages
|
||||
that mentions the bot's nickname.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, room, nick):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.room = room
|
||||
self.nick = nick
|
||||
@@ -78,11 +67,11 @@ class MUCBot(sleekxmpp.ClientXMPP):
|
||||
"""
|
||||
self.get_roster()
|
||||
self.send_presence()
|
||||
self.plugin['xep_0045'].joinMUC(self.room,
|
||||
self.nick,
|
||||
# If a room password is needed, use:
|
||||
# password=the_room_password,
|
||||
wait=True)
|
||||
self.plugin['xep_0045'].join_muc(self.room,
|
||||
self.nick,
|
||||
# If a room password is needed, use:
|
||||
# password=the_room_password,
|
||||
wait=True)
|
||||
|
||||
def muc_message(self, msg):
|
||||
"""
|
||||
@@ -132,62 +121,49 @@ class MUCBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-r", "--room", dest="room",
|
||||
help="MUC room to join")
|
||||
optp.add_option("-n", "--nick", dest="nick",
|
||||
help="MUC nickname")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-r", "--room", dest="room",
|
||||
help="MUC room to join")
|
||||
parser.add_argument("-n", "--nick", dest="nick",
|
||||
help="MUC nickname")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.room is None:
|
||||
opts.room = raw_input("MUC room: ")
|
||||
if opts.nick is None:
|
||||
opts.nick = raw_input("MUC nickname: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.room is None:
|
||||
args.room = input("MUC room: ")
|
||||
if args.nick is None:
|
||||
args.nick = input("MUC nickname: ")
|
||||
|
||||
# Setup the MUCBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = MUCBot(opts.jid, opts.password, opts.room, opts.nick)
|
||||
xmpp = MUCBot(args.jid, args.password, args.room, args.nick)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0045') # Multi-User Chat
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
103
examples/ping.py
103
examples/ping.py
@@ -1,41 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp import asyncio
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class PingTest(sleekxmpp.ClientXMPP):
|
||||
class PingTest(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that will send a ping request
|
||||
A simple Slixmpp bot that will send a ping request
|
||||
to a given JID.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, pingjid):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
if pingjid is None:
|
||||
pingjid = self.boundjid.bare
|
||||
self.pingjid = pingjid
|
||||
@@ -45,8 +36,9 @@ class PingTest(sleekxmpp.ClientXMPP):
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -64,8 +56,8 @@ class PingTest(sleekxmpp.ClientXMPP):
|
||||
self.get_roster()
|
||||
|
||||
try:
|
||||
rtt = self['xep_0199'].ping(self.pingjid,
|
||||
timeout=10)
|
||||
rtt = yield from self['xep_0199'].ping(self.pingjid,
|
||||
timeout=10)
|
||||
logging.info("Success! RTT: %s", rtt)
|
||||
except IqError as e:
|
||||
logging.info("Error pinging %s: %s",
|
||||
@@ -79,65 +71,44 @@ class PingTest(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
optp.add_option('-t', '--pingto', help='set jid to ping',
|
||||
action='store', type='string', dest='pingjid',
|
||||
default=None)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
parser.add_argument("-t", "--pingto", help="set jid to ping",
|
||||
dest="pingjid", default=None)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the PingTest and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = PingTest(opts.jid, opts.password, opts.pingjid)
|
||||
xmpp = PingTest(args.jid, args.password, args.pingjid)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0060') # PubSub
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,41 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class EchoBot(sleekxmpp.ClientXMPP):
|
||||
class EchoBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that will echo messages it
|
||||
A simple Slixmpp bot that will echo messages it
|
||||
receives, along with a short thank you message.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
@@ -82,87 +71,65 @@ class EchoBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("--phost", dest="proxy_host",
|
||||
help="Proxy hostname")
|
||||
optp.add_option("--pport", dest="proxy_port",
|
||||
help="Proxy port")
|
||||
optp.add_option("--puser", dest="proxy_user",
|
||||
help="Proxy username")
|
||||
optp.add_option("--ppass", dest="proxy_pass",
|
||||
help="Proxy password")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("--phost", dest="proxy_host",
|
||||
help="Proxy hostname")
|
||||
parser.add_argument("--pport", dest="proxy_port",
|
||||
help="Proxy port")
|
||||
parser.add_argument("--puser", dest="proxy_user",
|
||||
help="Proxy username")
|
||||
parser.add_argument("--ppass", dest="proxy_pass",
|
||||
help="Proxy password")
|
||||
|
||||
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.proxy_host is None:
|
||||
opts.proxy_host = raw_input("Proxy host: ")
|
||||
if opts.proxy_port is None:
|
||||
opts.proxy_port = raw_input("Proxy port: ")
|
||||
if opts.proxy_user is None:
|
||||
opts.proxy_user = raw_input("Proxy username: ")
|
||||
if opts.proxy_pass is None and opts.proxy_user:
|
||||
opts.proxy_pass = getpass.getpass("Proxy password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.proxy_host is None:
|
||||
args.proxy_host = input("Proxy host: ")
|
||||
if args.proxy_port is None:
|
||||
args.proxy_port = input("Proxy port: ")
|
||||
if args.proxy_user is None:
|
||||
args.proxy_user = input("Proxy username: ")
|
||||
if args.proxy_pass is None and args.proxy_user:
|
||||
args.proxy_pass = getpass("Proxy password: ")
|
||||
|
||||
# Setup the EchoBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = EchoBot(opts.jid, opts.password)
|
||||
xmpp = EchoBot(args.jid, args.password)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0060') # PubSub
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
xmpp.use_proxy = True
|
||||
xmpp.proxy_config = {
|
||||
'host': opts.proxy_host,
|
||||
'port': int(opts.proxy_port),
|
||||
'username': opts.proxy_user,
|
||||
'password': opts.proxy_pass}
|
||||
'host': args.proxy_host,
|
||||
'port': int(args.proxy_port),
|
||||
'username': args.proxy_user,
|
||||
'password': args.proxy_pass}
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,31 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.xmlstream import ET, tostring
|
||||
import asyncio
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp.xmlstream import ET, tostring
|
||||
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class PubsubClient(sleekxmpp.ClientXMPP):
|
||||
class PubsubClient(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password, server,
|
||||
node=None, action='list', data=''):
|
||||
super(PubsubClient, self).__init__(jid, password)
|
||||
node=None, action='nodes', data=''):
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.register_plugin('xep_0030')
|
||||
self.register_plugin('xep_0059')
|
||||
@@ -40,162 +30,137 @@ class PubsubClient(sleekxmpp.ClientXMPP):
|
||||
self.data = data
|
||||
self.pubsub_server = server
|
||||
|
||||
self.add_event_handler('session_start', self.start, threaded=True)
|
||||
self.add_event_handler('session_start', self.start)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
self.get_roster()
|
||||
self.send_presence()
|
||||
|
||||
try:
|
||||
getattr(self, self.action)()
|
||||
yield from getattr(self, self.action)()
|
||||
except:
|
||||
logging.error('Could not execute: %s' % self.action)
|
||||
logging.error('Could not execute: %s', self.action)
|
||||
self.disconnect()
|
||||
|
||||
def nodes(self):
|
||||
try:
|
||||
result = self['xep_0060'].get_nodes(self.pubsub_server, self.node)
|
||||
result = yield from self['xep_0060'].get_nodes(self.pubsub_server, self.node)
|
||||
for item in result['disco_items']['items']:
|
||||
print(' - %s' % str(item))
|
||||
except:
|
||||
logging.error('Could not retrieve node list.')
|
||||
logging.info(' - %s', str(item))
|
||||
except XMPPError as error:
|
||||
logging.error('Could not retrieve node list: %s', error.format())
|
||||
|
||||
def create(self):
|
||||
try:
|
||||
self['xep_0060'].create_node(self.pubsub_server, self.node)
|
||||
except:
|
||||
logging.error('Could not create node: %s' % self.node)
|
||||
yield from self['xep_0060'].create_node(self.pubsub_server, self.node)
|
||||
logging.info('Created node %s', self.node)
|
||||
except XMPPError as error:
|
||||
logging.error('Could not create node %s: %s', self.node, error.format())
|
||||
|
||||
def delete(self):
|
||||
try:
|
||||
self['xep_0060'].delete_node(self.pubsub_server, self.node)
|
||||
print('Deleted node: %s' % self.node)
|
||||
except:
|
||||
logging.error('Could not delete node: %s' % self.node)
|
||||
yield from self['xep_0060'].delete_node(self.pubsub_server, self.node)
|
||||
logging.info('Deleted node %s', self.node)
|
||||
except XMPPError as error:
|
||||
logging.error('Could not delete node %s: %s', self.node, error.format())
|
||||
|
||||
def publish(self):
|
||||
payload = ET.fromstring("<test xmlns='test'>%s</test>" % self.data)
|
||||
try:
|
||||
result = self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload)
|
||||
id = result['pubsub']['publish']['item']['id']
|
||||
print('Published at item id: %s' % id)
|
||||
except:
|
||||
logging.error('Could not publish to: %s' % self.node)
|
||||
result = yield from self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload)
|
||||
logging.info('Published at item id: %s', result['pubsub']['publish']['item']['id'])
|
||||
except XMPPError as error:
|
||||
logging.error('Could not publish to %s: %s', self.node, error.format())
|
||||
|
||||
def get(self):
|
||||
try:
|
||||
result = self['xep_0060'].get_item(self.pubsub_server, self.node, self.data)
|
||||
result = yield from self['xep_0060'].get_item(self.pubsub_server, self.node, self.data)
|
||||
for item in result['pubsub']['items']['substanzas']:
|
||||
print('Retrieved item %s: %s' % (item['id'], tostring(item['payload'])))
|
||||
except:
|
||||
logging.error('Could not retrieve item %s from node %s' % (self.data, self.node))
|
||||
logging.info('Retrieved item %s: %s', item['id'], tostring(item['payload']))
|
||||
except XMPPError as error:
|
||||
logging.error('Could not retrieve item %s from node %s: %s', self.data, self.node, error.format())
|
||||
|
||||
def retract(self):
|
||||
try:
|
||||
result = self['xep_0060'].retract(self.pubsub_server, self.node, self.data)
|
||||
print('Retracted item %s from node %s' % (self.data, self.node))
|
||||
except:
|
||||
logging.error('Could not retract item %s from node %s' % (self.data, self.node))
|
||||
yield from self['xep_0060'].retract(self.pubsub_server, self.node, self.data)
|
||||
logging.info('Retracted item %s from node %s', self.data, self.node)
|
||||
except XMPPError as error:
|
||||
logging.error('Could not retract item %s from node %s: %s', self.data, self.node, error.format())
|
||||
|
||||
def purge(self):
|
||||
try:
|
||||
result = self['xep_0060'].purge(self.pubsub_server, self.node)
|
||||
print('Purged all items from node %s' % self.node)
|
||||
except:
|
||||
logging.error('Could not purge items from node %s' % self.node)
|
||||
yield from self['xep_0060'].purge(self.pubsub_server, self.node)
|
||||
logging.info('Purged all items from node %s', self.node)
|
||||
except XMPPError as error:
|
||||
logging.error('Could not purge items from node %s: %s', self.node, error.format())
|
||||
|
||||
def subscribe(self):
|
||||
try:
|
||||
result = self['xep_0060'].subscribe(self.pubsub_server, self.node)
|
||||
print('Subscribed %s to node %s' % (self.boundjid.bare, self.node))
|
||||
except:
|
||||
logging.error('Could not subscribe %s to node %s' % (self.boundjid.bare, self.node))
|
||||
iq = yield from self['xep_0060'].subscribe(self.pubsub_server, self.node)
|
||||
subscription = iq['pubsub']['subscription']
|
||||
logging.info('Subscribed %s to node %s', subscription['jid'], subscription['node'])
|
||||
except XMPPError as error:
|
||||
logging.error('Could not subscribe %s to node %s: %s', self.boundjid.bare, self.node, error.format())
|
||||
|
||||
def unsubscribe(self):
|
||||
try:
|
||||
result = self['xep_0060'].unsubscribe(self.pubsub_server, self.node)
|
||||
print('Unsubscribed %s from node %s' % (self.boundjid.bare, self.node))
|
||||
except:
|
||||
logging.error('Could not unsubscribe %s from node %s' % (self.boundjid.bare, self.node))
|
||||
yield from self['xep_0060'].unsubscribe(self.pubsub_server, self.node)
|
||||
logging.info('Unsubscribed %s from node %s', self.boundjid.bare, self.node)
|
||||
except XMPPError as error:
|
||||
logging.error('Could not unsubscribe %s from node %s: %s', self.boundjid.bare, self.node, error.format())
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
optp.version = '%%prog 0.1'
|
||||
optp.usage = "Usage: %%prog [options] <jid> " + \
|
||||
parser = ArgumentParser()
|
||||
parser.version = '%%prog 0.1'
|
||||
parser.usage = "Usage: %%prog [options] <jid> " + \
|
||||
'nodes|create|delete|purge|subscribe|unsubscribe|publish|retract|get' + \
|
||||
' [<node> <data>]'
|
||||
|
||||
optp.add_option('-q','--quiet', help='set logging to ERROR',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-d','--debug', help='set logging to DEBUG',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-v','--verbose', help='set logging to COMM',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=5,
|
||||
default=logging.ERROR)
|
||||
parser.add_argument("-q","--quiet", help="set logging to ERROR",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.ERROR,
|
||||
default=logging.INFO)
|
||||
parser.add_argument("-d","--debug", help="set logging to DEBUG",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.DEBUG,
|
||||
default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
opts,args = optp.parse_args()
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
parser.add_argument("server")
|
||||
parser.add_argument("action", choices=["nodes", "create", "delete", "purge", "subscribe", "unsubscribe", "publish", "retract", "get"])
|
||||
parser.add_argument("node", nargs='?')
|
||||
parser.add_argument("data", nargs='?')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if len(args) < 2:
|
||||
optp.print_help()
|
||||
exit()
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
|
||||
if len(args) == 2:
|
||||
args = (args[0], args[1], '', '', '')
|
||||
elif len(args) == 3:
|
||||
args = (args[0], args[1], args[2], '', '')
|
||||
elif len(args) == 4:
|
||||
args = (args[0], args[1], args[2], args[3], '')
|
||||
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the Pubsub client
|
||||
xmpp = PubsubClient(opts.jid, opts.password,
|
||||
server=args[0],
|
||||
node=args[2],
|
||||
action=args[1],
|
||||
data=args[3])
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
xmpp = PubsubClient(args.jid, args.password,
|
||||
server=args.server,
|
||||
node=args.node,
|
||||
action=args.action,
|
||||
data=args.data)
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process(forever=False)
|
||||
|
@@ -1,32 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.xmlstream import ET, tostring
|
||||
from sleekxmpp.xmlstream.matcher import StanzaPath
|
||||
from sleekxmpp.xmlstream.handler import Callback
|
||||
import slixmpp
|
||||
from slixmpp.xmlstream import ET, tostring
|
||||
from slixmpp.xmlstream.matcher import StanzaPath
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class PubsubEvents(sleekxmpp.ClientXMPP):
|
||||
class PubsubEvents(slixmpp.ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(PubsubEvents, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.register_plugin('xep_0030')
|
||||
self.register_plugin('xep_0059')
|
||||
@@ -96,59 +84,39 @@ class PubsubEvents(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
logging.info("Run this in conjunction with the pubsub_client.py " + \
|
||||
"example to watch events happen as you give commands.")
|
||||
|
||||
# Setup the PubsubEvents listener
|
||||
xmpp = PubsubEvents(opts.jid, opts.password)
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
xmpp = PubsubEvents(args.jid, args.password)
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,34 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.exceptions import IqError, IqTimeout
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
|
||||
|
||||
class RegisterBot(sleekxmpp.ClientXMPP):
|
||||
class RegisterBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic bot that will attempt to register an account
|
||||
@@ -40,23 +29,23 @@ class RegisterBot(sleekxmpp.ClientXMPP):
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
# The register event provides an Iq result stanza with
|
||||
# a registration form from the server. This may include
|
||||
# the basic registration fields, a data form, an
|
||||
# out-of-band URL, or any combination. For more advanced
|
||||
# cases, you will need to examine the fields provided
|
||||
# and respond accordingly. SleekXMPP provides plugins
|
||||
# and respond accordingly. Slixmpp provides plugins
|
||||
# for data forms and OOB links that will make that easier.
|
||||
self.add_event_handler("register", self.register, threaded=True)
|
||||
self.add_event_handler("register", self.register)
|
||||
|
||||
def start(self, event):
|
||||
"""
|
||||
@@ -101,7 +90,7 @@ class RegisterBot(sleekxmpp.ClientXMPP):
|
||||
resp['register']['password'] = self.password
|
||||
|
||||
try:
|
||||
resp.send(now=True)
|
||||
yield from resp.send()
|
||||
logging.info("Account created for %s!" % self.boundjid)
|
||||
except IqError as e:
|
||||
logging.error("Could not register account: %s" %
|
||||
@@ -114,40 +103,37 @@ class RegisterBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Setup the RegisterBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = RegisterBot(opts.jid, opts.password)
|
||||
xmpp = RegisterBot(args.jid, args.password)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data forms
|
||||
xmpp.register_plugin('xep_0066') # Out-of-band Data
|
||||
@@ -157,23 +143,6 @@ if __name__ == '__main__':
|
||||
# though they allow it. If this applies to your server, use:
|
||||
xmpp['xep_0077'].force_registration = True
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,36 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
import threading
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.exceptions import IqError, IqTimeout
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp.xmlstream.asyncio import asyncio
|
||||
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class RosterBrowser(sleekxmpp.ClientXMPP):
|
||||
class RosterBrowser(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic script for dumping a client's roster to
|
||||
@@ -38,20 +26,19 @@ class RosterBrowser(sleekxmpp.ClientXMPP):
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster. We need threaded=True so that the
|
||||
# session_start handler doesn't block event processing
|
||||
# while we wait for presence stanzas to arrive.
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start)
|
||||
self.add_event_handler("changed_status", self.wait_for_presences)
|
||||
|
||||
self.received = set()
|
||||
self.presences_received = threading.Event()
|
||||
self.presences_received = asyncio.Event()
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -65,17 +52,21 @@ class RosterBrowser(sleekxmpp.ClientXMPP):
|
||||
event does not provide any additional
|
||||
data.
|
||||
"""
|
||||
future = asyncio.Future()
|
||||
def callback(result):
|
||||
future.set_result(None)
|
||||
try:
|
||||
self.get_roster()
|
||||
self.get_roster(callback=callback)
|
||||
yield from future
|
||||
except IqError as err:
|
||||
print('Error: %' % err.iq['error']['condition'])
|
||||
print('Error: %s' % err.iq['error']['condition'])
|
||||
except IqTimeout:
|
||||
print('Error: Request timed out')
|
||||
self.send_presence()
|
||||
|
||||
|
||||
print('Waiting for presence updates...\n')
|
||||
self.presences_received.wait(5)
|
||||
yield from asyncio.sleep(10)
|
||||
|
||||
print('Roster for %s' % self.boundjid.bare)
|
||||
groups = self.client_roster.groups()
|
||||
@@ -115,58 +106,37 @@ class RosterBrowser(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
optp.add_option('-q','--quiet', help='set logging to ERROR',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-d','--debug', help='set logging to DEBUG',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-v','--verbose', help='set logging to COMM',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=5,
|
||||
default=logging.ERROR)
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-q","--quiet", help="set logging to ERROR",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
parser.add_argument("-d","--debug", help="set logging to DEBUG",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
opts,args = optp.parse_args()
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
xmpp = RosterBrowser(opts.jid, opts.password)
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
xmpp = RosterBrowser(args.jid, args.password)
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Dann Martens
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||
from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||
ANY_ALL, Future
|
||||
import time
|
||||
|
||||
@@ -20,7 +20,7 @@ class Boomerang(Endpoint):
|
||||
|
||||
@remote
|
||||
def throw(self):
|
||||
print "Duck!"
|
||||
print("Duck!")
|
||||
|
||||
|
||||
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Dann Martens
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||
from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||
ANY_ALL
|
||||
import threading
|
||||
import time
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Dann Martens
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||
from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||
ANY_ALL
|
||||
import threading
|
||||
|
||||
|
90
examples/s5b_transfer/s5b_receiver.py
Executable file
90
examples/s5b_transfer/s5b_receiver.py
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2015 Emmanuel Gil Peyrot
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
|
||||
|
||||
class S5BReceiver(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic example of creating and using a SOCKS5 bytestream.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, filename):
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.file = open(filename, 'wb')
|
||||
|
||||
self.add_event_handler("socks5_connected", self.stream_opened)
|
||||
self.add_event_handler("socks5_data", self.stream_data)
|
||||
self.add_event_handler("socks5_closed", self.stream_closed)
|
||||
|
||||
def stream_opened(self, sid):
|
||||
logging.info('Stream opened. %s', sid)
|
||||
|
||||
def stream_data(self, data):
|
||||
self.file.write(data)
|
||||
|
||||
def stream_closed(self, exception):
|
||||
logging.info('Stream closed. %s', exception)
|
||||
self.file.close()
|
||||
self.disconnect()
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-o", "--out", dest="filename",
|
||||
help="file to save to")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.filename is None:
|
||||
args.filename = input("File path: ")
|
||||
|
||||
# Setup the S5BReceiver and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = S5BReceiver(args.jid, args.password, args.filename)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0065', {
|
||||
'auto_accept': True
|
||||
}) # SOCKS5 Bytestreams
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
xmpp.connect()
|
||||
xmpp.process(forever=False)
|
124
examples/s5b_transfer/s5b_sender.py
Executable file
124
examples/s5b_transfer/s5b_sender.py
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2015 Emmanuel Gil Peyrot
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
|
||||
|
||||
class S5BSender(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic example of creating and using a SOCKS5 bytestream.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, receiver, filename):
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.receiver = receiver
|
||||
|
||||
self.file = open(filename, 'rb')
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
# and the XML streams are ready for use.
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
|
||||
Typical actions for the session_start event are
|
||||
requesting the roster and broadcasting an initial
|
||||
presence stanza.
|
||||
|
||||
Arguments:
|
||||
event -- An empty dictionary. The session_start
|
||||
event does not provide any additional
|
||||
data.
|
||||
"""
|
||||
|
||||
try:
|
||||
# Open the S5B stream in which to write to.
|
||||
proxy = yield from self['xep_0065'].handshake(self.receiver)
|
||||
|
||||
# Send the entire file.
|
||||
while True:
|
||||
data = self.file.read(1048576)
|
||||
if not data:
|
||||
break
|
||||
yield from proxy.write(data)
|
||||
|
||||
# And finally close the stream.
|
||||
proxy.transport.write_eof()
|
||||
except (IqError, IqTimeout):
|
||||
print('File transfer errored')
|
||||
else:
|
||||
print('File transfer finished')
|
||||
finally:
|
||||
self.file.close()
|
||||
self.disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-r", "--receiver", dest="receiver",
|
||||
help="JID of the receiver")
|
||||
parser.add_argument("-f", "--file", dest="filename",
|
||||
help="file to send")
|
||||
parser.add_argument("-m", "--use-messages", action="store_true",
|
||||
help="use messages instead of iqs for file transfer")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.receiver is None:
|
||||
args.receiver = input("Receiver: ")
|
||||
if args.filename is None:
|
||||
args.filename = input("File path: ")
|
||||
|
||||
# Setup the S5BSender and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = S5BSender(args.jid, args.password, args.receiver, args.filename)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0065') # SOCKS5 Bytestreams
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
xmpp.connect()
|
||||
xmpp.process(forever=False)
|
@@ -1,41 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
|
||||
|
||||
class SendMsgBot(sleekxmpp.ClientXMPP):
|
||||
class SendMsgBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic SleekXMPP bot that will log in, send a message,
|
||||
A basic Slixmpp bot that will log in, send a message,
|
||||
and then log out.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, recipient, message):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The message we wish to send, and the JID that
|
||||
# will receive it.
|
||||
@@ -47,7 +36,7 @@ class SendMsgBot(sleekxmpp.ClientXMPP):
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
def start(self, event):
|
||||
"""
|
||||
@@ -69,75 +58,53 @@ class SendMsgBot(sleekxmpp.ClientXMPP):
|
||||
mbody=self.msg,
|
||||
mtype='chat')
|
||||
|
||||
# Using wait=True ensures that the send queue will be
|
||||
# emptied before ending the session.
|
||||
self.disconnect(wait=True)
|
||||
self.disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser(description=SendMsgBot.__doc__)
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-t", "--to", dest="to",
|
||||
help="JID to send the message to")
|
||||
optp.add_option("-m", "--message", dest="message",
|
||||
help="message to send")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-t", "--to", dest="to",
|
||||
help="JID to send the message to")
|
||||
parser.add_argument("-m", "--message", dest="message",
|
||||
help="message to send")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.to is None:
|
||||
opts.to = raw_input("Send To: ")
|
||||
if opts.message is None:
|
||||
opts.message = raw_input("Message: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.to is None:
|
||||
args.to = input("Send To: ")
|
||||
if args.message is None:
|
||||
args.message = input("Message: ")
|
||||
|
||||
# Setup the EchoBot and register plugins. Note that while plugins may
|
||||
# have interdependencies, the order in which you register them does
|
||||
# not matter.
|
||||
xmpp = SendMsgBot(opts.jid, opts.password, opts.to, opts.message)
|
||||
xmpp = SendMsgBot(args.jid, args.password, args.to, args.message)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,50 +1,39 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import imghdr
|
||||
import logging
|
||||
import getpass
|
||||
from getpass import getpass
|
||||
import threading
|
||||
from optparse import OptionParser
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.exceptions import XMPPError
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp import asyncio
|
||||
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
|
||||
|
||||
class AvatarSetter(sleekxmpp.ClientXMPP):
|
||||
class AvatarSetter(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A basic script for downloading the avatars for a user's contacts.
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password, filepath):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
self.add_event_handler("session_start", self.start, threaded=True)
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
self.filepath = filepath
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -63,7 +52,7 @@ class AvatarSetter(sleekxmpp.ClientXMPP):
|
||||
|
||||
avatar_file = None
|
||||
try:
|
||||
avatar_file = open(os.path.expanduser(self.filepath))
|
||||
avatar_file = open(os.path.expanduser(self.filepath), 'rb')
|
||||
except IOError:
|
||||
print('Could not find file: %s' % self.filepath)
|
||||
return self.disconnect()
|
||||
@@ -77,32 +66,31 @@ class AvatarSetter(sleekxmpp.ClientXMPP):
|
||||
avatar_file.close()
|
||||
|
||||
used_xep84 = False
|
||||
try:
|
||||
print('Publish XEP-0084 avatar data')
|
||||
self['xep_0084'].publish_avatar(avatar)
|
||||
used_xep84 = True
|
||||
except XMPPError:
|
||||
print('Could not publish XEP-0084 avatar')
|
||||
|
||||
try:
|
||||
print('Update vCard with avatar')
|
||||
self['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type)
|
||||
except XMPPError:
|
||||
print('Publish XEP-0084 avatar data')
|
||||
result = yield from self['xep_0084'].publish_avatar(avatar)
|
||||
if isinstance(result, XMPPError):
|
||||
print('Could not publish XEP-0084 avatar')
|
||||
else:
|
||||
used_xep84 = True
|
||||
|
||||
print('Update vCard with avatar')
|
||||
result = yield from self['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type)
|
||||
if isinstance(result, XMPPError):
|
||||
print('Could not set vCard avatar')
|
||||
|
||||
if used_xep84:
|
||||
try:
|
||||
print('Advertise XEP-0084 avatar metadata')
|
||||
self['xep_0084'].publish_avatar_metadata([
|
||||
{'id': avatar_id,
|
||||
'type': avatar_type,
|
||||
'bytes': avatar_bytes}
|
||||
# We could advertise multiple avatars to provide
|
||||
# options in image type, source (HTTP vs pubsub),
|
||||
# size, etc.
|
||||
# {'id': ....}
|
||||
])
|
||||
except XMPPError:
|
||||
print('Advertise XEP-0084 avatar metadata')
|
||||
result = yield from self['xep_0084'].publish_avatar_metadata([
|
||||
{'id': avatar_id,
|
||||
'type': avatar_type,
|
||||
'bytes': avatar_bytes}
|
||||
# We could advertise multiple avatars to provide
|
||||
# options in image type, source (HTTP vs pubsub),
|
||||
# size, etc.
|
||||
# {'id': ....}
|
||||
])
|
||||
if isinstance(result, XMPPError):
|
||||
print('Could not publish XEP-0084 metadata')
|
||||
|
||||
print('Wait for presence updates to propagate...')
|
||||
@@ -111,64 +99,44 @@ class AvatarSetter(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
optp.add_option('-q','--quiet', help='set logging to ERROR',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-d','--debug', help='set logging to DEBUG',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
optp.add_option('-v','--verbose', help='set logging to COMM',
|
||||
action='store_const',
|
||||
dest='loglevel',
|
||||
const=5,
|
||||
default=logging.ERROR)
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-q","--quiet", help="set logging to ERROR",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.ERROR,
|
||||
default=logging.ERROR)
|
||||
parser.add_argument("-d","--debug", help="set logging to DEBUG",
|
||||
action="store_const",
|
||||
dest="loglevel",
|
||||
const=logging.DEBUG,
|
||||
default=logging.ERROR)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
optp.add_option("-f", "--file", dest="filepath",
|
||||
help="path to the avatar file")
|
||||
opts,args = optp.parse_args()
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-f", "--file", dest="filepath",
|
||||
help="path to the avatar file")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if opts.filepath is None:
|
||||
opts.filepath = raw_input("Avatar file location: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
if args.filepath is None:
|
||||
args.filepath = input("Avatar file location: ")
|
||||
|
||||
xmpp = AvatarSetter(opts.jid, opts.password, opts.filepath)
|
||||
xmpp = AvatarSetter(args.jid, args.password, args.filepath)
|
||||
xmpp.register_plugin('xep_0054')
|
||||
xmpp.register_plugin('xep_0153')
|
||||
xmpp.register_plugin('xep_0084')
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,18 +1,18 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
try:
|
||||
from httplib import HTTPSConnection
|
||||
@@ -21,24 +21,14 @@ except ImportError:
|
||||
from urllib.parse import urlencode
|
||||
from http.client import HTTPSConnection
|
||||
|
||||
import sleekxmpp
|
||||
from sleekxmpp.xmlstream import JID
|
||||
|
||||
# Python versions before 3.0 do not use UTF-8 encoding
|
||||
# by default. To ensure that Unicode is handled properly
|
||||
# throughout SleekXMPP, we will set the default encoding
|
||||
# ourselves to UTF-8.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
else:
|
||||
raw_input = input
|
||||
import slixmpp
|
||||
from slixmpp.xmlstream import JID
|
||||
|
||||
|
||||
class ThirdPartyAuthBot(sleekxmpp.ClientXMPP):
|
||||
class ThirdPartyAuthBot(slixmpp.ClientXMPP):
|
||||
|
||||
"""
|
||||
A simple SleekXMPP bot that will echo messages it
|
||||
A simple Slixmpp bot that will echo messages it
|
||||
receives, along with a short thank you message.
|
||||
|
||||
This version uses a thirdpary service for authentication,
|
||||
@@ -46,7 +36,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP):
|
||||
"""
|
||||
|
||||
def __init__(self, jid, password):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The X-GOOGLE-TOKEN mech is ranked lower than PLAIN
|
||||
# due to Google only allowing a single SASL attempt per
|
||||
@@ -55,7 +45,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP):
|
||||
# X-GOOGLE-TOKEN with a TLS connection, explicitly select
|
||||
# it using:
|
||||
#
|
||||
# sleekxmpp.ClientXMPP.__init__(self, jid, password,
|
||||
# slixmpp.ClientXMPP.__init__(self, jid, password,
|
||||
# sasl_mech="X-GOOGLE-TOKEN")
|
||||
|
||||
# The session_start event will be triggered when
|
||||
@@ -104,37 +94,34 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
|
||||
|
||||
access_token = None
|
||||
|
||||
# Since documentation on how to work with Google tokens
|
||||
@@ -156,11 +143,11 @@ if __name__ == '__main__':
|
||||
params = urlencode({
|
||||
'accountType': 'GOOGLE',
|
||||
'service': 'mail',
|
||||
'Email': JID(opts.jid).bare,
|
||||
'Passwd': opts.password
|
||||
'Email': JID(args.jid).bare,
|
||||
'Passwd': args.password
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
try:
|
||||
conn.request('POST', '/accounts/ClientLogin', params, headers)
|
||||
@@ -208,12 +195,12 @@ if __name__ == '__main__':
|
||||
# We're using an access token instead of a password, so we'll use `''` as
|
||||
# a password argument filler.
|
||||
|
||||
xmpp = ThirdPartyAuthBot(opts.jid, '')
|
||||
xmpp = ThirdPartyAuthBot(args.jid, '')
|
||||
xmpp.credentials['access_token'] = access_token
|
||||
|
||||
# The credentials dictionary is used to provide additional authentication
|
||||
# information beyond just a password.
|
||||
|
||||
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0004') # Data Forms
|
||||
xmpp.register_plugin('xep_0060') # PubSub
|
||||
@@ -231,17 +218,7 @@ if __name__ == '__main__':
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
# Google only allows one SASL attempt per connection, so in order to
|
||||
# Google only allows one SASL attempt per connection, so in order to
|
||||
# enable the X-GOOGLE-TOKEN mechanism, we'll disable TLS.
|
||||
if xmpp.connect(use_tls=False):
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
try:
|
||||
import json
|
||||
@@ -16,16 +16,16 @@ except ImportError:
|
||||
print('This demo requires the requests package for using HTTP.')
|
||||
sys.exit()
|
||||
|
||||
from sleekxmpp import ClientXMPP
|
||||
from slixmpp import ClientXMPP
|
||||
|
||||
|
||||
class LocationBot(ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(LocationBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
self.add_event_handler('session_start', self.start, threaded=True)
|
||||
self.add_event_handler('user_location_publish',
|
||||
self.add_event_handler('session_start', self.start)
|
||||
self.add_event_handler('user_location_publish',
|
||||
self.user_location_publish)
|
||||
|
||||
self.register_plugin('xep_0004')
|
||||
@@ -71,55 +71,35 @@ class LocationBot(ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
xmpp = LocationBot(opts.jid, opts.password)
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
xmpp = LocationBot(args.jid, args.password)
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
|
||||
try:
|
||||
from appscript import *
|
||||
@@ -11,13 +11,13 @@ except ImportError:
|
||||
print('This demo requires the appscript package to interact with iTunes.')
|
||||
sys.exit()
|
||||
|
||||
from sleekxmpp import ClientXMPP
|
||||
from slixmpp import ClientXMPP
|
||||
|
||||
|
||||
class TuneBot(ClientXMPP):
|
||||
|
||||
def __init__(self, jid, password):
|
||||
super(TuneBot, self).__init__(jid, password)
|
||||
super().__init__(jid, password)
|
||||
|
||||
# Check for the current song every 5 seconds.
|
||||
self.schedule('Check Current Tune', 5, self._update_tune, repeat=True)
|
||||
@@ -83,55 +83,35 @@ class TuneBot(ClientXMPP):
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Setup the command line arguments.
|
||||
optp = OptionParser()
|
||||
parser = ArgumentParser()
|
||||
|
||||
# Output verbosity options.
|
||||
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||
action='store_const', dest='loglevel',
|
||||
const=5, default=logging.INFO)
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
xmpp = TuneBot(opts.jid, opts.password)
|
||||
|
||||
# If you are working with an OpenFire server, you may need
|
||||
# to adjust the SSL version used:
|
||||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
# If you want to verify the SSL certificates offered by a server:
|
||||
# xmpp.ca_certs = "path/to/ca/cert"
|
||||
xmpp = TuneBot(args.jid, args.password)
|
||||
|
||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||
if xmpp.connect():
|
||||
# If you do not have the dnspython library installed, you will need
|
||||
# to manually specify the name of the server if it does not match
|
||||
# the one in the JID. For example, to use Google Talk you would
|
||||
# need to use:
|
||||
#
|
||||
# if xmpp.connect(('talk.google.com', 5222)):
|
||||
# ...
|
||||
xmpp.process(block=True)
|
||||
print("Done")
|
||||
else:
|
||||
print("Unable to connect.")
|
||||
xmpp.connect()
|
||||
xmpp.process()
|
||||
|
233
ez_setup.py
233
ez_setup.py
@@ -1,233 +0,0 @@
|
||||
#!python
|
||||
"""Bootstrap setuptools installation
|
||||
|
||||
If you want to use setuptools in your package's setup.py, just include this
|
||||
file in the same directory with it, and add this to the top of your setup.py::
|
||||
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
|
||||
If you want to require a specific version of setuptools, set a download
|
||||
mirror, or use an alternate download directory, you can do so by supplying
|
||||
the appropriate options to ``use_setuptools()``.
|
||||
|
||||
This file can also be run as a script to install or upgrade setuptools.
|
||||
"""
|
||||
import sys
|
||||
DEFAULT_VERSION = "0.6c7"
|
||||
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
|
||||
|
||||
md5_data = {
|
||||
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
|
||||
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
|
||||
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
|
||||
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
|
||||
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
|
||||
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
|
||||
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
|
||||
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
|
||||
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
|
||||
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
|
||||
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
|
||||
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
|
||||
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
|
||||
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
|
||||
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
|
||||
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
|
||||
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
|
||||
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
|
||||
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
|
||||
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
|
||||
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
|
||||
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
|
||||
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
|
||||
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
|
||||
}
|
||||
|
||||
import sys, os
|
||||
|
||||
def _validate_md5(egg_name, data):
|
||||
if egg_name in md5_data:
|
||||
from md5 import md5
|
||||
digest = md5(data).hexdigest()
|
||||
if digest != md5_data[egg_name]:
|
||||
print >>sys.stderr, (
|
||||
"md5 validation of %s failed! (Possible download problem?)"
|
||||
% egg_name
|
||||
)
|
||||
sys.exit(2)
|
||||
return data
|
||||
|
||||
|
||||
def use_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, min_version=None,
|
||||
download_delay=15
|
||||
):
|
||||
"""Automatically find/download setuptools and make it available on sys.path
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end with
|
||||
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
|
||||
it is not already available. If `download_delay` is specified, it should
|
||||
be the number of seconds that will be paused before initiating a download,
|
||||
should one be required. If an older version of setuptools is installed,
|
||||
this routine will print a message to ``sys.stderr`` and raise SystemExit in
|
||||
an attempt to abort the calling script.
|
||||
"""
|
||||
try:
|
||||
import setuptools
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
print >>sys.stderr, (
|
||||
"You have an obsolete version of setuptools installed. Please\n"
|
||||
"remove it from your system entirely before rerunning this script."
|
||||
)
|
||||
sys.exit(2)
|
||||
except ImportError:
|
||||
egg = download_setuptools(version, download_base, to_dir, download_delay)
|
||||
sys.path.insert(0, egg)
|
||||
import setuptools; setuptools.bootstrap_install_from = egg
|
||||
|
||||
import pkg_resources
|
||||
try:
|
||||
if not min_version:
|
||||
min_version = version
|
||||
pkg_resources.require("setuptools>="+min_version)
|
||||
|
||||
except pkg_resources.VersionConflict, e:
|
||||
# XXX could we install in a subprocess here?
|
||||
print >>sys.stderr, (
|
||||
"The required version of setuptools (>=%s) is not available, and\n"
|
||||
"can't be installed while this script is running. Please install\n"
|
||||
" a more recent version first.\n\n(Currently using %r)"
|
||||
) % (min_version, e.args[0])
|
||||
sys.exit(2)
|
||||
|
||||
def download_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||
delay = 15
|
||||
):
|
||||
"""Download setuptools from a specified location and return its filename
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end
|
||||
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||
`delay` is the number of seconds to pause before an actual download attempt.
|
||||
"""
|
||||
import urllib2, shutil
|
||||
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
|
||||
url = download_base + egg_name
|
||||
saveto = os.path.join(to_dir, egg_name)
|
||||
src = dst = None
|
||||
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||
try:
|
||||
from distutils import log
|
||||
if delay:
|
||||
log.warn("""
|
||||
---------------------------------------------------------------------------
|
||||
This script requires setuptools version %s to run (even to display
|
||||
help). I will attempt to download it for you (from
|
||||
%s), but
|
||||
you may need to enable firewall access for this script first.
|
||||
I will start the download in %d seconds.
|
||||
|
||||
(Note: if this machine does not have network access, please obtain the file
|
||||
|
||||
%s
|
||||
|
||||
and place it in this directory before rerunning this script.)
|
||||
---------------------------------------------------------------------------""",
|
||||
version, download_base, delay, url
|
||||
); from time import sleep; sleep(delay)
|
||||
log.warn("Downloading %s", url)
|
||||
src = urllib2.urlopen(url)
|
||||
# Read/write all in one block, so we don't create a corrupt file
|
||||
# if the download is interrupted.
|
||||
data = _validate_md5(egg_name, src.read())
|
||||
dst = open(saveto,"wb"); dst.write(data)
|
||||
finally:
|
||||
if src: src.close()
|
||||
if dst: dst.close()
|
||||
return os.path.realpath(saveto)
|
||||
|
||||
def main(argv, version=DEFAULT_VERSION):
|
||||
"""Install or upgrade setuptools and EasyInstall"""
|
||||
|
||||
try:
|
||||
import setuptools
|
||||
except ImportError:
|
||||
egg = None
|
||||
try:
|
||||
egg = download_setuptools(version, delay=0)
|
||||
sys.path.insert(0,egg)
|
||||
from setuptools.command.easy_install import main
|
||||
return main(list(argv)+[egg]) # we're done here
|
||||
finally:
|
||||
if egg and os.path.exists(egg):
|
||||
os.unlink(egg)
|
||||
else:
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
# tell the user to uninstall obsolete version
|
||||
use_setuptools(version)
|
||||
|
||||
req = "setuptools>="+version
|
||||
import pkg_resources
|
||||
try:
|
||||
pkg_resources.require(req)
|
||||
except pkg_resources.VersionConflict:
|
||||
try:
|
||||
from setuptools.command.easy_install import main
|
||||
except ImportError:
|
||||
from easy_install import main
|
||||
main(list(argv)+[download_setuptools(delay=0)])
|
||||
sys.exit(0) # try to force an exit
|
||||
else:
|
||||
if argv:
|
||||
from setuptools.command.easy_install import main
|
||||
main(argv)
|
||||
else:
|
||||
print "Setuptools version",version,"or greater has been installed."
|
||||
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
|
||||
|
||||
|
||||
|
||||
def update_md5(filenames):
|
||||
"""Update our built-in md5 registry"""
|
||||
|
||||
import re
|
||||
from md5 import md5
|
||||
|
||||
for name in filenames:
|
||||
base = os.path.basename(name)
|
||||
f = open(name,'rb')
|
||||
md5_data[base] = md5(f.read()).hexdigest()
|
||||
f.close()
|
||||
|
||||
data = [" %r: %r,\n" % it for it in md5_data.items()]
|
||||
data.sort()
|
||||
repl = "".join(data)
|
||||
|
||||
import inspect
|
||||
srcfile = inspect.getsourcefile(sys.modules[__name__])
|
||||
f = open(srcfile, 'rb'); src = f.read(); f.close()
|
||||
|
||||
match = re.search("\nmd5_data = {\n([^}]+)}", src)
|
||||
if not match:
|
||||
print >>sys.stderr, "Internal error!"
|
||||
sys.exit(2)
|
||||
|
||||
src = src[:match.start(1)] + repl + src[match.end(1):]
|
||||
f = open(srcfile,'w')
|
||||
f.write(src)
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
|
||||
update_md5(sys.argv[2:])
|
||||
else:
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
||||
|
||||
|
||||
|
69
run_tests.py
Executable file
69
run_tests.py
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import unittest
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from distutils.core import Command
|
||||
from importlib import import_module
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run_tests(filenames=None):
|
||||
"""
|
||||
Find and run all tests in the tests/ directory.
|
||||
|
||||
Excludes live tests (tests/live_*).
|
||||
"""
|
||||
if not filenames:
|
||||
filenames = [i for i in Path('tests').glob('test_*')]
|
||||
else:
|
||||
filenames = [Path(i) for i in filenames]
|
||||
|
||||
modules = ['.'.join(test.parts[:-1] + (test.stem,)) for test in filenames]
|
||||
|
||||
suites = []
|
||||
for filename in modules:
|
||||
module = import_module(filename)
|
||||
suites.append(module.suite)
|
||||
|
||||
tests = unittest.TestSuite(suites)
|
||||
runner = unittest.TextTestRunner(verbosity=2)
|
||||
|
||||
# Disable logging output
|
||||
logging.basicConfig(level=100)
|
||||
logging.disable(100)
|
||||
|
||||
result = runner.run(tests)
|
||||
return result
|
||||
|
||||
|
||||
# Add a 'test' command for setup.py
|
||||
|
||||
class TestCommand(Command):
|
||||
|
||||
user_options = []
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
run_tests()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser(description='Run unit tests.')
|
||||
parser.add_argument('tests', metavar='TEST', nargs='*', help='list of tests to run, or nothing to run them all')
|
||||
args = parser.parse_args()
|
||||
|
||||
result = run_tests(args.tests)
|
||||
print("<tests %s ran='%s' errors='%s' fails='%s' success='%s'/>" % (
|
||||
"xmlns='http//andyet.net/protocol/tests'",
|
||||
result.testsRun, len(result.errors),
|
||||
len(result.failures), result.wasSuccessful()))
|
||||
|
||||
sys.exit(not result.wasSuccessful())
|
180
setup.py
180
setup.py
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2007-2011 Nathanael C. Fritz
|
||||
@@ -7,150 +7,52 @@
|
||||
# This software is licensed as described in the README.rst and LICENSE
|
||||
# file, which you should have received as part of this distribution.
|
||||
|
||||
import sys
|
||||
import codecs
|
||||
from pathlib import Path
|
||||
try:
|
||||
from setuptools import setup, Command
|
||||
from setuptools import setup
|
||||
except ImportError:
|
||||
from distutils.core import setup, Command
|
||||
# from ez_setup import use_setuptools
|
||||
from distutils.core import setup
|
||||
|
||||
from testall import TestCommand
|
||||
from sleekxmpp.version import __version__
|
||||
# if 'cygwin' in sys.platform.lower():
|
||||
# min_version = '0.6c6'
|
||||
# else:
|
||||
# min_version = '0.6a9'
|
||||
#
|
||||
# try:
|
||||
# use_setuptools(min_version=min_version)
|
||||
# except TypeError:
|
||||
# # locally installed ez_setup won't have min_version
|
||||
# use_setuptools()
|
||||
#
|
||||
# from setuptools import setup, find_packages, Extension, Feature
|
||||
try:
|
||||
from Cython.Build import cythonize
|
||||
except ImportError:
|
||||
print('Cython not found, falling back to the slow stringprep module.')
|
||||
ext_modules = None
|
||||
else:
|
||||
ext_modules = cythonize('slixmpp/stringprep.pyx')
|
||||
|
||||
VERSION = __version__
|
||||
DESCRIPTION = 'SleekXMPP is an elegant Python library for XMPP (aka Jabber, Google Talk, etc).'
|
||||
with codecs.open('README.rst', 'r', encoding='UTF-8') as readme:
|
||||
LONG_DESCRIPTION = ''.join(readme)
|
||||
from run_tests import TestCommand
|
||||
from slixmpp.version import __version__
|
||||
|
||||
CLASSIFIERS = [ 'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.1',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
]
|
||||
VERSION = __version__
|
||||
DESCRIPTION = ('Slixmpp is an elegant Python library for XMPP (aka Jabber, '
|
||||
'Google Talk, etc).')
|
||||
with open('README.rst', encoding='utf8') as readme:
|
||||
LONG_DESCRIPTION = readme.read()
|
||||
|
||||
packages = [ 'sleekxmpp',
|
||||
'sleekxmpp/stanza',
|
||||
'sleekxmpp/test',
|
||||
'sleekxmpp/roster',
|
||||
'sleekxmpp/util',
|
||||
'sleekxmpp/util/sasl',
|
||||
'sleekxmpp/xmlstream',
|
||||
'sleekxmpp/xmlstream/matcher',
|
||||
'sleekxmpp/xmlstream/handler',
|
||||
'sleekxmpp/plugins',
|
||||
'sleekxmpp/plugins/xep_0004',
|
||||
'sleekxmpp/plugins/xep_0004/stanza',
|
||||
'sleekxmpp/plugins/xep_0009',
|
||||
'sleekxmpp/plugins/xep_0009/stanza',
|
||||
'sleekxmpp/plugins/xep_0012',
|
||||
'sleekxmpp/plugins/xep_0013',
|
||||
'sleekxmpp/plugins/xep_0016',
|
||||
'sleekxmpp/plugins/xep_0020',
|
||||
'sleekxmpp/plugins/xep_0027',
|
||||
'sleekxmpp/plugins/xep_0030',
|
||||
'sleekxmpp/plugins/xep_0030/stanza',
|
||||
'sleekxmpp/plugins/xep_0033',
|
||||
'sleekxmpp/plugins/xep_0047',
|
||||
'sleekxmpp/plugins/xep_0048',
|
||||
'sleekxmpp/plugins/xep_0049',
|
||||
'sleekxmpp/plugins/xep_0050',
|
||||
'sleekxmpp/plugins/xep_0054',
|
||||
'sleekxmpp/plugins/xep_0059',
|
||||
'sleekxmpp/plugins/xep_0060',
|
||||
'sleekxmpp/plugins/xep_0060/stanza',
|
||||
'sleekxmpp/plugins/xep_0065',
|
||||
'sleekxmpp/plugins/xep_0066',
|
||||
'sleekxmpp/plugins/xep_0071',
|
||||
'sleekxmpp/plugins/xep_0077',
|
||||
'sleekxmpp/plugins/xep_0078',
|
||||
'sleekxmpp/plugins/xep_0080',
|
||||
'sleekxmpp/plugins/xep_0084',
|
||||
'sleekxmpp/plugins/xep_0085',
|
||||
'sleekxmpp/plugins/xep_0086',
|
||||
'sleekxmpp/plugins/xep_0091',
|
||||
'sleekxmpp/plugins/xep_0092',
|
||||
'sleekxmpp/plugins/xep_0095',
|
||||
'sleekxmpp/plugins/xep_0096',
|
||||
'sleekxmpp/plugins/xep_0107',
|
||||
'sleekxmpp/plugins/xep_0108',
|
||||
'sleekxmpp/plugins/xep_0115',
|
||||
'sleekxmpp/plugins/xep_0118',
|
||||
'sleekxmpp/plugins/xep_0128',
|
||||
'sleekxmpp/plugins/xep_0131',
|
||||
'sleekxmpp/plugins/xep_0152',
|
||||
'sleekxmpp/plugins/xep_0153',
|
||||
'sleekxmpp/plugins/xep_0172',
|
||||
'sleekxmpp/plugins/xep_0184',
|
||||
'sleekxmpp/plugins/xep_0186',
|
||||
'sleekxmpp/plugins/xep_0191',
|
||||
'sleekxmpp/plugins/xep_0196',
|
||||
'sleekxmpp/plugins/xep_0198',
|
||||
'sleekxmpp/plugins/xep_0199',
|
||||
'sleekxmpp/plugins/xep_0202',
|
||||
'sleekxmpp/plugins/xep_0203',
|
||||
'sleekxmpp/plugins/xep_0221',
|
||||
'sleekxmpp/plugins/xep_0224',
|
||||
'sleekxmpp/plugins/xep_0231',
|
||||
'sleekxmpp/plugins/xep_0235',
|
||||
'sleekxmpp/plugins/xep_0249',
|
||||
'sleekxmpp/plugins/xep_0257',
|
||||
'sleekxmpp/plugins/xep_0258',
|
||||
'sleekxmpp/plugins/xep_0279',
|
||||
'sleekxmpp/plugins/xep_0280',
|
||||
'sleekxmpp/plugins/xep_0297',
|
||||
'sleekxmpp/plugins/xep_0308',
|
||||
'sleekxmpp/plugins/xep_0313',
|
||||
'sleekxmpp/plugins/xep_0319',
|
||||
'sleekxmpp/plugins/xep_0323',
|
||||
'sleekxmpp/plugins/xep_0323/stanza',
|
||||
'sleekxmpp/plugins/xep_0325',
|
||||
'sleekxmpp/plugins/xep_0325/stanza',
|
||||
'sleekxmpp/plugins/google',
|
||||
'sleekxmpp/plugins/google/gmail',
|
||||
'sleekxmpp/plugins/google/auth',
|
||||
'sleekxmpp/plugins/google/settings',
|
||||
'sleekxmpp/plugins/google/nosave',
|
||||
'sleekxmpp/features',
|
||||
'sleekxmpp/features/feature_mechanisms',
|
||||
'sleekxmpp/features/feature_mechanisms/stanza',
|
||||
'sleekxmpp/features/feature_starttls',
|
||||
'sleekxmpp/features/feature_bind',
|
||||
'sleekxmpp/features/feature_session',
|
||||
'sleekxmpp/features/feature_rosterver',
|
||||
'sleekxmpp/features/feature_preapproval',
|
||||
'sleekxmpp/thirdparty',
|
||||
]
|
||||
CLASSIFIERS = [
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
]
|
||||
|
||||
packages = [str(mod.parent) for mod in Path('slixmpp').rglob('__init__.py')]
|
||||
|
||||
setup(
|
||||
name = "sleekxmpp",
|
||||
version = VERSION,
|
||||
description = DESCRIPTION,
|
||||
long_description = LONG_DESCRIPTION,
|
||||
author = 'Nathanael Fritz',
|
||||
author_email = 'fritzy [at] netflint.net',
|
||||
url = 'http://github.com/fritzy/SleekXMPP',
|
||||
license = 'MIT',
|
||||
platforms = [ 'any' ],
|
||||
packages = packages,
|
||||
requires = [ 'dnspython', 'pyasn1', 'pyasn1_modules' ],
|
||||
classifiers = CLASSIFIERS,
|
||||
cmdclass = {'test': TestCommand}
|
||||
name="slixmpp",
|
||||
version=VERSION,
|
||||
description=DESCRIPTION,
|
||||
long_description=LONG_DESCRIPTION,
|
||||
author='Florent Le Coz',
|
||||
author_email='louiz@louiz.org',
|
||||
url='https://dev.louiz.org/projects/slixmpp',
|
||||
license='MIT',
|
||||
platforms=['any'],
|
||||
packages=packages,
|
||||
ext_modules=ext_modules,
|
||||
install_requires=['aiodns>=1.0', 'pyasn1', 'pyasn1_modules'],
|
||||
classifiers=CLASSIFIERS,
|
||||
cmdclass={'test': TestCommand}
|
||||
)
|
||||
|
@@ -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__
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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)
|
@@ -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
|
@@ -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
|
@@ -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
|
638
sleekxmpp/jid.py
638
sleekxmpp/jid.py
@@ -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))
|
@@ -1,47 +0,0 @@
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from sleekxmpp.plugins.base import register_plugin, BasePlugin
|
||||
|
||||
from sleekxmpp.plugins.google.gmail import Gmail
|
||||
from sleekxmpp.plugins.google.auth import GoogleAuth
|
||||
from sleekxmpp.plugins.google.settings import GoogleSettings
|
||||
from sleekxmpp.plugins.google.nosave import GoogleNoSave
|
||||
|
||||
|
||||
class Google(BasePlugin):
|
||||
|
||||
"""
|
||||
Google: Custom GTalk Features
|
||||
|
||||
Also see: <https://developers.google.com/talk/jep_extensions/extensions>
|
||||
"""
|
||||
|
||||
name = 'google'
|
||||
description = 'Google: Custom GTalk Features'
|
||||
dependencies = set([
|
||||
'gmail',
|
||||
'google_settings',
|
||||
'google_nosave',
|
||||
'google_auth'
|
||||
])
|
||||
|
||||
def __getitem__(self, attr):
|
||||
if attr in ('settings', 'nosave', 'auth'):
|
||||
return self.xmpp['google_%s' % attr]
|
||||
elif attr == 'gmail':
|
||||
return self.xmpp['gmail']
|
||||
else:
|
||||
raise KeyError(attr)
|
||||
|
||||
|
||||
register_plugin(Gmail)
|
||||
register_plugin(GoogleAuth)
|
||||
register_plugin(GoogleSettings)
|
||||
register_plugin(GoogleNoSave)
|
||||
register_plugin(Google)
|
@@ -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
|
@@ -1,52 +0,0 @@
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||
from sleekxmpp.plugins import BasePlugin
|
||||
from sleekxmpp.plugins.google.auth import stanza
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GoogleAuth(BasePlugin):
|
||||
|
||||
"""
|
||||
Google: Auth Extensions (JID Domain Discovery, OAuth2)
|
||||
|
||||
Also see:
|
||||
<https://developers.google.com/talk/jep_extensions/jid_domain_change>
|
||||
<https://developers.google.com/talk/jep_extensions/oauth>
|
||||
"""
|
||||
|
||||
name = 'google_auth'
|
||||
description = 'Google: Auth Extensions (JID Domain Discovery, OAuth2)'
|
||||
dependencies = set(['feature_mechanisms'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
self.xmpp.namespace_map['http://www.google.com/talk/protocol/auth'] = 'ga'
|
||||
|
||||
register_stanza_plugin(self.xmpp['feature_mechanisms'].stanza.Auth,
|
||||
stanza.GoogleAuth)
|
||||
|
||||
self.xmpp.add_filter('out', self._auth)
|
||||
|
||||
def plugin_end(self):
|
||||
self.xmpp.del_filter('out', self._auth)
|
||||
|
||||
def _auth(self, stanza):
|
||||
if isinstance(stanza, self.xmpp['feature_mechanisms'].stanza.Auth):
|
||||
stanza.stream = self.xmpp
|
||||
stanza['google']['client_uses_full_bind_result'] = True
|
||||
if stanza['mechanism'] == 'X-OAUTH2':
|
||||
stanza['google']['service'] = 'oauth2'
|
||||
print(stanza)
|
||||
return stanza
|
@@ -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
|
@@ -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)
|
@@ -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
|
@@ -1,83 +0,0 @@
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from sleekxmpp.stanza import Iq, Message
|
||||
from sleekxmpp.xmlstream.handler import Callback
|
||||
from sleekxmpp.xmlstream.matcher import StanzaPath
|
||||
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||
from sleekxmpp.plugins import BasePlugin
|
||||
from sleekxmpp.plugins.google.nosave import stanza
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GoogleNoSave(BasePlugin):
|
||||
|
||||
"""
|
||||
Google: Off the Record Chats
|
||||
|
||||
NOTE: This is NOT an encryption method.
|
||||
|
||||
Also see <https://developers.google.com/talk/jep_extensions/otr>.
|
||||
"""
|
||||
|
||||
name = 'google_nosave'
|
||||
description = 'Google: Off the Record Chats'
|
||||
dependencies = set(['google_settings'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Message, stanza.NoSave)
|
||||
register_stanza_plugin(Iq, stanza.NoSaveQuery)
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('Google Nosave',
|
||||
StanzaPath('iq@type=set/google_nosave'),
|
||||
self._handle_nosave_change))
|
||||
|
||||
def plugin_end(self):
|
||||
self.xmpp.remove_handler('Google Nosave')
|
||||
|
||||
def enable(self, jid=None, block=True, timeout=None, callback=None):
|
||||
if jid is None:
|
||||
self.xmpp['google_settings'].update({'archiving_enabled': False},
|
||||
block=block, timeout=timeout, callback=callback)
|
||||
else:
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'set'
|
||||
iq['google_nosave']['item']['jid'] = jid
|
||||
iq['google_nosave']['item']['value'] = True
|
||||
return iq.send(block=block, timeout=timeout, callback=callback)
|
||||
|
||||
def disable(self, jid=None, block=True, timeout=None, callback=None):
|
||||
if jid is None:
|
||||
self.xmpp['google_settings'].update({'archiving_enabled': True},
|
||||
block=block, timeout=timeout, callback=callback)
|
||||
else:
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'set'
|
||||
iq['google_nosave']['item']['jid'] = jid
|
||||
iq['google_nosave']['item']['value'] = False
|
||||
return iq.send(block=block, timeout=timeout, callback=callback)
|
||||
|
||||
def get(self, block=True, timeout=None, callback=None):
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'get'
|
||||
iq.enable('google_nosave')
|
||||
return iq.send(block=block, timeout=timeout, callback=callback)
|
||||
|
||||
def _handle_nosave_change(self, iq):
|
||||
reply = self.xmpp.Iq()
|
||||
reply['type'] = 'result'
|
||||
reply['id'] = iq['id']
|
||||
reply['to'] = iq['from']
|
||||
reply.send()
|
||||
self.xmpp.event('google_nosave_change', iq)
|
@@ -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
|
@@ -1,110 +0,0 @@
|
||||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin
|
||||
|
||||
|
||||
class UserSettings(ElementBase):
|
||||
name = 'usersetting'
|
||||
namespace = 'google:setting'
|
||||
plugin_attrib = 'google_settings'
|
||||
interfaces = set(['auto_accept_suggestions',
|
||||
'mail_notifications',
|
||||
'archiving_enabled',
|
||||
'gmail',
|
||||
'email_verified',
|
||||
'domain_privacy_notice',
|
||||
'display_name'])
|
||||
|
||||
def _get_setting(self, setting):
|
||||
xml = self.xml.find('{%s}%s' % (self.namespace, setting))
|
||||
if xml is not None:
|
||||
return xml.attrib.get('value', '') == 'true'
|
||||
return False
|
||||
|
||||
def _set_setting(self, setting, value):
|
||||
self._del_setting(setting)
|
||||
if value in (True, False):
|
||||
xml = ET.Element('{%s}%s' % (self.namespace, setting))
|
||||
xml.attrib['value'] = 'true' if value else 'false'
|
||||
self.xml.append(xml)
|
||||
|
||||
def _del_setting(self, setting):
|
||||
xml = self.xml.find('{%s}%s' % (self.namespace, setting))
|
||||
if xml is not None:
|
||||
self.xml.remove(xml)
|
||||
|
||||
def get_display_name(self):
|
||||
xml = self.xml.find('{%s}%s' % (self.namespace, 'displayname'))
|
||||
if xml is not None:
|
||||
return xml.attrib.get('value', '')
|
||||
return ''
|
||||
|
||||
def set_display_name(self, value):
|
||||
self._del_setting(setting)
|
||||
if value:
|
||||
xml = ET.Element('{%s}%s' % (self.namespace, 'displayname'))
|
||||
xml.attrib['value'] = value
|
||||
self.xml.append(xml)
|
||||
|
||||
def del_display_name(self):
|
||||
self._del_setting('displayname')
|
||||
|
||||
def get_auto_accept_suggestions(self):
|
||||
return self._get_setting('autoacceptsuggestions')
|
||||
|
||||
def get_mail_notifications(self):
|
||||
return self._get_setting('mailnotifications')
|
||||
|
||||
def get_archiving_enabled(self):
|
||||
return self._get_setting('archivingenabled')
|
||||
|
||||
def get_gmail(self):
|
||||
return self._get_setting('gmail')
|
||||
|
||||
def get_email_verified(self):
|
||||
return self._get_setting('emailverified')
|
||||
|
||||
def get_domain_privacy_notice(self):
|
||||
return self._get_setting('domainprivacynotice')
|
||||
|
||||
def set_auto_accept_suggestions(self, value):
|
||||
self._set_setting('autoacceptsuggestions', value)
|
||||
|
||||
def set_mail_notifications(self, value):
|
||||
self._set_setting('mailnotifications', value)
|
||||
|
||||
def set_archiving_enabled(self, value):
|
||||
self._set_setting('archivingenabled', value)
|
||||
|
||||
def set_gmail(self, value):
|
||||
self._set_setting('gmail', value)
|
||||
|
||||
def set_email_verified(self, value):
|
||||
self._set_setting('emailverified', value)
|
||||
|
||||
def set_domain_privacy_notice(self, value):
|
||||
self._set_setting('domainprivacynotice', value)
|
||||
|
||||
def del_auto_accept_suggestions(self):
|
||||
self._del_setting('autoacceptsuggestions')
|
||||
|
||||
def del_mail_notifications(self):
|
||||
self._del_setting('mailnotifications')
|
||||
|
||||
def del_archiving_enabled(self):
|
||||
self._del_setting('archivingenabled')
|
||||
|
||||
def del_gmail(self):
|
||||
self._del_setting('gmail')
|
||||
|
||||
def del_email_verified(self):
|
||||
self._del_setting('emailverified')
|
||||
|
||||
def del_domain_privacy_notice(self):
|
||||
self._del_setting('domainprivacynotice')
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user