Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/gajim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/commands.py232
-rw-r--r--src/common/connection_handlers.py115
-rw-r--r--src/common/dataforms.py7
3 files changed, 241 insertions, 113 deletions
diff --git a/src/common/commands.py b/src/common/commands.py
new file mode 100644
index 000000000..746f1a1a6
--- /dev/null
+++ b/src/common/commands.py
@@ -0,0 +1,232 @@
+##
+## 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
+ def isVisibleFor(jid): return True
+
+ 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 cancel(self, request):
+ response, cmd = self.buildResponse(request, status='canceled')
+ self.connection.send(response)
+ return False # finish the session
+
+class ChangeStatusCommand(AdHocCommand):
+ commandnode = 'change-status'
+ commandname = 'Change status information'
+
+ def execute(self, request):
+ # first query...
+ response, cmd = self.buildResponse(request, defaultaction='execute', actions=['execute'])
+
+ cmd.addChild(node=dataforms.DataForm(
+ title='Change status',
+ instructions='Set the presence type and description',
+ fields=[
+ dataforms.DataField('list-single', 'presence-type',
+ 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.DataField('text-multi', 'presence-desc',
+ label='Presence description:')]))
+
+ self.connection.send(response)
+
+ # 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.DataForm(node=request.getTag('command').getTag('x'))
+ except TypeError:
+ return False
+
+ try:
+ presencetype = form['presence-type']
+ if not presencetype in ('free-for-chat', 'online', 'away', 'xa', 'dnd', 'offline'):
+ #raise BadSomething
+ return
+ except KeyError:
+# raise BadSomething
+ return
+
+ try:
+ presencedesc = form['presence-desc']
+ except KeyError:
+ presencedesc = u''
+
+ response, cmd = self.buildResponse(request, status='completed')
+ cmd.addChild('note', {}, 'The status has been changed.')
+
+ self.connection.send(response)
+
+ # looking for account name...
+ accname = None
+ for acc in gajim.connections.iterkeys():
+ if self.connection is gajim.connections[acc]:
+ accname=acc
+ assert accname is not None
+
+ gajim.interface.roster.send_status(accname, presencetype, presencedesc)
+
+ 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 = {}
+
+ 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():
+ if cmd.isVisibleFor(jid):
+ q.addChild('item', {
+ # TODO: find the jid
+ 'jid': 'our-jid',
+ '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]
+ if cmd.isVisibleFor(jid):
+ 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
+ newcmd = self.__commands[node]
+ if not newcmd.isVisibleFor(jid):
+ return
+
+ # generate new sessionid
+ sessionid = self.connection.getAnID()
+
+ # create new instance and run it
+ obj = newcmd(conn=self.connection, jid=jid, sessionid=sessionid)
+ rc = obj.execute(iq_obj)
+ if rc:
+ self.__sessions[(jid, sessionid, node)] = obj
+ raise NodeProcessed
+ 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': rc = obj.execute(iq_obj)
+ elif action == 'complete': rc = obj.complete(iq_obj)
+ else:
+ # action is wrong. stop the session, send error
+ del self.__sessions[magictuple]
+ return
+ 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
+
diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py
index f52104e68..522ef46ec 100644
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -32,6 +32,8 @@ import common.xmpp
from common import GnuPG
from common import helpers
from common import gajim
+from common import dataforms
+from common.commands import ConnectionCommands
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
'invisible']
@@ -1054,119 +1056,6 @@ class ConnectionVcard:
else:
self.dispatch('VCARD', vcard)
-class AdHocCommand:
- commandnode = 'command'
- commandname = 'The Command'
- commandfeatures = (common.xmpp.NS_DATA,)
-
- @staticmethod
- def isVisibleFor(jid): return True
-
-class ChangeStatusCommand(AdHocCommand):
- commandnode = 'change-status'
- commandname = 'Change status information'
- def __init__(self, sessiondata):
- pass
-
-class ConnectionCommands:
- def __init__(self):
- # a list of all commands exposed
- self.__commands = {}
- for cmdobj in (ChangeStatusCommand,):
- self.__commands[cmdobj.commandnode] = cmdobj
-
- # a list of sessions; keys are tuples (jid, sessionid, node)
- self.__sessions = {}
-
- 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.iter_items():
- if cmd.isVisibleFor(jid):
- q.addChild('item', {
- 'jid': 'our-jid',
- '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]
- if cmd.isVisibleFor(jid):
- 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': common.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
- newcmd = self.__commands[node]
- if not newcmd.isVisibleFor(jid):
- return
-
- # generate new sessionid
- sessionid = self.connection.getAnID()
-
- # create new instance and run it
- obj = newcmd(jid=jid, sessionid=sessionid)
- rc = obj.execute()
- if rc:
- self.__sessions[(jid, sessionid, node)] = obj
- raise NodeProcessed
- 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]
-
- 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': rc = obj.execute(iq_obj)
- elif action == 'complete': rc = obj.complete(iq_obj)
- else:
- # action is wrong. stop the session, send error
- del self.__sessions[magictuple]
- return
-
- # delete the session if rc is False
- if not rc:
- del self.__sessions[magictuple]
-
- raise NodeProcessed
-
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands):
def __init__(self):
ConnectionVcard.__init__(self)
diff --git a/src/common/dataforms.py b/src/common/dataforms.py
index 5acf452ad..6c1e76240 100644
--- a/src/common/dataforms.py
+++ b/src/common/dataforms.py
@@ -287,6 +287,13 @@ class DataForm(xmpp.Node, object):
return
raise KeyError, "This form does not contain %r field." % var
+ def __contains__(self, name):
+ for field in self.iter_fields():
+ if field.var==name:
+ return True
+ else:
+ return False
+
class DataField(xmpp.Node, object):
def __init__(self, typ=None,var=None, value=None, label=None, desc=None,
required=None, options=None, node=None):