adhoc.cpp

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

Generated on Sun Apr 27 11:08:13 2008 for gloox by  doxygen 1.5.5