adhoc command infrastructure
From: Roelof Naude <roelof.naude@xxxxxxxxxx>
Date: Mon, 19 Mar 2007 13:13:11 +0100 (CET)
hi

gloox currently supplies a complete infrastructure to execute a command
on a remote entity. unfortunately the infrastructure to allow command
execution within one's own bot/client is lacking.

the attach files (not patches), provide such a framework. the idea is to
spark conversation/ideas/discussion around the framework. the files
currently contains (some) lines of other code not included, and will NOT
compile as is. this is fairly easy to fix/change...

how do one use the framework? that is very easy as well:
1. create an instance of gloox::adhoc
2. create an instance of AdhocCommandManager
3. derive your own command implementations from AdhocCommand
4. register commands with AdhocCommandManager
(AdhocCommandManager::addCommand)

the framework was taken from wild-/openfire:
http://svn.igniterealtime.org/svn/repos/wildfire/trunk/src/java/org/jivesoftware/wildfire/commands/{AdHocCommand,
AdHocCommandHandler,SessionData}.java

i've removed 3 features from the java implementation, i.e
1. session expiration (this is trivial to add)
2. limit of simultaneous commands executed (can be re-added)
3. the AdhocCommand will always allow a client to execute the command
(see AdHocCommand.cpp#hasPermission). a subclass can choose to override
the default behavior.

a slighty tighter integration with gloox can be achieved by allowing
AdhocCommandManager to handle disco#items. In such a case only commands
which the user is allowed to execute will be shown during service discovery.

comments welcome.

regards
roelof.


#include "AdhocCommand.h"

#include <gloox/tag.h>

bool AdhocCommand::hasPermission(const std::string& bareJid) const
{
  return true;
}

void AdhocCommand::addNextStageInformation(SessionData& data, gloox::Tag* 
command) 
{
  // Increment the stage number to the next stage
  data.setStage(data.getStage() + 1);
  // Return the data form of the current stage to the command requester. The
  // requester will need to specify the action to follow (e.g. execute, prev,
  // cancel, etc.) and complete the form is going "forward"
  addStageInformation(data, command);
  // Include the available actions at this stage
  addStageActions(data, command);
}

void AdhocCommand::addPreviousStageInformation(SessionData& data, gloox::Tag* 
command) 
{
  // Decrement the stage number to the previous stage
  data.setStage(data.getStage() - 1);
  // Return the data form of the current stage to the command requester. The
  // requester will need to specify the action to follow (e.g. execute, prev,
  // cancel, etc.) and complete the form is going "forward"
  addStageInformation(data, command);
  // Include the available actions at this stage
  addStageActions(data, command);
}

void AdhocCommand::addStageActions(SessionData& data, gloox::Tag* command) 
{
  // Add allowed actions to the response
  gloox::Tag* actions = new gloox::Tag(command, "actions");
  gloox::StringList validActions = getActions(data);
  gloox::StringList::const_iterator it = validActions.begin();
  for ( ; it != validActions.end(); ++it) {
    new gloox::Tag(actions, *it);
  } //for
  
  std::string executeAction = getExecuteAction(data);
  // Add default execute action to the response
  actions->addAttribute("execute", executeAction);

  // Store the allowed actions that the user can follow from this stage
  data.setAllowedActions(validActions);
  // Store the default execute action to follow if the user does not specify an
  // action in his command
  data.setExecuteAction(executeAction);
}

#ifndef ADHOCCOMMAND_H
#define ADHOCCOMMAND_H

#include <string>

#include "SessionData.h"

#include <gloox/gloox.h>
#include <gloox/jid.h>

class gloox::Tag;

/**
 * An ad-hoc command is a stateless object responsbile for executing the 
provided service. Each
 * subclass will only have one instance that will be shared across all users 
sessions. T
 * Therefore, it is important to not keep any information related to executions 
as permanent 
 * data (i.e. as instance or static variables). Each command has a 
<tt>code</tt> that should be
 * unique within a given JID.<p>
 *
 * Commands may have zero or more stages. Each stage is usually used for 
gathering information
 * required for the command execution. Users are able to move forward or 
backward across the
 * different stages. Commands may not be cancelled while they are beig 
executed. However, users
 * may request the "cancel" action when submiting a stage response indicating 
that the command
 * execution should be aborted. Thus, releasing any collected information. 
Commands that require
 * user interaction (i.e. have more than one stage) will have to provide the 
data forms the user
 * must complete in each stage and the allowed actions the user might perform 
during each stage
 * (e.g. go to the previous stage or go to the next stage).<p>
 *
 * This implemetation is taken from wild-/openfire.
 * \see 
http://svn.igniterealtime.org/svn/repos/wildfire/trunk/src/java/org/jivesoftware/wildfire/commands/AdHocCommand.java
 */
class AdhocCommand 
{
  public:
    /**
     * Destructor
     */
    virtual ~AdhocCommand() {};
    /**
     * \return The descriptive label of the command
     */
    virtual std::string getLabel() const = 0;
    /**
     * Returns true if the requester is allowed to execute this command. 
Subclasses may 
     * redefine this method with any specific logic.<p>
     *
     * Note: The default implementation always return \c true
     *
     * \param requester the JID of the user requesting to execute this command.
     * \return true if the requester is allowed to execute this command.
     */
    virtual bool hasPermission(const std::string& bareJid) const;
    /**
     * Returns the unique identifier for this command for the containing JID. 
The code will
     * be used as the node in the disco#items or the node when executing the 
command.
     *
     * \return the unique identifier for this command for the containing JID.
     */
    virtual std::string getCode() const = 0;
    /**
     * Returns the max number of stages for this command. The number of stages 
may vary 
     * according to the collected data in previous stages. Therefore, a 
SessionData object is 
     * passed as a parameter. When the max number of stages has been reached 
then the command 
     * is ready to be executed.
     *
     * \param data the gathered data through the command stages or 
<tt>null</tt> if the
     *        command does not have stages or the requester is requesting the 
execution for the
     *        first time.
     * \return the max number of stages for this command.
     */
    virtual int getMaxStages() const = 0;
    /**
     * Executes the command with the specified session data.
     *
     * \param data the gathered data through the command stages or 
<tt>null</tt> if the
     *        command does not have stages.
     * \param command the command element to be sent to the command requester 
with a reported
     *        data result or note element with the answer of the execution.
     */
    virtual void execute(SessionData& data, gloox::Tag* command) = 0;
    /**
     * Increments the stage number by one and adds to the command element the 
new data form and
     * new allowed actions that the user might perform.
     *
     * \param data the gathered data through the command stages.
     * \param command the command element to be sent to the command requester.
     */
    void addNextStageInformation(SessionData& data, gloox::Tag* command);

    /**
     * Decrements the stage number by one and adds to the command the data form 
and allowed
     * actions that the user might perform of the previous stage.
     *
     * \param data the gathered data through the command stages.
     * \param command the command element to be sent to the command requester.
     */
    void addPreviousStageInformation(SessionData& data, gloox::Tag* command);
  protected:    
    /**
     * Adds to the command element the data form or notes required by the 
current stage. The
     * current stage is specified in the SessionData. This method will never be 
invoked for
     * commands that have no stages.
     *
     * \param data the gathered data through the command stages or 
<tt>null</tt> if the
     *        command does not have stages or the requester is requesting the 
execution for the
     *        first time.
     * \param command the command element to be sent to the command requester.
     */
    virtual void addStageInformation(SessionData& data, gloox::Tag* command) = 
0;
    /**
     * Returns a collection with the allowed actions based on the current stage 
as defined
     * in the SessionData. Possible actions are: <tt>prev</tt>, <tt>next</tt> 
and 
     * <tt>complete</tt>. This method will never be invoked for commands that 
have no stages.
     *
     * \param data the gathered data through the command stages or 
<tt>null</tt> if the
     *        command does not have stages or the requester is requesting the 
execution for the
     *        first time.
     * \return a collection with the allowed actions based on the current stage 
as defined
     *         in the SessionData.
     */
    virtual gloox::StringList getActions(SessionData& data) const = 0;
    /**
     * Returns which of the actions available for the current stage is 
considered the equivalent
     * to "execute". When the requester sends his reply, if no action was 
defined in the command
     * then the action will be assumed "execute" thus assuming the action 
returned by this
     * method. This method will never be invoked for commands that have no 
stages.
     *
     * \param data the gathered data through the command stages or 
<tt>null</tt> if the
     *        command does not have stages or the requester is requesting the 
execution for the
     *        first time.
     * \return which of the actions available for the current stage is 
considered the equivalent
              to "execute".
     */
    virtual std::string getExecuteAction(SessionData& data) const = 0;
    /**
     * Adds the allowed actions to follow from the current stage. Possible 
actions are:
     * <tt>prev</tt>, <tt>next</tt> and <tt>complete</tt>.
     *
     * \param data the gathered data through the command stages or 
<tt>null</tt> if the
     *        command does not have stages or the requester is requesting the 
execution for the
     *        first time.
     * \param command the command element to be sent to the command requester.
     */
  private:  
    /**
     * Add the list of valid actions to the \c command element
     * \param data The session data
     * \param command The command xml element
     */   
    void addStageActions(SessionData& data, gloox::Tag* command);
};

#endif

#include "AdhocCommandManager.h"

#include <gloox/dataform.h>

#include <map>
#include <string>

#include "Logger.h"
#include "XmppUtil.h"

AdhocCommandManager::AdhocCommandManager(gloox::Adhoc* adhoc, 
gloox::ClientBase* parent)
  : m_adhoc(adhoc),
    m_parent(parent)
{
}
    
AdhocCommandManager::~AdhocCommandManager()
{
}

void AdhocCommandManager::addCommand(AdhocCommand* command)
{
  m_adhoc->registerAdhocCommandProvider(this, command->getCode(), 
command->getLabel());
  m_commands[command->getCode()] = AdhocCommandPtr(command);
}
    
void AdhocCommandManager::handleAdhocCommand(const std::string& commandCode, 
gloox::Tag* tag, 
  const gloox::JID& from, const std::string& id)
{
  LOG_DEBUG("Handling command[" << commandCode << "]\n");
  std::string sessionid = tag->findAttribute("sessionid");
  const std::string& bareJid = from.bare();
  const std::string& fullJid = from.full();
  
  std::auto_ptr<gloox::Tag> childElement(new gloox::Tag("command"));
  childElement->addAttribute("xmlns", gloox::XMLNS_ADHOC_COMMANDS);
  childElement->addAttribute("sessionid", sessionid);
  childElement->addAttribute("node", commandCode);
  
  AdhocCommandPtr command = m_commands[commandCode];
  if (sessionid.empty()) {
    LOG_DEBUG("No previous session!\n");
    // Check that the requester has enough permission. Answer forbidden error if
    // requester permissions are not enough to execute the requested command
    if (!command->hasPermission(bareJid)) {
      LOG_DEBUG("No permissions[" << bareJid << "]\n");
      sendError(fullJid, commandCode, id, sessionid, "forbidden", "");
      return;
    } //if

    //Create new session ID
    sessionid = m_parent->getID();
    childElement->addAttribute("sessionid", sessionid);

    if (command->getMaxStages() == 0) {
      // The command does not require any user interaction (returns results 
only)
      // Execute the command and return the execution result which may be a
      // data form (i.e. report data) or a note element
      SessionData tmp;
      command->execute(tmp, childElement.get());
      
      childElement->addAttribute("status", "completed");
    } else {
      // The command requires user interactions (ie. has stages)
                    
      // Originate a new command session.
      SessionDataPtr session(new SessionData(sessionid, fullJid));
      m_sessions[sessionid] = session;
      
      childElement->addAttribute("status", "executing");

      // Add to the child element the data form the user must complete and
      // the allowed actions
      command->addNextStageInformation(*session, childElement.get());
    } //if
  } else {
    // An execution session already exists and the user has requested to 
perform a
    // certain action.
    std::string action = tag->findAttribute("action");
    // Check that a Session exists for the specified sessionID
    if (m_sessions.find(sessionid) == m_sessions.end()) {
      // Answer a bad_request error (bad-sessionid)
      sendError(fullJid, commandCode, id, sessionid, "bad-request", 
"bad-sessionid");
      return;
    } //if
     
    SessionDataPtr session = m_sessions[sessionid];

    // Check if the user is requesting to cancel the command
    if (action == "cancel") {
      // User requested to cancel command execution so remove the session data
      removeSessionData(sessionid);
      sendCanceled(fullJid, id, commandCode, sessionid);
      return;
    } //if

    // If the user didn't specify an action then follow the default execute 
action
    if (action.empty() || (action == "execute")) {
      action = session->getExecuteAction();
    }

    // Check that the specified action was previously offered
    if (!session->isValidAction(action)) {
      // Answer a bad_request error (bad-action)
      sendError(fullJid, commandCode, id, sessionid, "bad_request", 
"bad-action");
      return;
    } else if (action == "prev") {
      // Move to the previous stage and add to the child element the data form
      // the user must complete and the allowed actions of the previous stage
      childElement->addAttribute("status", "executing");
      command->addPreviousStageInformation(*session, childElement.get());
    } else if (action == "next") {
      // Store the completed form in the session data
      saveCompletedForm(tag, *session);
      // Move to the next stage and add to the child element the new data form
      // the user must complete and the new allowed actions
      childElement->addAttribute("status", "executing");
      command->addNextStageInformation(*session, childElement.get());
    } else if (action == "complete") {
      // Store the completed form in the session data
      saveCompletedForm(tag, *session);
      // Execute the command and return the execution result which may be a
      // data form (i.e. report data) or a note element
      command->execute(*session, childElement.get());
      childElement->addAttribute("status", "completed");

      // Command has been executed so remove the session data
      removeSessionData(sessionid);
    } //if
  } //if  
  
  //send the reply
  gloox::Tag* iq = XmppUtil::createIq("result", fullJid, 
m_parent->jid().full(), id);
  iq->addChild(childElement.release());
  
  m_parent->send(iq);
}  
  
void AdhocCommandManager::saveCompletedForm(gloox::Tag* iqCommand, SessionData& 
session)
{
  gloox::Tag* formElement = iqCommand->findChild("x", "xmlns", 
gloox::XMLNS_X_DATA);
  if (formElement != 0) {
    SessionData::DataFormPtr dataForm(new gloox::DataForm(formElement));
    // Store the variables and their values in the session data
    session.addStageForm(dataForm);
  } //if
}
    
void AdhocCommandManager::removeSessionData(const std::string& sessionid)
{
  m_sessions.erase(sessionid);
}

void AdhocCommandManager::sendError(const std::string& to, const std::string& 
cmd, 
  const std::string& id, const std::string& sessionId, const std::string& 
reason, 
  const std::string& specific) const
{
  gloox::Tag* iq = XmppUtil::createIq("error", to, m_parent->jid().full(), id);
  XmppUtil::createCmdNode(iq, cmd, "execute", sessionId);
  XmppUtil::createError(iq, "modify", "400", reason, specific);
  
  m_parent->send(iq);
}

void AdhocCommandManager::sendCanceled(const std::string& to, const 
std::string& id, 
  const std::string& command, const std::string& sessionid) const
{
  gloox::Tag* iq = XmppUtil::createIq("result", to, m_parent->jid().full(), id);
  XmppUtil::createCmdNode(iq, command, "canceled", sessionid);
  m_parent->send(iq);
}
#ifndef ADHOCCOMMANDMANAGER_H
#define ADHOCCOMMANDMANAGER_H

#include <map>
#include <string>

#include <boost/shared_ptr.hpp>

#include "gloox/adhoc.h"
#include "gloox/adhoccommandprovider.h"
#include "gloox/clientbase.h"
#include "gloox/tag.h"

#include "AdhocCommand.h"
/**
 * An AdHocCommandHandler is responsbile for providing discoverable information 
about the
 * supported commands and for handling commands requests. This is an 
implementation of JEP-50:
 * Ad-Hoc Commands.<p>
 *
 * Ad-hoc commands that require user interaction will have one or more stages. 
For each 
 * stage the user will complete a data form and send it back to the server. The 
data entered 
 * by the user is kept in a SessionData. Instances of {@link AdhocCommand} are 
stateless. 
 *
 * New commands can be added dynamically by sending the message {@link 
#addCommand(AdHocCommand)}.
 * The command will immediatelly appear in the disco#items list and might be 
executed by those
 * users with enough execution permissions.
 *
 * This implementation is taken from wild-/openfire
 * \see 
http://svn.igniterealtime.org/svn/repos/wildfire/trunk/src/java/org/jivesoftware/wildfire/commands/AdHocCommandHandler.java
 */
class AdhocCommandManager : public gloox::AdhocCommandProvider
{
  public:
    /**
     * Constructor
     * \param adhoc The adhoc command implementation
     * \param parent The client base to use for sending messages
     */
    AdhocCommandManager(gloox::Adhoc* adhoc, gloox::ClientBase* parent);
    /**
     * Destructor
     */
    ~AdhocCommandManager();
    /**
     * Adds a new command to the list of supported ad-hoc commands by this 
server. The new
     * command will appear in the discoverable items list and will be executed 
for those users
     * with enough permission.
     *
     * \param command the new ad-hoc command to add.
     */
    void addCommand(AdhocCommand* command);
    
    //gloox api callbacks AdhocCommandProvider
    virtual void handleAdhocCommand(const std::string& command, gloox::Tag* 
tag, 
      const gloox::JID& from, const std::string& id);
  private:
    /**
     * Auto delete gloox::Adhoc
     */
    std::auto_ptr<gloox::Adhoc> m_adhoc;
    /**
     * Client for sending messages
     */
    gloox::ClientBase* m_parent;
    /**
     * Type definition for adhoc command implementations
     */
    typedef boost::shared_ptr<AdhocCommand> AdhocCommandPtr;
    /**
     * Type definition for session data
     */
    typedef boost::shared_ptr<SessionData> SessionDataPtr;
    /**
     * Map that holds the offered commands by this service. Note: 
Key=commandCode, 
     * Value=command.
     * commandCode matches the node attribute sent by command requesters.
     */
    typedef std::map<std::string, AdhocCommandPtr> CommandMap;
    CommandMap m_commands;
    /**
     * Map that holds the command sessions. Used mainly to quickly locate a 
SessionData.
     * Note: Key=sessionID, Value=SessionData
     */
    typedef std::map<std::string, SessionDataPtr> SessionMap;
    SessionMap m_sessions;
    /**
     * Stores in the SessionData the fields and their values as specified in 
the completed
     * data form by the user.
     *
     * \param iqCommand the command element containing the data form element.
     * \param session the SessionData for this command execution.
     */
    void saveCompletedForm(gloox::Tag* iqCommand, SessionData& session);
    /**
     * Releases the data kept for the command execution whose id is sessionid. 
The number of
     * commands executions currently being executed by the user (full JID) will 
be decreased.
     *
     * \param sessionid id of the session that identifies this command 
execution.
     * \param from the full JID of the command requester.
     */
    void removeSessionData(const std::string& sessionid);
    /**
     * Send an IQ error to \c to
     * \param to The jid to which the error should be send
     * \param cmd The command name
     * \param id The original message id
     * \param sessionid The original session id
     * \param reason The stanza reason
     * \param specific The adhoc specific reason
     */  
    void sendError(const std::string& to, const std::string& cmd, const 
std::string& id, 
      const std::string& sessionId, const std::string& reason, 
      const std::string& specific) const;
    /**
     * If a recipient cancel command execution, send 'canceled' as confirmation
     * \param to The jid to which the confirmation should be send
     * \param id The original message id
     * \param command The command name
     * \param sessionid The original session id
     */    
    void sendCanceled(const std::string& to, const std::string& id, const 
std::string& command, 
      const std::string& sessionid) const;
};

#endif
#include "SessionData.h"

SessionData::SessionData(const std::string& sessionid, const gloox::JID& owner)
  : m_creationStamp(std::time(0)),
    m_id(sessionid),
    m_owner(owner),
    m_stagesData(),
    m_executeAction(),
    m_allowedActions(),
    m_stage(-1)
{
}

SessionData::SessionData()
  : m_creationStamp(0),
    m_id(),
    m_owner(),
    m_stagesData(),
    m_executeAction(),
    m_allowedActions(),
    m_stage(-1)
{
}

SessionData::~SessionData()
{
}

const std::string& SessionData::getId() const
{
  return m_id;
}

    
const gloox::JID& SessionData::getOwner() const
{
  return m_owner;
}

std::time_t SessionData::getCreationStamp() const
{
  return m_creationStamp;
}

const std::string& SessionData::getExecuteAction() const
{
  return m_executeAction;
}

void SessionData::setExecuteAction(const std::string& executeAction) 
{
  m_executeAction = executeAction;
}

void SessionData::setAllowedActions(const gloox::StringList& allowedActions) 
{
  m_allowedActions = allowedActions;
}

bool SessionData::isValidAction(const std::string& actionName) 
{
  gloox::StringList::const_iterator it = m_allowedActions.begin();
  for( ; it != m_allowedActions.end(); ++it) {
    if (*it == actionName)
      return true;
  } //for
  return false;
}

void SessionData::addStageForm(DataFormPtr& data) 
{
  m_stagesData[m_stage] = data;
}

SessionData::DataFormPtr& SessionData::getData(int stage)
{
  if ((stage < 0) || (stage > m_stage))
    return m_stagesData[m_stage];  
    
  return m_stagesData[stage];
}

int SessionData::getStage() const 
{
  return m_stage;
}

void SessionData::setStage(int stage) 
{
  m_stage = stage;
}
#ifndef SESSIONDATA_H
#define SESSIONDATA_H

#include <ctime>

#include <boost/shared_ptr.hpp>

#include <gloox/dataform.h>
#include <gloox/gloox.h>
#include <gloox/jid.h>

/**
 * A SessionData instance is responsible for keeping information gathered 
during the many stages
 * of the command being executed. Each session data is associated with the 
<tt>sessionid</tt>
 * attribute included in the <tt>command</tt> child element of the IQ packet.
 *
 * This implementation is taken from wild-/openfire
 * \see 
http://svn.igniterealtime.org/svn/repos/wildfire/trunk/src/java/org/jivesoftware/wildfire/commands/SessionData.java
 */
class SessionData 
{
  public:
    /**
     * Type definition to allow the sharing of data forms
     */
    typedef boost::shared_ptr<gloox::DataForm> DataFormPtr;
    /**
     * Constructor
     * \param sessionid The session's unique id
     * \param owner The owner of the session
     */
    SessionData(const std::string& sessionid, const gloox::JID& owner);
    /**
     * Dummy constructor.
     *
     * This is only used when contructing a temporary empty session
     */
    SessionData();
    /**
     * Destructor
     */
    ~SessionData();
    /**
     * \return The session id
     */
    const std::string& getId() const;
    /**
     * \return the JID of the entity that is executing the command.
     */
    const gloox::JID& getOwner() const;
    /**
     * \return The time when the session was created
     */
    std::time_t getCreationStamp() const;
    /**
     * \return The current stage's execute action
     */
    const std::string& getExecuteAction() const;
    /**
     * Set the current execute action
     * \param executeAction The execute action
     */
    void setExecuteAction(const std::string& executeAction);
    /**
     * Sets the valid actions that the user can follow from the current stage.
     *
     * \param allowedActions list of valid actions.
     */
    void setAllowedActions(const gloox::StringList& allowedActions);
    /**
     * Returns true if the specified action is valid in the current stage. The 
action should 
     * have previously been offered to the user.
     *
     * \param actionName the name of the action to validate.
     * \return true if the specified action is valid in the current stage.
     */
    bool isValidAction(const std::string& actionName);
    /**
     * Add the data form for the current stage
     * \param data The stage's data form
     */
    void addStageForm(DataFormPtr& data);
    /**
     * Return the data form for the specified stage. Call the method with no 
parameter, or
     * pass -1, to retrieve the current stage's data.
     * \param stage The stage in which data you are interested
     * @return The data form
     */
    DataFormPtr& getData(int stage = -1);
    /**
     * Returns the current stage where the requester is located. Stages are 
numbered from 0. A
     * stage with value 0 means that a command request has just been received 
and no data form
     * has been sent to the requester yet. The first sent data form of the 
first stage would be
     * represented as stage 1.
     *
     * @return the current stage where the requester is located.
     */
    int getStage() const;
    /**
     * Sets the current stage where the requester is located. Stages are 
numbered from 0. A
     * stage with value 0 means that a command request has just been received 
and no data form
     * has been sent to the requester yet. The first sent data form of the 
first stage would be
     * represented as stage 1.
     *
     * @param stage the current stage where the requester is located.
     */
    void setStage(int stage);
  private:
    /**
     * Time of session creation
     */
    std::time_t m_creationStamp;
    /**
     * Session's id
     */
    std::string m_id;
    /**
     * Owner of session
     */
    gloox::JID m_owner;
    /**
     * Map that keeps the association of variables and values obtained in each 
stage.
     * Note: Key=stage number, Value=DataForm.
     */
    typedef std::map<int, DataFormPtr> StagesData;
    StagesData m_stagesData;
    /**
     * Keeps the default execution action to follow if the command requester 
does not include
     * an action in his command.
     */
    std::string m_executeAction;
    /**
     * List of allowed actions
     */
    gloox::StringList m_allowedActions;;
    /**
     * Indicates the current stage where the requester is located. Stages are 
numbered from 0.
     */
    int m_stage;    
};

#endif