summaryrefslogtreecommitdiff
path: root/src/xmpppy-0.5.0rc1/doc/examples/commandsbot.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmpppy-0.5.0rc1/doc/examples/commandsbot.py')
-rw-r--r--src/xmpppy-0.5.0rc1/doc/examples/commandsbot.py289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/xmpppy-0.5.0rc1/doc/examples/commandsbot.py b/src/xmpppy-0.5.0rc1/doc/examples/commandsbot.py
new file mode 100644
index 00000000..f32c13c6
--- /dev/null
+++ b/src/xmpppy-0.5.0rc1/doc/examples/commandsbot.py
@@ -0,0 +1,289 @@
+#!/usr/bin/python
+""" The example of using xmpppy's Ad-Hoc Commands (JEP-0050) implementation.
+"""
+import xmpp
+from xmpp.protocol import *
+
+options = {
+ 'JID': 'circles@example.com',
+ 'Password': '********',
+}
+
+class TestCommand(xmpp.commands.Command_Handler_Prototype):
+ """ Example class. You should read source if you wish to understate how it works. This one
+ actually does some calculations."""
+ name = 'testcommand'
+ description = 'Circle calculations'
+ def __init__(self, jid=''):
+ """ Initialize some internals. Set the first request handler to self.calcTypeForm.
+ """
+ xmpp.commands.Command_Handler_Prototype.__init__(self,jid)
+ self.initial = {
+ 'execute': self.initialForm
+ }
+
+ def initialForm(self, conn, request):
+ """ Assign a session id and send the first form. """
+ sessionid = self.getSessionID()
+ self.sessions[sessionid] = {
+ 'jid':request.getFrom(),
+ 'data':{'type':None}
+ }
+
+ # simulate that the client sent sessionid, so calcTypeForm will be able
+ # to continue
+ request.getTag(name="command").setAttr('sessionid', sessionid)
+
+ return self.calcTypeForm(conn, request)
+
+ def calcTypeForm(self, conn, request):
+ """ Send first form to the requesting user. """
+ # get the session data
+ sessionid = request.getTagAttr('command','sessionid')
+ session = self.sessions[sessionid]
+
+ # What to do when a user sends us a response? Note, that we should always
+ # include 'execute', as it is a default action when requester does not send
+ # exact action to do (should be set to the same as 'next' or 'complete' fields)
+ session['actions'] = {
+ 'cancel': self.cancel,
+ 'next': self.calcTypeFormAccept,
+ 'execute': self.calcTypeFormAccept,
+ }
+
+ # The form to send
+ calctypefield = xmpp.DataField(
+ name='calctype',
+ desc='Calculation Type',
+ value=session['data']['type'],
+ options=[
+ ['Calculate the diameter of a circle','circlediameter'],
+ ['Calculate the area of a circle','circlearea']
+ ],
+ typ='list-single',
+ required=1)
+
+ # We set label attribute... seems that the xmpppy.DataField cannot do that
+ calctypefield.setAttr('label', 'Calculation Type')
+
+ form = xmpp.DataForm(
+ title='Select type of operation',
+ data=[
+ 'Use the combobox to select the type of calculation you would like'\
+ 'to do, then click Next.',
+ calctypefield])
+
+ # Build a reply with the form
+ reply = request.buildReply('result')
+ replypayload = [
+ xmpp.Node('actions',
+ attrs={'execute':'next'},
+ payload=[xmpp.Node('next')]),
+ form]
+ reply.addChild(
+ name='command',
+ namespace=NS_COMMANDS,
+ attrs={
+ 'node':request.getTagAttr('command','node'),
+ 'sessionid':sessionid,
+ 'status':'executing'},
+ payload=replypayload)
+ self._owner.send(reply) # Question: self._owner or conn?
+ raise xmpp.NodeProcessed
+
+ def calcTypeFormAccept(self, conn, request):
+ """ Load the calcType form filled in by requester, then reply with
+ the second form. """
+ # get the session data
+ sessionid = request.getTagAttr('command','sessionid')
+ session = self.sessions[sessionid]
+
+ # load the form
+ node = request.getTag(name='command').getTag(name='x',namespace=NS_DATA)
+ form = xmpp.DataForm(node=node)
+
+ # retrieve the data
+ session['data']['type'] = form.getField('calctype').getValue()
+
+ # send second form
+ return self.calcDataForm(conn, request)
+
+ def calcDataForm(self, conn, request, notavalue=None):
+ """ Send a form asking for diameter. """
+ # get the session data
+ sessionid = request.getTagAttr('command','sessionid')
+ session = self.sessions[sessionid]
+
+ # set the actions taken on requester's response
+ session['actions'] = {
+ 'cancel': self.cancel,
+ 'prev': self.calcTypeForm,
+ 'next': self.calcDataFormAccept,
+ 'execute': self.calcDataFormAccept
+ }
+
+ # create a form
+ radiusfield = xmpp.DataField(desc='Radius',name='radius',typ='text-single')
+ radiusfield.setAttr('label', 'Radius')
+
+ form = xmpp.DataForm(
+ title = 'Enter the radius',
+ data=[
+ 'Enter the radius of the circle (numbers only)',
+ radiusfield])
+
+ # build a reply stanza
+ reply = request.buildReply('result')
+ replypayload = [
+ xmpp.Node('actions',
+ attrs={'execute':'complete'},
+ payload=[xmpp.Node('complete'),xmpp.Node('prev')]),
+ form]
+
+ if notavalue:
+ replypayload.append(xmpp.Node('note',
+ attrs={'type': 'warn'},
+ payload=['You have to enter valid number.']))
+
+ reply.addChild(
+ name='command',
+ namespace=NS_COMMANDS,
+ attrs={
+ 'node':request.getTagAttr('command','node'),
+ 'sessionid':request.getTagAttr('command','sessionid'),
+ 'status':'executing'},
+ payload=replypayload)
+
+ self._owner.send(reply)
+ raise xmpp.NodeProcessed
+
+ def calcDataFormAccept(self, conn, request):
+ """ Load the calcType form filled in by requester, then reply with the result. """
+ # get the session data
+ sessionid = request.getTagAttr('command','sessionid')
+ session = self.sessions[sessionid]
+
+ # load the form
+ node = request.getTag(name='command').getTag(name='x',namespace=NS_DATA)
+ form = xmpp.DataForm(node=node)
+
+ # retrieve the data; if the entered value is not a number, return to second stage
+ try:
+ value = float(form.getField('radius').getValue())
+ except:
+ self.calcDataForm(conn, request, notavalue=True)
+
+ # calculate the answer
+ from math import pi
+ if session['data']['type'] == 'circlearea':
+ result = (value**2) * pi
+ else:
+ result = 2 * value * pi
+
+ # build the result form
+ form = xmpp.DataForm(
+ typ='result',
+ data=[xmpp.DataField(desc='result', name='result', value=result)])
+
+ # build the reply stanza
+ reply = request.buildReply('result')
+ reply.addChild(
+ name='command',
+ namespace=NS_COMMANDS,
+ attrs={
+ 'node':request.getTagAttr('command','node'),
+ 'sessionid':sessionid,
+ 'status':'completed'},
+ payload=[form])
+
+ self._owner.send(reply)
+
+ # erase the data about session
+ del self.sessions[sessionid]
+
+ raise xmpp.NodeProcessed
+
+ def cancel(self, conn, request):
+ """ Requester canceled the session, send a short reply. """
+ # get the session id
+ sessionid = request.getTagAttr('command','sessionid')
+
+ # send the reply
+ reply = request.buildReply('result')
+ reply.addChild(
+ name='command',
+ namespace=NS_COMMANDS,
+ attrs={
+ 'node':request.getTagAttr('command','node'),
+ 'sessionid':sessionid,
+ 'status':'cancelled'})
+ self._owner.send(reply)
+
+ # erase the data about session
+ del self.sessions[sessionid]
+
+ raise xmpp.NodeProcessed
+
+class ConnectionError: pass
+class AuthorizationError: pass
+class NotImplemented: pass
+
+class Bot:
+ """ The main bot class. """
+
+ def __init__(self, JID, Password):
+ """ Create a new bot. Connect to the server and log in. """
+
+ # connect...
+ jid = xmpp.JID(JID)
+ self.connection = xmpp.Client(jid.getDomain(), debug=['always', 'browser', 'testcommand'])
+
+ result = self.connection.connect()
+
+ if result is None:
+ raise ConnectionError
+
+ # authorize
+ result = self.connection.auth(jid.getNode(), Password)
+
+ if result is None:
+ raise AuthorizationError
+
+ # plugins
+ # disco - needed by commands
+
+ # warning: case of "plugin" method names are important!
+ # to attach a command to Commands class, use .plugin()
+ # to attach anything to Client class, use .PlugIn()
+ self.disco = xmpp.browser.Browser()
+ self.disco.PlugIn(self.connection)
+ self.disco.setDiscoHandler({
+ 'info': {
+ 'ids': [{
+ 'category': 'client',
+ 'type': 'pc',
+ 'name': 'Bot'
+ }],
+ 'features': [NS_DISCO_INFO],
+ }
+ })
+
+ self.commands = xmpp.commands.Commands(self.disco)
+ self.commands.PlugIn(self.connection)
+
+ self.command_test = TestCommand()
+ self.command_test.plugin(self.commands)
+
+ # presence
+ self.connection.sendInitPresence(requestRoster=0)
+
+ def loop(self):
+ """ Do nothing except handling new xmpp stanzas. """
+ try:
+ while self.connection.Process(1):
+ pass
+ except KeyboardInterrupt:
+ pass
+
+bot = Bot(**options)
+bot.loop()