summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/.gitignore1
-rw-r--r--docs/_static/haiku.css15
-rw-r--r--docs/_static/pygments.css70
-rw-r--r--docs/conf.py4
-rw-r--r--docs/index.rst2
-rwxr-xr-xexamples/adhoc_provider.py204
-rwxr-xr-xexamples/adhoc_user.py210
-rwxr-xr-xexamples/disco_browser.py199
-rwxr-xr-xexamples/echo_client.py144
-rwxr-xr-xexamples/echo_component.py122
-rwxr-xr-xexamples/muc.py193
-rwxr-xr-xexamples/ping.py141
-rwxr-xr-xexamples/proxy_echo_client.py168
-rw-r--r--examples/roster_browser.py172
-rw-r--r--examples/rpc_async.py44
-rw-r--r--examples/rpc_client_side.py53
-rw-r--r--examples/rpc_server_side.py52
-rwxr-xr-xexamples/send_client.py143
18 files changed, 1929 insertions, 8 deletions
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..88f9974b
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+_build/*
diff --git a/docs/_static/haiku.css b/docs/_static/haiku.css
index 615ed47b..9651d11f 100644
--- a/docs/_static/haiku.css
+++ b/docs/_static/haiku.css
@@ -59,9 +59,10 @@ body {
margin: auto;
padding: 0px;
font-family: "Helvetica Neueu", Helvetica, sans-serif;
- min-width: 59em;
+ min-width: 30em;
max-width: 70em;
color: #444;
+ text-align: center;
}
div.footer {
@@ -124,21 +125,25 @@ a.headerlink:hover {
/* basic text elements */
div.content {
+ margin: auto;
margin-top: 20px;
- margin-left: 40px;
- margin-right: 40px;
margin-bottom: 50px;
font-size: 0.9em;
+ width: 700px;
+ text-align: left;
}
/* heading and navigation */
div.header {
position: relative;
+ margin: auto;
margin-top: 125px;
height: 85px;
padding: 0 40px;
font-family: "Yanone Kaffeesatz";
+ text-align: left;
+ width: 750px;
}
div.header h1 {
font-size: 2.6em;
@@ -185,12 +190,12 @@ div.topnav {
z-index: 0;
}
div.topnav p {
+ margin: auto;
margin-top: 0;
- margin-left: 40px;
- margin-right: 40px;
margin-bottom: 0px;
text-align: right;
font-size: 0.8em;
+ width: 750px;
}
div.bottomnav {
background: #eeeeee;
diff --git a/docs/_static/pygments.css b/docs/_static/pygments.css
new file mode 100644
index 00000000..f04bc738
--- /dev/null
+++ b/docs/_static/pygments.css
@@ -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 */
diff --git a/docs/conf.py b/docs/conf.py
index dd83f243..72e39d0f 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -50,7 +50,7 @@ copyright = u'2011, Nathan Fritz, Lance Stout'
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
-release = '1.0RC3'
+release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# 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
# 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
# further. For a list of options available for each theme, see the
diff --git a/docs/index.rst b/docs/index.rst
index fc6541d6..dc482d6e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,7 +13,7 @@ SleekXMPP
``develop`` branch.
**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**
- `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
diff --git a/examples/adhoc_provider.py b/examples/adhoc_provider.py
new file mode 100755
index 00000000..a72158c3
--- /dev/null
+++ b/examples/adhoc_provider.py
@@ -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.")
diff --git a/examples/adhoc_user.py b/examples/adhoc_user.py
new file mode 100755
index 00000000..bbd42d81
--- /dev/null
+++ b/examples/adhoc_user.py
@@ -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.")
diff --git a/examples/disco_browser.py b/examples/disco_browser.py
new file mode 100755
index 00000000..0d282d78
--- /dev/null
+++ b/examples/disco_browser.py
@@ -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.")
diff --git a/examples/echo_client.py b/examples/echo_client.py
new file mode 100755
index 00000000..7e553c4a
--- /dev/null
+++ b/examples/echo_client.py
@@ -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.")
diff --git a/examples/echo_component.py b/examples/echo_component.py
new file mode 100755
index 00000000..82f6eb9f
--- /dev/null
+++ b/examples/echo_component.py
@@ -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.")
diff --git a/examples/muc.py b/examples/muc.py
new file mode 100755
index 00000000..8fe2eb49
--- /dev/null
+++ b/examples/muc.py
@@ -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.")
diff --git a/examples/ping.py b/examples/ping.py
new file mode 100755
index 00000000..258fd764
--- /dev/null
+++ b/examples/ping.py
@@ -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.")
diff --git a/examples/proxy_echo_client.py b/examples/proxy_echo_client.py
new file mode 100755
index 00000000..25bfc891
--- /dev/null
+++ b/examples/proxy_echo_client.py
@@ -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.")
diff --git a/examples/roster_browser.py b/examples/roster_browser.py
new file mode 100644
index 00000000..b366d00f
--- /dev/null
+++ b/examples/roster_browser.py
@@ -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.")
+
diff --git a/examples/rpc_async.py b/examples/rpc_async.py
new file mode 100644
index 00000000..0b6d1936
--- /dev/null
+++ b/examples/rpc_async.py
@@ -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()
+ \ No newline at end of file
diff --git a/examples/rpc_client_side.py b/examples/rpc_client_side.py
new file mode 100644
index 00000000..ca1084f0
--- /dev/null
+++ b/examples/rpc_client_side.py
@@ -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()
+ \ No newline at end of file
diff --git a/examples/rpc_server_side.py b/examples/rpc_server_side.py
new file mode 100644
index 00000000..0af8af43
--- /dev/null
+++ b/examples/rpc_server_side.py
@@ -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()
+ \ No newline at end of file
diff --git a/examples/send_client.py b/examples/send_client.py
new file mode 100755
index 00000000..caf47687
--- /dev/null
+++ b/examples/send_client.py
@@ -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.")