Update doc settings to new theme, add examples, use 1.0
This commit is contained in:
parent
97378998a5
commit
3a4e3d3f51
18 changed files with 1929 additions and 8 deletions
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
_build/*
|
15
docs/_static/haiku.css
vendored
15
docs/_static/haiku.css
vendored
|
@ -59,9 +59,10 @@ body {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
font-family: "Helvetica Neueu", Helvetica, sans-serif;
|
font-family: "Helvetica Neueu", Helvetica, sans-serif;
|
||||||
min-width: 59em;
|
min-width: 30em;
|
||||||
max-width: 70em;
|
max-width: 70em;
|
||||||
color: #444;
|
color: #444;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.footer {
|
div.footer {
|
||||||
|
@ -124,21 +125,25 @@ a.headerlink:hover {
|
||||||
/* basic text elements */
|
/* basic text elements */
|
||||||
|
|
||||||
div.content {
|
div.content {
|
||||||
|
margin: auto;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-left: 40px;
|
|
||||||
margin-right: 40px;
|
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
width: 700px;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* heading and navigation */
|
/* heading and navigation */
|
||||||
|
|
||||||
div.header {
|
div.header {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
margin-top: 125px;
|
margin-top: 125px;
|
||||||
height: 85px;
|
height: 85px;
|
||||||
padding: 0 40px;
|
padding: 0 40px;
|
||||||
font-family: "Yanone Kaffeesatz";
|
font-family: "Yanone Kaffeesatz";
|
||||||
|
text-align: left;
|
||||||
|
width: 750px;
|
||||||
}
|
}
|
||||||
div.header h1 {
|
div.header h1 {
|
||||||
font-size: 2.6em;
|
font-size: 2.6em;
|
||||||
|
@ -185,12 +190,12 @@ div.topnav {
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
div.topnav p {
|
div.topnav p {
|
||||||
|
margin: auto;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-left: 40px;
|
|
||||||
margin-right: 40px;
|
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
|
width: 750px;
|
||||||
}
|
}
|
||||||
div.bottomnav {
|
div.bottomnav {
|
||||||
background: #eeeeee;
|
background: #eeeeee;
|
||||||
|
|
70
docs/_static/pygments.css
vendored
Normal file
70
docs/_static/pygments.css
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
.highlight .hll { background-color: #ffffcc }
|
||||||
|
.highlight { background: #000000; color: #f6f3e8; }
|
||||||
|
.highlight .c { color: #7C7C7C; } /* Comment */
|
||||||
|
.highlight .err { color: #f6f3e8; } /* Error */
|
||||||
|
.highlight .g { color: #f6f3e8; } /* Generic */
|
||||||
|
.highlight .k { color: #00ADEE; } /* Keyword */
|
||||||
|
.highlight .l { color: #f6f3e8; } /* Literal */
|
||||||
|
.highlight .n { color: #f6f3e8; } /* Name */
|
||||||
|
.highlight .o { color: #f6f3e8; } /* Operator */
|
||||||
|
.highlight .x { color: #f6f3e8; } /* Other */
|
||||||
|
.highlight .p { color: #f6f3e8; } /* Punctuation */
|
||||||
|
.highlight .cm { color: #7C7C7C; } /* Comment.Multiline */
|
||||||
|
.highlight .cp { color: #96CBFE; } /* Comment.Preproc */
|
||||||
|
.highlight .c1 { color: #7C7C7C; } /* Comment.Single */
|
||||||
|
.highlight .cs { color: #7C7C7C; } /* Comment.Special */
|
||||||
|
.highlight .gd { color: #f6f3e8; } /* Generic.Deleted */
|
||||||
|
.highlight .ge { color: #f6f3e8; } /* Generic.Emph */
|
||||||
|
.highlight .gr { color: #ffffff; background-color: #ff0000 } /* Generic.Error */
|
||||||
|
.highlight .gh { color: #f6f3e8; font-weight: bold; } /* Generic.Heading */
|
||||||
|
.highlight .gi { color: #f6f3e8; } /* Generic.Inserted */
|
||||||
|
.highlight .go { color: #070707; } /* Generic.Output */
|
||||||
|
.highlight .gp { color: #f6f3e8; } /* Generic.Prompt */
|
||||||
|
.highlight .gs { color: #f6f3e8; } /* Generic.Strong */
|
||||||
|
.highlight .gu { color: #f6f3e8; font-weight: bold; } /* Generic.Subheading */
|
||||||
|
.highlight .gt { color: #ffffff; font-weight: bold; background-color: #FF6C60 } /* Generic.Traceback */
|
||||||
|
.highlight .kc { color: #6699CC; } /* Keyword.Constant */
|
||||||
|
.highlight .kd { color: #6699CC; } /* Keyword.Declaration */
|
||||||
|
.highlight .kn { color: #6699CC; } /* Keyword.Namespace */
|
||||||
|
.highlight .kp { color: #6699CC; } /* Keyword.Pseudo */
|
||||||
|
.highlight .kr { color: #6699CC; } /* Keyword.Reserved */
|
||||||
|
.highlight .kt { color: #FFFFB6; } /* Keyword.Type */
|
||||||
|
.highlight .ld { color: #f6f3e8; } /* Literal.Date */
|
||||||
|
.highlight .m { color: #FF73FD; } /* Literal.Number */
|
||||||
|
.highlight .s { color: #F46DBA;/*#A8FF60;*/ } /* Literal.String */
|
||||||
|
.highlight .na { color: #f6f3e8; } /* Name.Attribute */
|
||||||
|
.highlight .nb { color: #f6f3e8; } /* Name.Builtin */
|
||||||
|
.highlight .nc { color: #f6f3e8; } /* Name.Class */
|
||||||
|
.highlight .no { color: #99CC99; } /* Name.Constant */
|
||||||
|
.highlight .nd { color: #f6f3e8; } /* Name.Decorator */
|
||||||
|
.highlight .ni { color: #E18964; } /* Name.Entity */
|
||||||
|
.highlight .ne { color: #f6f3e8; } /* Name.Exception */
|
||||||
|
.highlight .nf { color: #F64DBA; } /* Name.Function */
|
||||||
|
.highlight .nl { color: #f6f3e8; } /* Name.Label */
|
||||||
|
.highlight .nn { color: #f6f3e8; } /* Name.Namespace */
|
||||||
|
.highlight .nx { color: #f6f3e8; } /* Name.Other */
|
||||||
|
.highlight .py { color: #f6f3e8; } /* Name.Property */
|
||||||
|
.highlight .nt { color: #00ADEE; } /* Name.Tag */
|
||||||
|
.highlight .nv { color: #C6C5FE; } /* Name.Variable */
|
||||||
|
.highlight .ow { color: #ffffff; } /* Operator.Word */
|
||||||
|
.highlight .w { color: #f6f3e8; } /* Text.Whitespace */
|
||||||
|
.highlight .mf { color: #FF73FD; } /* Literal.Number.Float */
|
||||||
|
.highlight .mh { color: #FF73FD; } /* Literal.Number.Hex */
|
||||||
|
.highlight .mi { color: #FF73FD; } /* Literal.Number.Integer */
|
||||||
|
.highlight .mo { color: #FF73FD; } /* Literal.Number.Oct */
|
||||||
|
.highlight .sb { color: #A8FF60; } /* Literal.String.Backtick */
|
||||||
|
.highlight .sc { color: #A8FF60; } /* Literal.String.Char */
|
||||||
|
.highlight .sd { color: #A8FF60; } /* Literal.String.Doc */
|
||||||
|
.highlight .s2 { color: #A8FF60; } /* Literal.String.Double */
|
||||||
|
.highlight .se { color: #A8FF60; } /* Literal.String.Escape */
|
||||||
|
.highlight .sh { color: #A8FF60; } /* Literal.String.Heredoc */
|
||||||
|
.highlight .si { color: #A8FF60; } /* Literal.String.Interpol */
|
||||||
|
.highlight .sx { color: #A8FF60; } /* Literal.String.Other */
|
||||||
|
.highlight .sr { color: #A8FF60; } /* Literal.String.Regex */
|
||||||
|
.highlight .s1 { color: #A8FF60; } /* Literal.String.Single */
|
||||||
|
.highlight .ss { color: #A8FF60; } /* Literal.String.Symbol */
|
||||||
|
.highlight .bp { color: #f6f3e8; } /* Name.Builtin.Pseudo */
|
||||||
|
.highlight .vc { color: #C6C5FE; } /* Name.Variable.Class */
|
||||||
|
.highlight .vg { color: #C6C5FE; } /* Name.Variable.Global */
|
||||||
|
.highlight .vi { color: #C6C5FE; } /* Name.Variable.Instance */
|
||||||
|
.highlight .il { color: #FF73FD; } /* Literal.Number.Integer.Long */
|
|
@ -50,7 +50,7 @@ copyright = u'2011, Nathan Fritz, Lance Stout'
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.0'
|
version = '1.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '1.0RC3'
|
release = '1.0'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -91,7 +91,7 @@ pygments_style = 'tango'
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'nature'
|
html_theme = 'haiku'
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
|
|
@ -13,7 +13,7 @@ SleekXMPP
|
||||||
``develop`` branch.
|
``develop`` branch.
|
||||||
|
|
||||||
**Latest Stable Release**
|
**Latest Stable Release**
|
||||||
- `1.0 RC3 <http://github.com/fritzy/SleekXMPP/zipball/1.0-RC3>`_
|
- `1.0 <http://github.com/fritzy/SleekXMPP/zipball/1.0>`_
|
||||||
|
|
||||||
**Develop Releases**
|
**Develop Releases**
|
||||||
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
|
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
|
||||||
|
|
204
examples/adhoc_provider.py
Executable file
204
examples/adhoc_provider.py
Executable file
|
@ -0,0 +1,204 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class CommandBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP bot that provides a basic
|
||||||
|
adhoc command.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, jid, password):
|
||||||
|
sleekxmpp.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)
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an initial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
|
||||||
|
# We add the command after session_start has fired
|
||||||
|
# to ensure that the correct full JID is used.
|
||||||
|
|
||||||
|
# If using a component, may also pass jid keyword parameter.
|
||||||
|
|
||||||
|
self['xep_0050'].add_command(node='greeting',
|
||||||
|
name='Greeting',
|
||||||
|
handler=self._handle_command)
|
||||||
|
|
||||||
|
def _handle_command(self, iq, session):
|
||||||
|
"""
|
||||||
|
Respond to the initial request for a command.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
iq -- The iq stanza containing the command request.
|
||||||
|
session -- A dictionary of data relevant to the command
|
||||||
|
session. Additional, custom data may be saved
|
||||||
|
here to persist across handler callbacks.
|
||||||
|
"""
|
||||||
|
form = self['xep_0004'].makeForm('form', 'Greeting')
|
||||||
|
form['instructions'] = 'Send a custom greeting to a JID'
|
||||||
|
form.addField(var='greeting',
|
||||||
|
ftype='text-single',
|
||||||
|
label='Your greeting')
|
||||||
|
|
||||||
|
session['payload'] = form
|
||||||
|
session['next'] = self._handle_command_complete
|
||||||
|
session['has_next'] = False
|
||||||
|
|
||||||
|
# Other useful session values:
|
||||||
|
# session['to'] -- The JID that received the
|
||||||
|
# command request.
|
||||||
|
# session['from'] -- The JID that sent the
|
||||||
|
# command request.
|
||||||
|
# session['has_next'] = True -- There are more steps to complete
|
||||||
|
# session['allow_complete'] = True -- Allow user to finish immediately
|
||||||
|
# and possibly skip steps
|
||||||
|
# session['cancel'] = handler -- Assign a handler for if the user
|
||||||
|
# cancels the command.
|
||||||
|
# session['notes'] = [ -- Add informative notes about the
|
||||||
|
# ('info', 'Info message'), command's results.
|
||||||
|
# ('warning', 'Warning message'),
|
||||||
|
# ('error', 'Error message')]
|
||||||
|
|
||||||
|
return session
|
||||||
|
|
||||||
|
def _handle_command_complete(self, payload, session):
|
||||||
|
"""
|
||||||
|
Process a command result from the user.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
payload -- Either a single item, such as a form, or a list
|
||||||
|
of items or forms if more than one form was
|
||||||
|
provided to the user. The payload may be any
|
||||||
|
stanza, such as jabber:x:oob for out of band
|
||||||
|
data, or jabber:x:data for typical data forms.
|
||||||
|
session -- A dictionary of data relevant to the command
|
||||||
|
session. Additional, custom data may be saved
|
||||||
|
here to persist across handler callbacks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# In this case (as is typical), the payload is a form
|
||||||
|
form = payload
|
||||||
|
|
||||||
|
greeting = form['values']['greeting']
|
||||||
|
|
||||||
|
self.send_message(mto=session['from'],
|
||||||
|
mbody="%s, World!" % greeting,
|
||||||
|
mtype='chat')
|
||||||
|
|
||||||
|
# Having no return statement is the same as unsetting the 'payload'
|
||||||
|
# and 'next' session values and returning the session.
|
||||||
|
|
||||||
|
# Unless it is the final step, always return the session dictionary.
|
||||||
|
|
||||||
|
session['payload'] = None
|
||||||
|
session['next'] = None
|
||||||
|
|
||||||
|
return session
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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.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.")
|
210
examples/adhoc_user.py
Executable file
210
examples/adhoc_user.py
Executable file
|
@ -0,0 +1,210 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class CommandUserBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP 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)
|
||||||
|
|
||||||
|
self.command_provider = other
|
||||||
|
self.greeting = greeting
|
||||||
|
|
||||||
|
# The session_start event will be triggered when
|
||||||
|
# the bot establishes its connection with the server
|
||||||
|
# and the XML streams are ready for use. We want to
|
||||||
|
# listen for this event so that we we can initialize
|
||||||
|
# our roster.
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
self.add_event_handler("message", self.message)
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an initial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
|
||||||
|
# We first create a session dictionary containing:
|
||||||
|
# 'next' -- the handler to execute on a successful response
|
||||||
|
# 'error' -- the handler to execute if an error occurs
|
||||||
|
|
||||||
|
# The session may also contain custom data.
|
||||||
|
|
||||||
|
session = {'greeting': self.greeting,
|
||||||
|
'next': self._command_start,
|
||||||
|
'error': self._command_error}
|
||||||
|
|
||||||
|
self['xep_0050'].start_command(jid=self.command_provider,
|
||||||
|
node='greeting',
|
||||||
|
session=session)
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
"""
|
||||||
|
Process incoming message stanzas.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
msg -- The received message stanza.
|
||||||
|
"""
|
||||||
|
logging.info(msg['body'])
|
||||||
|
|
||||||
|
def _command_start(self, iq, session):
|
||||||
|
"""
|
||||||
|
Process the initial command result.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
iq -- The iq stanza containing the command result.
|
||||||
|
session -- A dictionary of data relevant to the command
|
||||||
|
session. Additional, custom data may be saved
|
||||||
|
here to persist across handler callbacks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The greeting command provides a form with a single field:
|
||||||
|
# <x xmlns="jabber:x:data" type="form">
|
||||||
|
# <field var="greeting"
|
||||||
|
# type="text-single"
|
||||||
|
# label="Your greeting" />
|
||||||
|
# </x>
|
||||||
|
|
||||||
|
form = self['xep_0004'].makeForm(ftype='submit')
|
||||||
|
form.addField(var='greeting',
|
||||||
|
value=session['greeting'])
|
||||||
|
|
||||||
|
session['payload'] = form
|
||||||
|
|
||||||
|
# We don't need to process the next result.
|
||||||
|
session['next'] = None
|
||||||
|
|
||||||
|
# Other options include using:
|
||||||
|
# continue_command() -- Continue to the next step in the workflow
|
||||||
|
# cancel_command() -- Stop command execution.
|
||||||
|
|
||||||
|
self['xep_0050'].complete_command(session)
|
||||||
|
|
||||||
|
def _command_error(self, iq, session):
|
||||||
|
"""
|
||||||
|
Process an error that occurs during command execution.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
iq -- The iq stanza containing the error.
|
||||||
|
session -- A dictionary of data relevant to the command
|
||||||
|
session. Additional, custom data may be saved
|
||||||
|
here to persist across handler callbacks.
|
||||||
|
"""
|
||||||
|
logging.error("COMMAND: %s %s" % (iq['error']['condition'],
|
||||||
|
iq['error']['text']))
|
||||||
|
|
||||||
|
# Terminate the command's execution and clear its session.
|
||||||
|
# The session will automatically be cleared if no error
|
||||||
|
# handler is provided.
|
||||||
|
self['xep_0050'].terminate_command(session)
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
|
||||||
|
opts, args = optp.parse_args()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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.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.")
|
199
examples/disco_browser.py
Executable file
199
examples/disco_browser.py
Executable file
|
@ -0,0 +1,199 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class Disco(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A demonstration for using basic service discovery.
|
||||||
|
|
||||||
|
Send a disco#info and disco#items request to a JID/node combination,
|
||||||
|
and print out the results.
|
||||||
|
|
||||||
|
May also request only particular info categories such as just features,
|
||||||
|
or just items.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, jid, password, target_jid, target_node='', get=''):
|
||||||
|
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||||
|
|
||||||
|
# Using service discovery requires the XEP-0030 plugin.
|
||||||
|
self.register_plugin('xep_0030')
|
||||||
|
|
||||||
|
self.get = get
|
||||||
|
self.target_jid = target_jid
|
||||||
|
self.target_node = target_node
|
||||||
|
|
||||||
|
# Values to control which disco entities are reported
|
||||||
|
self.info_types = ['', 'all', 'info', 'identities', 'features']
|
||||||
|
self.identity_types = ['', 'all', 'info', 'identities']
|
||||||
|
self.feature_types = ['', 'all', 'info', 'features']
|
||||||
|
self.items_types = ['', 'all', 'items']
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
In this case, we send disco#info and disco#items
|
||||||
|
stanzas to the requested JID and print the results.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.get_roster()
|
||||||
|
self.send_presence()
|
||||||
|
|
||||||
|
if self.get in self.info_types:
|
||||||
|
# By using block=True, the result stanza will be
|
||||||
|
# returned. Execution will block until the reply is
|
||||||
|
# received. Non-blocking options would be to listen
|
||||||
|
# for the disco_info event, or passing a handler
|
||||||
|
# function using the callback parameter.
|
||||||
|
info = self['xep_0030'].get_info(jid=self.target_jid,
|
||||||
|
node=self.target_node,
|
||||||
|
block=True)
|
||||||
|
if self.get in self.items_types:
|
||||||
|
# The same applies from above. Listen for the
|
||||||
|
# disco_items event or pass a callback function
|
||||||
|
# if you need to process a non-blocking request.
|
||||||
|
items = self['xep_0030'].get_items(jid=self.target_jid,
|
||||||
|
node=self.target_node,
|
||||||
|
block=True)
|
||||||
|
else:
|
||||||
|
logging.error("Invalid disco request type.")
|
||||||
|
self.disconnect()
|
||||||
|
return
|
||||||
|
|
||||||
|
header = 'XMPP Service Discovery: %s' % self.target_jid
|
||||||
|
print(header)
|
||||||
|
print('-' * len(header))
|
||||||
|
if self.target_node != '':
|
||||||
|
print('Node: %s' % self.target_node)
|
||||||
|
print('-' * len(header))
|
||||||
|
|
||||||
|
if self.get in self.identity_types:
|
||||||
|
print('Identities:')
|
||||||
|
for identity in info['disco_info']['identities']:
|
||||||
|
print(' - %s' % str(identity))
|
||||||
|
|
||||||
|
if self.get in self.feature_types:
|
||||||
|
print('Features:')
|
||||||
|
for feature in info['disco_info']['features']:
|
||||||
|
print(' - %s' % feature)
|
||||||
|
|
||||||
|
if self.get in self.items_types:
|
||||||
|
print('Items:')
|
||||||
|
for item in items['disco_items']['items']:
|
||||||
|
print(' - %s' % str(item))
|
||||||
|
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
if __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'
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
# 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.")
|
144
examples/echo_client.py
Executable file
144
examples/echo_client.py
Executable file
|
@ -0,0 +1,144 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class EchoBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP 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)
|
||||||
|
|
||||||
|
# The session_start event will be triggered when
|
||||||
|
# the bot establishes its connection with the server
|
||||||
|
# and the XML streams are ready for use. We want to
|
||||||
|
# listen for this event so that we we can initialize
|
||||||
|
# our roster.
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
|
||||||
|
# The message event is triggered whenever a message
|
||||||
|
# stanza is received. Be aware that that includes
|
||||||
|
# MUC messages and error messages.
|
||||||
|
self.add_event_handler("message", self.message)
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an initial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
"""
|
||||||
|
Process incoming message stanzas. Be aware that this also
|
||||||
|
includes MUC messages and error messages. It is usually
|
||||||
|
a good idea to check the messages's type before processing
|
||||||
|
or sending replies.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
msg -- The received message stanza. See the documentation
|
||||||
|
for stanza objects and the Message stanza to see
|
||||||
|
how it may be used.
|
||||||
|
"""
|
||||||
|
if msg['type'] in ('chat', 'normal'):
|
||||||
|
msg.reply("Thanks for sending\n%(body)s" % msg).send()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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.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.")
|
122
examples/echo_component.py
Executable file
122
examples/echo_component.py
Executable file
|
@ -0,0 +1,122 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
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):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class EchoComponent(ComponentXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP component that echoes messages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, jid, secret, server, port):
|
||||||
|
ComponentXMPP.__init__(self, jid, secret, server, port)
|
||||||
|
|
||||||
|
# You don't need a session_start handler, but that is
|
||||||
|
# where you would broadcast initial presence.
|
||||||
|
|
||||||
|
# The message event is triggered whenever a message
|
||||||
|
# stanza is received. Be aware that that includes
|
||||||
|
# MUC messages and error messages.
|
||||||
|
self.add_event_handler("message", self.message)
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
"""
|
||||||
|
Process incoming message stanzas. Be aware that this also
|
||||||
|
includes MUC messages and error messages. It is usually
|
||||||
|
a good idea to check the messages's type before processing
|
||||||
|
or sending replies.
|
||||||
|
|
||||||
|
Since a component may send messages from any number of JIDs,
|
||||||
|
it is best to always include a from JID.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
msg -- The received message stanza. See the documentation
|
||||||
|
for stanza objects and the Message stanza to see
|
||||||
|
how it may be used.
|
||||||
|
"""
|
||||||
|
# The reply method will use the messages 'to' JID as the
|
||||||
|
# outgoing reply's 'from' JID.
|
||||||
|
msg.reply("Thanks for sending\n%(body)s" % msg).send()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
|
||||||
|
opts, args = optp.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: "))
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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
|
||||||
|
|
||||||
|
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||||
|
if xmpp.connect():
|
||||||
|
xmpp.process(block=True)
|
||||||
|
print("Done")
|
||||||
|
else:
|
||||||
|
print("Unable to connect.")
|
193
examples/muc.py
Executable file
193
examples/muc.py
Executable file
|
@ -0,0 +1,193 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class MUCBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP 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)
|
||||||
|
|
||||||
|
self.room = room
|
||||||
|
self.nick = nick
|
||||||
|
|
||||||
|
# The session_start event will be triggered when
|
||||||
|
# the bot establishes its connection with the server
|
||||||
|
# and the XML streams are ready for use. We want to
|
||||||
|
# listen for this event so that we we can initialize
|
||||||
|
# our roster.
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
|
||||||
|
# The groupchat_message event is triggered whenever a message
|
||||||
|
# stanza is received from any chat room. If you also also
|
||||||
|
# register a handler for the 'message' event, MUC messages
|
||||||
|
# will be processed by both handlers.
|
||||||
|
self.add_event_handler("groupchat_message", self.muc_message)
|
||||||
|
|
||||||
|
# The groupchat_presence event is triggered whenever a
|
||||||
|
# presence stanza is received from any chat room, including
|
||||||
|
# any presences you send yourself. To limit event handling
|
||||||
|
# to a single room, use the events muc::room@server::presence,
|
||||||
|
# muc::room@server::got_online, or muc::room@server::got_offline.
|
||||||
|
self.add_event_handler("muc::%s::got_online" % self.room,
|
||||||
|
self.muc_online)
|
||||||
|
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an initial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.getRoster()
|
||||||
|
self.sendPresence()
|
||||||
|
self.plugin['xep_0045'].joinMUC(self.room,
|
||||||
|
self.nick,
|
||||||
|
# If a room password is needed, use:
|
||||||
|
# password=the_room_password,
|
||||||
|
wait=True)
|
||||||
|
|
||||||
|
def muc_message(self, msg):
|
||||||
|
"""
|
||||||
|
Process incoming message stanzas from any chat room. Be aware
|
||||||
|
that if you also have any handlers for the 'message' event,
|
||||||
|
message stanzas may be processed by both handlers, so check
|
||||||
|
the 'type' attribute when using a 'message' event handler.
|
||||||
|
|
||||||
|
Whenever the bot's nickname is mentioned, respond to
|
||||||
|
the message.
|
||||||
|
|
||||||
|
IMPORTANT: Always check that a message is not from yourself,
|
||||||
|
otherwise you will create an infinite loop responding
|
||||||
|
to your own messages.
|
||||||
|
|
||||||
|
This handler will reply to messages that mention
|
||||||
|
the bot's nickname.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
msg -- The received message stanza. See the documentation
|
||||||
|
for stanza objects and the Message stanza to see
|
||||||
|
how it may be used.
|
||||||
|
"""
|
||||||
|
if msg['mucnick'] != self.nick and self.nick in msg['body']:
|
||||||
|
self.send_message(mto=msg['from'].bare,
|
||||||
|
mbody="I heard that, %s." % msg['mucnick'],
|
||||||
|
mtype='groupchat')
|
||||||
|
|
||||||
|
def muc_online(self, presence):
|
||||||
|
"""
|
||||||
|
Process a presence stanza from a chat room. In this case,
|
||||||
|
presences from users that have just come online are
|
||||||
|
handled by sending a welcome message that includes
|
||||||
|
the user's nickname and role in the room.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
presence -- The received presence stanza. See the
|
||||||
|
documentation for the Presence stanza
|
||||||
|
to see how else it may be used.
|
||||||
|
"""
|
||||||
|
if presence['muc']['nick'] != self.nick:
|
||||||
|
self.send_message(mto=presence['from'].bare,
|
||||||
|
mbody="Hello, %s %s" % (presence['muc']['role'],
|
||||||
|
presence['muc']['nick']),
|
||||||
|
mtype='groupchat')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
|
||||||
|
opts, args = optp.parse_args()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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.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.")
|
141
examples/ping.py
Executable file
141
examples/ping.py
Executable file
|
@ -0,0 +1,141 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class PingTest(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP bot that will send a ping request
|
||||||
|
to a given JID.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, jid, password, pingjid):
|
||||||
|
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||||
|
if pingjid is None:
|
||||||
|
pingjid = self.jid
|
||||||
|
self.pingjid = pingjid
|
||||||
|
|
||||||
|
# The session_start event will be triggered when
|
||||||
|
# the bot establishes its connection with the server
|
||||||
|
# and the XML streams are ready for use. We want to
|
||||||
|
# listen for this event so that we we can initialize
|
||||||
|
# our roster.
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an initial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
result = self['xep_0199'].send_ping(self.pingjid,
|
||||||
|
timeout=10,
|
||||||
|
errorfalse=True)
|
||||||
|
logging.info("Pinging...")
|
||||||
|
if result is False:
|
||||||
|
logging.info("Couldn't ping.")
|
||||||
|
self.disconnect()
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
logging.info("Success! RTT: %s", str(result))
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
optp.add_option('-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")
|
||||||
|
|
||||||
|
opts, args = optp.parse_args()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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.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.")
|
168
examples/proxy_echo_client.py
Executable file
168
examples/proxy_echo_client.py
Executable file
|
@ -0,0 +1,168 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class EchoBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP 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)
|
||||||
|
|
||||||
|
# The session_start event will be triggered when
|
||||||
|
# the bot establishes its connection with the server
|
||||||
|
# and the XML streams are ready for use. We want to
|
||||||
|
# listen for this event so that we we can initialize
|
||||||
|
# our roster.
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
|
||||||
|
# The message event is triggered whenever a message
|
||||||
|
# stanza is received. Be aware that that includes
|
||||||
|
# MUC messages and error messages.
|
||||||
|
self.add_event_handler("message", self.message)
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an initial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
"""
|
||||||
|
Process incoming message stanzas. Be aware that this also
|
||||||
|
includes MUC messages and error messages. It is usually
|
||||||
|
a good idea to check the messages's type before processing
|
||||||
|
or sending replies.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
msg -- The received message stanza. See the documentation
|
||||||
|
for stanza objects and the Message stanza to see
|
||||||
|
how it may be used.
|
||||||
|
"""
|
||||||
|
msg.reply("Thanks for sending\n%(body)s" % msg).send()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
opts, args = optp.parse_args()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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.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}
|
||||||
|
|
||||||
|
# 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.")
|
172
examples/roster_browser.py
Normal file
172
examples/roster_browser.py
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2011 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
import threading
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
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):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class RosterBrowser(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A basic script for dumping a client's roster to
|
||||||
|
the command line.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, jid, password):
|
||||||
|
sleekxmpp.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)
|
||||||
|
self.add_event_handler("changed_status", self.wait_for_presences)
|
||||||
|
|
||||||
|
self.received = set()
|
||||||
|
self.presences_received = threading.Event()
|
||||||
|
|
||||||
|
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:
|
||||||
|
self.get_roster()
|
||||||
|
except IqError as err:
|
||||||
|
print('Error: %' % 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)
|
||||||
|
|
||||||
|
print('Roster for %s' % self.boundjid.bare)
|
||||||
|
groups = self.client_roster.groups()
|
||||||
|
for group in groups:
|
||||||
|
print('\n%s' % group)
|
||||||
|
print('-' * 72)
|
||||||
|
for jid in groups[group]:
|
||||||
|
sub = self.client_roster[jid]['subscription']
|
||||||
|
name = self.client_roster[jid]['name']
|
||||||
|
if self.client_roster[jid]['name']:
|
||||||
|
print(' %s (%s) [%s]' % (name, jid, sub))
|
||||||
|
else:
|
||||||
|
print(' %s [%s]' % (jid, sub))
|
||||||
|
|
||||||
|
connections = self.client_roster.presence(jid)
|
||||||
|
for res, pres in connections.items():
|
||||||
|
show = 'available'
|
||||||
|
if pres['show']:
|
||||||
|
show = pres['show']
|
||||||
|
print(' - %s (%s)' % (res, show))
|
||||||
|
if pres['status']:
|
||||||
|
print(' %s' % pres['status'])
|
||||||
|
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
def wait_for_presences(self, pres):
|
||||||
|
"""
|
||||||
|
Track how many roster entries have received presence updates.
|
||||||
|
"""
|
||||||
|
self.received.add(pres['from'].bare)
|
||||||
|
if len(self.received) >= len(self.client_roster.keys()):
|
||||||
|
self.presences_received.set()
|
||||||
|
else:
|
||||||
|
self.presences_received.clear()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
# 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.")
|
||||||
|
|
44
examples/rpc_async.py
Normal file
44
examples/rpc_async.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2011 Dann Martens
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||||
|
ANY_ALL, Future
|
||||||
|
import time
|
||||||
|
|
||||||
|
class Boomerang(Endpoint):
|
||||||
|
|
||||||
|
def FQN(self):
|
||||||
|
return 'boomerang'
|
||||||
|
|
||||||
|
@remote
|
||||||
|
def throw(self):
|
||||||
|
print "Duck!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
session = Remote.new_session('kangaroo@xmpp.org/rpc', '*****')
|
||||||
|
|
||||||
|
session.new_handler(ANY_ALL, Boomerang)
|
||||||
|
|
||||||
|
boomerang = session.new_proxy('kangaroo@xmpp.org/rpc', Boomerang)
|
||||||
|
|
||||||
|
callback = Future()
|
||||||
|
|
||||||
|
boomerang.async(callback).throw()
|
||||||
|
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
53
examples/rpc_client_side.py
Normal file
53
examples/rpc_client_side.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2011 Dann Martens
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||||
|
ANY_ALL
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
class Thermostat(Endpoint):
|
||||||
|
|
||||||
|
def FQN(self):
|
||||||
|
return 'thermostat'
|
||||||
|
|
||||||
|
def __init(self, initial_temperature):
|
||||||
|
self._temperature = initial_temperature
|
||||||
|
self._event = threading.Event()
|
||||||
|
|
||||||
|
@remote
|
||||||
|
def set_temperature(self, temperature):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
@remote
|
||||||
|
def get_temperature(self):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
@remote(False)
|
||||||
|
def release(self):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
session = Remote.new_session('operator@xmpp.org/rpc', '*****')
|
||||||
|
|
||||||
|
thermostat = session.new_proxy('thermostat@xmpp.org/rpc', Thermostat)
|
||||||
|
|
||||||
|
print("Current temperature is %s" % thermostat.get_temperature())
|
||||||
|
|
||||||
|
thermostat.set_temperature(20)
|
||||||
|
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
52
examples/rpc_server_side.py
Normal file
52
examples/rpc_server_side.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2011 Dann Martens
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \
|
||||||
|
ANY_ALL
|
||||||
|
import threading
|
||||||
|
|
||||||
|
class Thermostat(Endpoint):
|
||||||
|
|
||||||
|
def FQN(self):
|
||||||
|
return 'thermostat'
|
||||||
|
|
||||||
|
def __init(self, initial_temperature):
|
||||||
|
self._temperature = initial_temperature
|
||||||
|
self._event = threading.Event()
|
||||||
|
|
||||||
|
@remote
|
||||||
|
def set_temperature(self, temperature):
|
||||||
|
print("Setting temperature to %s" % temperature)
|
||||||
|
self._temperature = temperature
|
||||||
|
|
||||||
|
@remote
|
||||||
|
def get_temperature(self):
|
||||||
|
return self._temperature
|
||||||
|
|
||||||
|
@remote(False)
|
||||||
|
def release(self):
|
||||||
|
self._event.set()
|
||||||
|
|
||||||
|
def wait_for_release(self):
|
||||||
|
self._event.wait()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
session = Remote.new_session('sleek@xmpp.org/rpc', '*****')
|
||||||
|
|
||||||
|
thermostat = session.new_handler(ANY_ALL, Thermostat, 18)
|
||||||
|
|
||||||
|
thermostat.wait_for_release()
|
||||||
|
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
143
examples/send_client.py
Executable file
143
examples/send_client.py
Executable file
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import getpass
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
else:
|
||||||
|
raw_input = input
|
||||||
|
|
||||||
|
|
||||||
|
class SendMsgBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A basic SleekXMPP 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)
|
||||||
|
|
||||||
|
# The message we wish to send, and the JID that
|
||||||
|
# will receive it.
|
||||||
|
self.recipient = recipient
|
||||||
|
self.msg = message
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an initial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
|
||||||
|
self.send_message(mto=self.recipient,
|
||||||
|
mbody=self.msg,
|
||||||
|
mtype='chat')
|
||||||
|
|
||||||
|
# Using wait=True ensures that the send queue will be
|
||||||
|
# emptied before ending the session.
|
||||||
|
self.disconnect(wait=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
|
||||||
|
opts, args = optp.parse_args()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.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: ")
|
||||||
|
|
||||||
|
# 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.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.")
|
Loading…
Reference in a new issue