adhoc.cpp

00001 /*
00002   Copyright (c) 2004-2007 by Jakob Schroeter <js@camaya.net>
00003   This file is part of the gloox library. http://camaya.net/gloox
00004 
00005   This software is distributed under a license. The full license
00006   agreement can be found in the file LICENSE in this distribution.
00007   This software may not be copied, modified, sold or distributed
00008   other than expressed in the named license agreement.
00009 
00010   This software is distributed without any warranty.
00011 */
00012 
00013 
00014 #include "adhoc.h"
00015 #include "adhochandler.h"
00016 #include "adhoccommandprovider.h"
00017 #include "disco.h"
00018 #include "discohandler.h"
00019 #include "client.h"
00020 #include "dataform.h"
00021 
00022 
00023 namespace gloox
00024 {
00025 
00026   Adhoc::Adhoc( ClientBase *parent )
00027     : m_parent( parent )
00028   {
00029     if( m_parent )
00030     {
00031       m_parent->registerIqHandler( this, XMLNS_ADHOC_COMMANDS );
00032       m_parent->disco()->addFeature( XMLNS_ADHOC_COMMANDS );
00033       m_parent->disco()->registerNodeHandler( this, XMLNS_ADHOC_COMMANDS );
00034       m_parent->disco()->registerNodeHandler( this, std::string() );
00035     }
00036   }
00037 
00038   Adhoc::~Adhoc()
00039   {
00040     if( m_parent )
00041     {
00042       m_parent->disco()->removeFeature( XMLNS_ADHOC_COMMANDS );
00043       m_parent->disco()->removeNodeHandler( this, XMLNS_ADHOC_COMMANDS );
00044       m_parent->disco()->removeNodeHandler( this, std::string() );
00045       m_parent->removeIqHandler( XMLNS_ADHOC_COMMANDS );
00046     }
00047   }
00048 
00049   StringList Adhoc::handleDiscoNodeFeatures( const std::string& /*node*/ )
00050   {
00051     StringList features;
00052     features.push_back( XMLNS_ADHOC_COMMANDS );
00053     return features;
00054   }
00055 
00056   DiscoNodeItemList Adhoc::handleDiscoNodeItems( const std::string& node )
00057   {
00058     DiscoNodeItemList l;
00059     if( node.empty() )
00060     {
00061       DiscoNodeItem item;
00062       item.node = XMLNS_ADHOC_COMMANDS;
00063       item.jid = m_parent->jid().full();
00064       item.name = "Ad-Hoc Commands";
00065       l.push_back( item );
00066     }
00067     else if( node == XMLNS_ADHOC_COMMANDS )
00068     {
00069       StringMap::const_iterator it = m_items.begin();
00070       for( ; it != m_items.end(); ++it )
00071       {
00072         DiscoNodeItem item;
00073         item.node = (*it).first;
00074         item.jid = m_parent->jid().full();
00075         item.name = (*it).second;
00076         l.push_back( item );
00077       }
00078     }
00079     return l;
00080   }
00081 
00082   StringMap Adhoc::handleDiscoNodeIdentities( const std::string& node, std::string& name )
00083   {
00084     StringMap::const_iterator it = m_items.find( node );
00085     if( it != m_items.end() )
00086       name = (*it).second;
00087     else
00088       name = "Ad-Hoc Commands";
00089 
00090     StringMap ident;
00091     if( node == XMLNS_ADHOC_COMMANDS )
00092       ident["automation"] = "command-list";
00093     else
00094       ident["automation"] = "command-node";
00095     return ident;
00096   }
00097 
00098   bool Adhoc::handleIq( Stanza *stanza )
00099   {
00100     if( stanza->subtype() != StanzaIqSet )
00101       return false;
00102 
00103     if( stanza->hasChild( "command" ) )
00104     {
00105       Tag *c = stanza->findChild( "command" );
00106       const std::string& node = c->findAttribute( "node" );
00107       AdhocCommandProviderMap::const_iterator it = m_adhocCommandProviders.find( node );
00108       if( !node.empty() && ( it != m_adhocCommandProviders.end() ) )
00109       {
00110         (*it).second->handleAdhocCommand( node, c, stanza->from(), stanza->id() );
00111         return true;
00112       }
00113     }
00114 
00115     return false;
00116   }
00117 
00118   bool Adhoc::handleIqID( Stanza * stanza, int context )
00119   {
00120     if( context != ExecuteAdhocCommand || stanza->subtype() != StanzaIqResult )
00121       return false;
00122 
00123     AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
00124     for( ; it != m_adhocTrackMap.end(); ++it )
00125     {
00126       if( (*it).second.context == context && (*it).second.remote == stanza->from() )
00127       {
00128         Tag *c = stanza->findChild( "command", "xmlns", XMLNS_ADHOC_COMMANDS );
00129         if( c )
00130         {
00131           const std::string& command = c->findAttribute( "node" );
00132           const std::string& id = c->findAttribute( "sessionid" );
00133           Tag *a = c->findChild( "actions" );
00134           int actions = ActionCancel;
00135           Adhoc::AdhocExecuteActions def = ActionCancel;
00136           if( a )
00137           {
00138             if( a->hasChild( "prev" ) )
00139               actions |= ActionPrevious;
00140             if( a->hasChild( "next" ) )
00141               actions |= ActionNext;
00142             if( a->hasChild( "complete" ) )
00143               actions |= ActionComplete;
00144             const std::string& d = a->findAttribute( "execute" );
00145             if( d == "next" )
00146               def = ActionNext;
00147             else if( d == "prev" )
00148               def = ActionPrevious;
00149             else if( d == "complete" )
00150               def = ActionComplete;
00151           }
00152           Tag *n = c->findChild( "note" );
00153           std::string note;
00154           AdhocNoteType type = AdhocNoteInfo;
00155           if( n )
00156           {
00157             note = n->cdata();
00158             if( n->hasAttribute( "type", "warn" ) )
00159               type = AdhocNoteWarn;
00160             else if( n->hasAttribute( "type", "error" ) )
00161               type = AdhocNoteError;
00162           }
00163           const std::string& s = c->findAttribute( "status" );
00164           AdhocCommandStatus status = AdhocCommandStatusUnknown;
00165           if( s == "executing" )
00166             status = AdhocCommandExecuting;
00167           else if( s == "completed" )
00168             status = AdhocCommandCompleted;
00169           else if( s == "canceled" )
00170             status = AdhocCommandCanceled;
00171           DataForm form;
00172           Tag *x = c->findChild( "x", "xmlns", XMLNS_X_DATA );
00173           if( x )
00174             form.parse( x );
00175 
00176           (*it).second.ah->handleAdhocExecutionResult( stanza->from(), command, status, id, form,
00177                                                        actions, def, note, type );
00178         }
00179 
00180         m_adhocTrackMap.erase( it );
00181         return true;
00182       }
00183     }
00184 
00185     return false;
00186   }
00187 
00188   void Adhoc::registerAdhocCommandProvider( AdhocCommandProvider *acp, const std::string& command,
00189                                             const std::string& name )
00190   {
00191     m_parent->disco()->registerNodeHandler( this, command );
00192     m_adhocCommandProviders[command] = acp;
00193     m_items[command] = name;
00194   }
00195 
00196   void Adhoc::handleDiscoInfoResult( Stanza *stanza, int context )
00197   {
00198     if( context != CheckAdhocSupport )
00199       return;
00200 
00201     AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
00202     for( ; it != m_adhocTrackMap.end(); ++it )
00203     {
00204       if( (*it).second.context == context && (*it).second.remote == stanza->from() )
00205       {
00206         Tag *q = stanza->findChild( "query", "xmlns", XMLNS_DISCO_INFO );
00207         if( q )
00208           (*it).second.ah->handleAdhocSupport( (*it).second.remote,
00209                   q->hasChild( "feature", "var", XMLNS_ADHOC_COMMANDS ) );
00210         m_adhocTrackMap.erase( it );
00211         break;
00212       }
00213     }
00214   }
00215 
00216   void Adhoc::handleDiscoItemsResult( Stanza *stanza, int context )
00217   {
00218     if( context != FetchAdhocCommands )
00219       return;
00220 
00221     AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
00222     for( ; it != m_adhocTrackMap.end(); ++it )
00223     {
00224       if( (*it).second.context == context && (*it).second.remote == stanza->from() )
00225       {
00226         Tag *q = stanza->findChild( "query", "xmlns", XMLNS_DISCO_ITEMS );
00227         if( q )
00228         {
00229           StringMap commands;
00230           const Tag::TagList& l = q->children();
00231           Tag::TagList::const_iterator itt = l.begin();
00232           for( ; itt != l.end(); ++itt )
00233           {
00234             const std::string& name = (*itt)->findAttribute( "name" );
00235             const std::string& node = (*itt)->findAttribute( "node" );
00236             if( (*itt)->name() == "item" && !name.empty() && !node.empty() )
00237             {
00238               commands[node] = name;
00239             }
00240           }
00241           (*it).second.ah->handleAdhocCommands( (*it).second.remote, commands );
00242         }
00243 
00244         m_adhocTrackMap.erase( it );
00245         break;
00246       }
00247     }
00248   }
00249 
00250   void Adhoc::handleDiscoError( Stanza *stanza, int context )
00251   {
00252     AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
00253     for( ; it != m_adhocTrackMap.end(); ++it )
00254     {
00255       if( (*it).second.context == context && (*it).second.remote == stanza->from() )
00256       {
00257         (*it).second.ah->handleAdhocError( (*it).second.remote, stanza->error() );
00258 
00259         m_adhocTrackMap.erase( it );
00260       }
00261     }
00262   }
00263 
00264   void Adhoc::checkSupport( const JID& remote, AdhocHandler *ah )
00265   {
00266     if( !remote || !ah )
00267       return;
00268 
00269     TrackStruct track;
00270     track.remote = remote;
00271     track.context = CheckAdhocSupport;
00272     track.ah = ah;
00273     m_adhocTrackMap[m_parent->getID()] = track;
00274     m_parent->disco()->getDiscoInfo( remote, "", this, CheckAdhocSupport );
00275   }
00276 
00277   void Adhoc::getCommands( const JID& remote, AdhocHandler *ah )
00278   {
00279     if( !remote || !ah )
00280       return;
00281 
00282     TrackStruct track;
00283     track.remote = remote;
00284     track.context = FetchAdhocCommands;
00285     track.ah = ah;
00286     m_adhocTrackMap[m_parent->getID()] = track;
00287     m_parent->disco()->getDiscoItems( remote, XMLNS_ADHOC_COMMANDS, this, FetchAdhocCommands );
00288   }
00289 
00290   void Adhoc::execute( const JID& remote, const std::string& command, AdhocHandler *ah,
00291                        const std::string& sessionid, DataForm *form,
00292                        AdhocExecuteActions action )
00293   {
00294     if( !remote || command.empty() || !ah )
00295       return;
00296 
00297     const std::string& id = m_parent->getID();
00298     Tag *iq = new Tag( "iq" );
00299     iq->addAttribute( "type", "set" );
00300     iq->addAttribute( "to", remote.full() );
00301     iq->addAttribute( "id", id );
00302     Tag *c = new Tag( iq, "command" );
00303     c->addAttribute( "xmlns", XMLNS_ADHOC_COMMANDS );
00304     c->addAttribute( "node", command );
00305     c->addAttribute( "action", "execute" );
00306     if( !sessionid.empty() )
00307       c->addAttribute( "sessionid", sessionid );
00308     if( action != ActionDefault )
00309     {
00310       switch( action )
00311       {
00312         case ActionPrevious:
00313           c->addAttribute( "action", "prev" );
00314           break;
00315         case ActionNext:
00316           c->addAttribute( "action", "next" );
00317           break;
00318         case ActionCancel:
00319           c->addAttribute( "action", "cancel" );
00320           break;
00321         case ActionComplete:
00322           c->addAttribute( "action", "complete" );
00323           break;
00324         default:
00325           break;
00326       }
00327     }
00328     if( form )
00329       c->addChild( form->tag() );
00330 
00331     TrackStruct track;
00332     track.remote = remote;
00333     track.context = ExecuteAdhocCommand;
00334     track.ah = ah;
00335     m_adhocTrackMap[id] = track;
00336 
00337     m_parent->trackID( this, id, ExecuteAdhocCommand );
00338     m_parent->send( iq );
00339   }
00340 
00341   void Adhoc::removeAdhocCommandProvider( const std::string& command )
00342   {
00343     m_parent->disco()->removeNodeHandler( this, command );
00344     m_adhocCommandProviders.erase( command );
00345     m_items.erase( command );
00346   }
00347 
00348 }

Generated on Sat Nov 10 08:50:26 2007 for gloox by  doxygen 1.5.3-20071008