gajim-plural/src/common/commands.py

260 lines
7.7 KiB
Python
Raw Normal View History

2006-07-17 15:40:25 +02:00
##
## Copyright (C) 2006 Gajim Team
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 2 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
import xmpp
import helpers
import dataforms
import gajim
class AdHocCommand:
commandnode = 'command'
commandname = 'The Command'
commandfeatures = (xmpp.NS_DATA,)
@staticmethod
2006-07-17 19:52:37 +02:00
def isVisibleFor(samejid):
''' This returns True if that command should be visible and invokable
for others.
samejid - True when command is invoked by an entity with the same bare jid.
'''
return True
2006-07-17 15:40:25 +02:00
def __init__(self, conn, jid, sessionid):
self.connection = conn
self.jid = jid
self.sessionid = sessionid
def buildResponse(self, request, status='executing', defaultaction=None, actions=None):
assert status in ('executing', 'completed', 'canceled')
response = request.buildReply('result')
cmd = response.addChild('command', {
'xmlns': xmpp.NS_COMMANDS,
'sessionid': self.sessionid,
'node': self.commandnode,
'status': status})
if defaultaction is not None or actions is not None:
if defaultaction is not None:
assert defaultaction in ('cancel', 'execute', 'prev', 'next', 'complete')
attrs = {'action': defaultaction}
else:
attrs = {}
cmd.addChild('actions', attrs, actions)
return response, cmd
def badRequest(self, stanza):
self.connection.connection.send(xmpp.Error(stanza, xmpp.NS_STANZAS+' bad-request'))
2006-07-17 19:52:37 +02:00
2006-07-17 15:40:25 +02:00
def cancel(self, request):
response, cmd = self.buildResponse(request, status='canceled')
2006-07-17 19:52:37 +02:00
self.connection.connection.send(response)
2006-07-17 15:40:25 +02:00
return False # finish the session
class ChangeStatusCommand(AdHocCommand):
commandnode = 'change-status'
commandname = 'Change status information'
2006-07-17 19:52:37 +02:00
@staticmethod
def isVisibleFor(samejid):
''' Change status is visible only if the entity has the same bare jid. '''
return samejid
2006-07-17 15:40:25 +02:00
def execute(self, request):
# first query...
response, cmd = self.buildResponse(request, defaultaction='execute', actions=['execute'])
cmd.addChild(node=dataforms.SimpleDataForm(
2006-07-17 15:40:25 +02:00
title='Change status',
instructions='Set the presence type and description',
fields=[
dataforms.Field('list-single',
var='presence-type',
2006-07-17 15:40:25 +02:00
label='Type of presence:',
options=[
(u'free-for-chat', u'Free for chat'),
(u'online', u'Online'),
(u'away', u'Away'),
(u'xa', u'Extended away'),
(u'dnd', u'Do not disturb'),
(u'offline', u'Offline - disconnect')],
value='online',
required=True),
dataforms.Field('text-multi',
var='presence-desc',
2006-07-17 15:40:25 +02:00
label='Presence description:')]))
2006-07-17 19:52:37 +02:00
self.connection.connection.send(response)
2006-07-17 15:40:25 +02:00
# for next invocation
self.execute = self.changestatus
return True # keep the session
def changestatus(self, request):
# check if the data is correct
try:
form=dataforms.SimpleDataForm(extend=request.getTag('command').getTag('x'))
except:
self.badRequest(request)
2006-07-17 15:40:25 +02:00
return False
try:
presencetype = form['presence-type'].value
if not presencetype in \
('free-for-chat', 'online', 'away', 'xa', 'dnd', 'offline'):
self.badRequest(request)
2006-07-17 19:52:37 +02:00
return False
except: # KeyError if there's no presence-type field in form or
# AttributeError if that field is of wrong type
self.badRequest(request)
2006-07-17 19:52:37 +02:00
return False
2006-07-17 15:40:25 +02:00
try:
presencedesc = form['presence-desc'].value
except: # same exceptions as in last comment
2006-07-17 15:40:25 +02:00
presencedesc = u''
response, cmd = self.buildResponse(request, status='completed')
cmd.addChild('note', {}, 'The status has been changed.')
# if going offline, we need to push response so it won't go into
# queue and disappear
self.connection.connection.send(response, presencetype=='offline')
2006-07-17 15:40:25 +02:00
2006-07-17 19:52:37 +02:00
# send new status
gajim.interface.roster.send_status(self.connection.name, presencetype, presencedesc)
2006-07-17 15:40:25 +02:00
return False # finish the session
class ConnectionCommands:
''' This class depends on that it is a part of Connection() class. '''
def __init__(self):
# a list of all commands exposed: node -> command class
self.__commands = {}
for cmdobj in (ChangeStatusCommand,):
self.__commands[cmdobj.commandnode] = cmdobj
# a list of sessions; keys are tuples (jid, sessionid, node)
self.__sessions = {}
2006-07-17 19:52:37 +02:00
def getOurBareJID(self):
return gajim.get_jid_from_account(self.name)
def isSameJID(self, jid):
''' Tests if the bare jid given is the same as our bare jid. '''
return xmpp.JID(jid).getStripped() == self.getOurBareJID()
2006-07-17 15:40:25 +02:00
def commandListQuery(self, con, iq_obj):
iq = iq_obj.buildReply('result')
jid = helpers.get_full_jid_from_iq(iq_obj)
q = iq.getTag('query')
for node, cmd in self.__commands.iteritems():
2006-07-17 19:52:37 +02:00
if cmd.isVisibleFor(self.isSameJID(jid)):
2006-07-17 15:40:25 +02:00
q.addChild('item', {
# TODO: find the jid
2006-07-17 19:52:37 +02:00
'jid': self.getOurBareJID()+u'/'+self.server_resource,
2006-07-17 15:40:25 +02:00
'node': node,
'name': cmd.commandname})
self.connection.send(iq)
def commandQuery(self, con, iq_obj):
''' Send disco result for query for command (JEP-0050, example 6.).
Return True if the result was sent, False if not. '''
jid = helpers.get_full_jid_from_iq(iq_obj)
node = iq_obj.getTagAttr('query', 'node')
if node not in self.__commands: return False
cmd = self.__commands[node]
2006-07-17 19:52:37 +02:00
if cmd.isVisibleFor(self.isSameJID(jid)):
2006-07-17 15:40:25 +02:00
iq = iq_obj.buildReply('result')
q = iq.getTag('query')
q.addChild('identity', attrs = {'type': 'command-node',
'category': 'automation',
'name': cmd.commandname})
q.addChild('feature', attrs = {'var': xmpp.NS_COMMANDS})
for feature in cmd.commandfeatures:
q.addChild('feature', attrs = {'var': feature})
self.connection.send(iq)
return True
return False
def _CommandExecuteCB(self, con, iq_obj):
jid = helpers.get_full_jid_from_iq(iq_obj)
cmd = iq_obj.getTag('command')
if cmd is None: return
node = cmd.getAttr('node')
if node is None: return
sessionid = cmd.getAttr('sessionid')
if sessionid is None:
# we start a new command session... only if we are visible for the jid
# and command exist
if node not in self.__commands.keys():
self.connection.send(
xmpp.Error(iq_obj, xmpp.NS_STANZAS+' item-not-found'))
raise xmpp.NodeProcessed
2006-07-17 15:40:25 +02:00
newcmd = self.__commands[node]
2006-07-17 19:52:37 +02:00
if not newcmd.isVisibleFor(self.isSameJID(jid)):
2006-07-17 15:40:25 +02:00
return
# generate new sessionid
sessionid = self.connection.getAnID()
# create new instance and run it
2006-07-17 19:52:37 +02:00
obj = newcmd(conn=self, jid=jid, sessionid=sessionid)
2006-07-17 15:40:25 +02:00
rc = obj.execute(iq_obj)
if rc:
self.__sessions[(jid, sessionid, node)] = obj
2006-07-17 19:52:37 +02:00
raise xmpp.NodeProcessed
2006-07-17 15:40:25 +02:00
else:
# the command is already running, check for it
magictuple = (jid, sessionid, node)
if magictuple not in self.__sessions:
# we don't have this session... ha!
return
action = cmd.getAttr('action')
obj = self.__sessions[magictuple]
try:
if action == 'cancel': rc = obj.cancel(iq_obj)
elif action == 'prev': rc = obj.prev(iq_obj)
elif action == 'next': rc = obj.next(iq_obj)
elif action == 'execute' or action is None:
rc = obj.execute(iq_obj)
elif action == 'complete': rc = obj.complete(iq_obj)
2006-07-17 15:40:25 +02:00
else:
# action is wrong. stop the session, send error
2006-07-17 19:52:37 +02:00
raise AttributeError
2006-07-17 15:40:25 +02:00
except AttributeError:
# the command probably doesn't handle invoked action...
# stop the session, return error
del self.__sessions[magictuple]
return
# delete the session if rc is False
if not rc:
del self.__sessions[magictuple]
raise xmpp.NodeProcessed