Updated the client and component examples.
The component example now actually uses a config.xml file for its connection information, and to initialize a roster.
This commit is contained in:
parent
9bef4b4d4d
commit
0b4320a196
5 changed files with 304 additions and 69 deletions
9
INSTALL
9
INSTALL
|
@ -1,11 +1,12 @@
|
||||||
Pre-requisites:
|
Pre-requisites:
|
||||||
Python 3.1 or 2.6
|
- Python 3.1 or 2.6
|
||||||
|
|
||||||
Install:
|
Install:
|
||||||
python3 setup.py install
|
> python3 setup.py install
|
||||||
|
|
||||||
Root install:
|
Root install:
|
||||||
sudo python3 setup.py install
|
> sudo python3 setup.py install
|
||||||
|
|
||||||
To test:
|
To test:
|
||||||
python example.py -v -j [USER@example.com] -p [PASSWORD]
|
> cd examples
|
||||||
|
> python echo_client.py -v -j [USER@example.com] -p [PASSWORD]
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
import sleekxmpp.componentxmpp
|
|
||||||
import logging
|
|
||||||
from optparse import OptionParser
|
|
||||||
import time
|
|
||||||
|
|
||||||
class Example(sleekxmpp.componentxmpp.ComponentXMPP):
|
|
||||||
|
|
||||||
def __init__(self, jid, password):
|
|
||||||
sleekxmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'vm1', 5230)
|
|
||||||
self.add_event_handler("session_start", self.start)
|
|
||||||
self.add_event_handler("message", self.message)
|
|
||||||
|
|
||||||
def start(self, event):
|
|
||||||
#self.getRoster()
|
|
||||||
#self.sendPresence(pto='admin@tigase.netflint.net/sarkozy')
|
|
||||||
#self.sendPresence(pto='tigase.netflint.net')
|
|
||||||
pass
|
|
||||||
|
|
||||||
def message(self, event):
|
|
||||||
self.sendMessage("%s/%s" % (event['jid'], event['resource']), "Thanks for sending me, \"%s\"." % event['message'], mtype=event['type'])
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
#parse command line arguements
|
|
||||||
optp = OptionParser()
|
|
||||||
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("-c","--config", dest="configfile", default="config.xml", help="set config file to use")
|
|
||||||
opts,args = optp.parse_args()
|
|
||||||
|
|
||||||
logging.basicConfig(level=opts.loglevel, format='%(levelname)-8s %(message)s')
|
|
||||||
xmpp = Example('component.vm1', 'secreteating')
|
|
||||||
xmpp.registerPlugin('xep_0004')
|
|
||||||
xmpp.registerPlugin('xep_0030')
|
|
||||||
xmpp.registerPlugin('xep_0060')
|
|
||||||
xmpp.registerPlugin('xep_0199')
|
|
||||||
if xmpp.connect():
|
|
||||||
xmpp.process(threaded=False)
|
|
||||||
print("done")
|
|
||||||
else:
|
|
||||||
print("Unable to connect.")
|
|
10
examples/config.xml
Normal file
10
examples/config.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<config xmlns="sleekxmpp:config">
|
||||||
|
<jid>component.localhost</jid>
|
||||||
|
<secret>ssshh</secret>
|
||||||
|
<server>localhost</server>
|
||||||
|
<port>8888</port>
|
||||||
|
|
||||||
|
<query xmlns="jabber:iq:roster">
|
||||||
|
<item jid="user@example.com" subscription="both" />
|
||||||
|
</query>
|
||||||
|
</config>
|
190
examples/config_component.py
Executable file
190
examples/config_component.py
Executable file
|
@ -0,0 +1,190 @@
|
||||||
|
#!/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 time
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
from sleekxmpp.componentxmpp import ComponentXMPP
|
||||||
|
from sleekxmpp.stanza.roster import Roster
|
||||||
|
from sleekxmpp.xmlstream import ElementBase
|
||||||
|
from sleekxmpp.xmlstream.stanzabase import ET, registerStanzaPlugin
|
||||||
|
|
||||||
|
# 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')
|
||||||
|
|
||||||
|
|
||||||
|
class Config(ElementBase):
|
||||||
|
|
||||||
|
"""
|
||||||
|
In order to make loading and manipulating an XML config
|
||||||
|
file easier, we will create a custom stanza object for
|
||||||
|
our config XML file contents. See the documentation
|
||||||
|
on stanza objects for more information on how to create
|
||||||
|
and use stanza objects and stanza plugins.
|
||||||
|
|
||||||
|
We will reuse the IQ roster query stanza to store roster
|
||||||
|
information since it already exists.
|
||||||
|
|
||||||
|
Example config XML:
|
||||||
|
<config xmlns="sleekxmpp:config">
|
||||||
|
<jid>component.localhost</jid>
|
||||||
|
<secret>ssshh</secret>
|
||||||
|
<server>localhost</server>
|
||||||
|
<port>8888</port>
|
||||||
|
|
||||||
|
<query xmlns="jabber:iq:roster">
|
||||||
|
<item jid="user@example.com" subscription="both" />
|
||||||
|
</query>
|
||||||
|
</config>
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "config"
|
||||||
|
namespace = "sleekxmpp:config"
|
||||||
|
interfaces = set(('jid', 'secret', 'server', 'port'))
|
||||||
|
sub_interfaces = interfaces
|
||||||
|
|
||||||
|
|
||||||
|
registerStanzaPlugin(Config, Roster)
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigComponent(ComponentXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP component that uses an external XML
|
||||||
|
file to store its configuration data. To make testing
|
||||||
|
that the component works, it will also echo messages sent
|
||||||
|
to it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, config):
|
||||||
|
"""
|
||||||
|
Create a ConfigComponent.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
config -- The XML contents of the config file.
|
||||||
|
config_file -- The XML config file object itself.
|
||||||
|
"""
|
||||||
|
ComponentXMPP.__init__(self, config['jid'],
|
||||||
|
config['secret'],
|
||||||
|
config['server'],
|
||||||
|
config['port'])
|
||||||
|
|
||||||
|
# Store the roster information.
|
||||||
|
self.roster = config['roster']['items']
|
||||||
|
|
||||||
|
# The session_start event will be triggered when
|
||||||
|
# the component 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
|
||||||
|
# broadcast any needed initial presence stanzas.
|
||||||
|
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.
|
||||||
|
|
||||||
|
The typical action for the session_start event in a component
|
||||||
|
is to broadcast presence stanzas to all subscribers to the
|
||||||
|
component. Note that the component does not have a roster
|
||||||
|
provided by the XMPP server. In this case, we have possibly
|
||||||
|
saved a roster in the component's configuration file.
|
||||||
|
|
||||||
|
Since the component may use any number of JIDs, you should
|
||||||
|
also include the JID that is sending the presence.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
for jid in self.roster:
|
||||||
|
if self.roster[jid]['subscription'] != 'none':
|
||||||
|
self.sendPresence(pfrom=self.jid, pto=jid)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Component name and secret options.
|
||||||
|
optp.add_option("-c", "--config", help="path to config file",
|
||||||
|
dest="config", default="config.xml")
|
||||||
|
|
||||||
|
opts, args = optp.parse_args()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.loglevel,
|
||||||
|
format='%(levelname)-8s %(message)s')
|
||||||
|
|
||||||
|
# Load configuration data.
|
||||||
|
config_file = open(opts.config, 'r+')
|
||||||
|
config_data = "\n".join([line for line in config_file])
|
||||||
|
config = Config(xml=ET.fromstring(config_data))
|
||||||
|
config_file.close()
|
||||||
|
|
||||||
|
# Setup the ConfigComponent and register plugins. Note that while plugins may
|
||||||
|
# have interdependencies, the order in which you register them does
|
||||||
|
# not matter.
|
||||||
|
xmpp = ConfigComponent(config)
|
||||||
|
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(threaded=False)
|
||||||
|
print("Done")
|
||||||
|
else:
|
||||||
|
print("Unable to connect.")
|
123
examples/echo_client.py
Normal file → Executable file
123
examples/echo_client.py
Normal file → Executable file
|
@ -1,54 +1,129 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# coding=utf8
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import sleekxmpp
|
"""
|
||||||
import logging
|
SleekXMPP: The Sleek XMPP Library
|
||||||
from optparse import OptionParser
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
import time
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
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):
|
if sys.version_info < (3,0):
|
||||||
reload(sys)
|
reload(sys)
|
||||||
sys.setdefaultencoding('utf8')
|
sys.setdefaultencoding('utf8')
|
||||||
|
|
||||||
|
|
||||||
class Example(sleekxmpp.ClientXMPP):
|
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):
|
def __init__(self, jid, password):
|
||||||
sleekxmpp.ClientXMPP.__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 intialize
|
||||||
|
# our roster.
|
||||||
self.add_event_handler("session_start", self.start)
|
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)
|
self.add_event_handler("message", self.message)
|
||||||
|
|
||||||
def start(self, event):
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an intial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
self.getRoster()
|
self.getRoster()
|
||||||
self.sendPresence()
|
self.sendPresence()
|
||||||
|
|
||||||
def message(self, msg):
|
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()
|
msg.reply("Thanks for sending\n%(body)s" % msg).send()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
#parse command line arguements
|
# Setup the command line arguments.
|
||||||
optp = OptionParser()
|
optp = OptionParser()
|
||||||
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("-j","--jid", dest="jid", help="JID to use")
|
|
||||||
optp.add_option("-p","--password", dest="password", help="password to use")
|
|
||||||
opts,args = optp.parse_args()
|
|
||||||
|
|
||||||
logging.basicConfig(level=opts.loglevel, format='%(levelname)-8s %(message)s')
|
# Output verbosity options.
|
||||||
xmpp = Example(opts.jid, opts.password)
|
optp.add_option('-q','--quiet', help='set logging to ERROR',
|
||||||
xmpp.registerPlugin('xep_0030')
|
action='store_const', dest='loglevel',
|
||||||
xmpp.registerPlugin('xep_0004')
|
const=logging.ERROR, default=logging.INFO)
|
||||||
xmpp.registerPlugin('xep_0060')
|
optp.add_option('-d','--debug', help='set logging to DEBUG',
|
||||||
xmpp.registerPlugin('xep_0199')
|
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)
|
||||||
|
|
||||||
# use this if you don't have pydns, and want to
|
# JID and password options.
|
||||||
# talk to GoogleTalk (e.g.)
|
optp.add_option("-j", "--jid", dest="jid",
|
||||||
if xmpp.connect(('talk.google.com', 5222)):
|
help="JID to use")
|
||||||
#khif xmpp.connect():
|
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')
|
||||||
|
|
||||||
|
# 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.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():
|
||||||
|
# If you do not have the pydns 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(threaded=False)
|
xmpp.process(threaded=False)
|
||||||
print("done")
|
print("Done")
|
||||||
else:
|
else:
|
||||||
print("Unable to connect.")
|
print("Unable to connect.")
|
||||||
|
|
Loading…
Reference in a new issue