Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

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 "error.h"
00019 #include "discohandler.h"
00020 #include "clientbase.h"
00021 #include "dataform.h"
00022 #include "util.h"
00023 
00024 namespace gloox
00025 {
00026 
00027   static const char* cmdActionStringValues[] =
00028   {
00029     "execute", "cancel", "prev", "next", "complete"
00030   };
00031 
00032   static inline const std::string actionString( Adhoc::Command::Action action )
00033   {
00034     return util::lookup2( action, cmdActionStringValues );
00035   }
00036 
00037   static const char* cmdStatusStringValues[] =
00038   {
00039     "executing", "completed", "canceled"
00040   };
00041 
00042   static inline const std::string statusString( Adhoc::Command::Status status )
00043   {
00044     return util::lookup( status, cmdStatusStringValues );
00045   }
00046 
00047   static const char* cmdNoteStringValues[] =
00048   {
00049     "info", "warn", "error"
00050   };
00051 
00052   static inline const std::string noteString( Adhoc::Command::Note::Severity sev )
00053   {
00054     return util::lookup( sev, cmdNoteStringValues );
00055   }
00056 
00057   // ---- Adhoc::Command::Note ----
00058   Adhoc::Command::Note::Note( const Tag* tag )
00059     : m_severity( InvalidSeverity )
00060   {
00061     if( !tag || tag->name() != "note" )
00062       return;
00063 
00064     m_severity = (Severity)util::deflookup( tag->findAttribute( "type" ), cmdNoteStringValues, Info );
00065     m_note = tag->cdata();
00066   }
00067 
00068   Tag* Adhoc::Command::Note::tag() const
00069   {
00070     if( m_note.empty() || m_severity == InvalidSeverity )
00071       return 0;
00072 
00073     Tag* n = new Tag( "note", m_note );
00074     n->addAttribute( TYPE, noteString( m_severity ) );
00075     return n;
00076   }
00077   // ---- ~Adhoc::Command::Note ----
00078 
00079   // ---- Adhoc::Command ----
00080   Adhoc::Command::Command( const std::string& node, Adhoc::Command::Action action )
00081     : StanzaExtension( ExtAdhocCommand ), m_node( node ), m_form( 0 ), m_action( action ),
00082       m_status( InvalidStatus ), m_actions( 0 )
00083   {
00084   }
00085 
00086   Adhoc::Command::Command( const std::string& node, const std::string& sessionid, Status status,
00087                            DataForm* form )
00088   : StanzaExtension( ExtAdhocCommand ), m_node( node ), m_sessionid( sessionid ),
00089     m_form( form ), m_action( InvalidAction ), m_status( status ), m_actions( 0 )
00090   {
00091   }
00092 
00093   Adhoc::Command::Command( const std::string& node, const std::string& sessionid,
00094                            Adhoc::Command::Action action )
00095     : StanzaExtension( ExtAdhocCommand ), m_node( node ), m_sessionid( sessionid ),
00096       m_form( 0 ), m_action( action ), m_actions( 0 )
00097   {
00098   }
00099 
00100   Adhoc::Command::Command( const Tag* tag )
00101     : StanzaExtension( ExtAdhocCommand ), m_form( 0 ), m_actions( 0 )
00102   {
00103     if( !tag || tag->name() != "command" || tag->xmlns() != XMLNS_ADHOC_COMMANDS )
00104       return;
00105 
00106     m_node = tag->findAttribute( "node" );
00107     m_sessionid = tag->findAttribute( "sessionid" );
00108     m_action = (Action)util::deflookup2( tag->findAttribute( "action" ), cmdActionStringValues, Execute );
00109     m_status = (Status)util::lookup( tag->findAttribute( "status" ), cmdStatusStringValues );
00110 
00111     Tag* a = tag->findChild( "actions" );
00112     if( a )
00113     {
00114       if( a->hasChild( "prev" ) )
00115         m_actions |= Previous;
00116       if( a->hasChild( "next" ) )
00117         m_actions |= Next;
00118       if( a->hasChild( "complete" ) )
00119         m_actions |= Complete;
00120     }
00121 
00122     const ConstTagList& l = tag->findTagList( "/command/note" );
00123     ConstTagList::const_iterator it = l.begin();
00124     for( ; it != l.end(); ++it )
00125       m_notes.push_back( new Note( (*it) ) );
00126 
00127     Tag* x = tag->findChild( "x", "xmlns", XMLNS_X_DATA );
00128     if( x )
00129       m_form = new DataForm( x );
00130   }
00131 
00132   Adhoc::Command::~Command()
00133   {
00134     util::clearList( m_notes );
00135     delete m_form;
00136   }
00137 
00138   const std::string& Adhoc::Command::filterString() const
00139   {
00140     static const std::string filter = "/iq/command[@xmlns='" + XMLNS_ADHOC_COMMANDS + "']";
00141     return filter;
00142   }
00143 
00144   Tag* Adhoc::Command::tag() const
00145   {
00146     if( m_node.empty() )
00147       return 0;
00148 
00149     Tag* c = new Tag( "command" );
00150     c->setXmlns( XMLNS_ADHOC_COMMANDS );
00151     c->addAttribute( "node", m_node );
00152     if( m_action != InvalidAction )
00153       c->addAttribute( "action", actionString( m_action ) );
00154     if( m_status != InvalidStatus )
00155       c->addAttribute( "status", statusString( m_status ) );
00156     if ( !m_sessionid.empty() )
00157       c->addAttribute( "sessionid", m_sessionid );
00158 
00159     if( m_form && *m_form )
00160       c->addChild( m_form->tag() );
00161 
00162     NoteList::const_iterator it = m_notes.begin();
00163     for( ; it != m_notes.end(); ++it )
00164       c->addChild( (*it)->tag() );
00165 
00166     return c;
00167   }
00168   // ---- ~Adhoc::Command ----
00169 
00170   // ---- Adhoc ----
00171   Adhoc::Adhoc( ClientBase* parent )
00172     : m_parent( parent )
00173   {
00174     if( !m_parent || !m_parent->disco() )
00175       return;
00176 
00177     m_parent->disco()->addFeature( XMLNS_ADHOC_COMMANDS );
00178     m_parent->disco()->registerNodeHandler( this, XMLNS_ADHOC_COMMANDS );
00179     m_parent->disco()->registerNodeHandler( this, EmptyString );
00180     m_parent->registerIqHandler( this, ExtAdhocCommand );
00181     m_parent->registerStanzaExtension( new Adhoc::Command() );
00182   }
00183 
00184   Adhoc::~Adhoc()
00185   {
00186     if( !m_parent || !m_parent->disco() )
00187       return;
00188 
00189     m_parent->disco()->removeFeature( XMLNS_ADHOC_COMMANDS );
00190     m_parent->disco()->removeNodeHandler( this, XMLNS_ADHOC_COMMANDS );
00191     m_parent->disco()->removeNodeHandler( this, EmptyString );
00192     m_parent->removeIqHandler( this, ExtAdhocCommand );
00193     m_parent->removeIDHandler( this );
00194     m_parent->removeStanzaExtension( ExtAdhocCommand );
00195   }
00196 
00197   StringList Adhoc::handleDiscoNodeFeatures( const JID& /*from*/, const std::string& /*node*/ )
00198   {
00199     StringList features;
00200     features.push_back( XMLNS_ADHOC_COMMANDS );
00201     return features;
00202 //    return StringList( 1, XMLNS_ADHOC_COMMANDS );
00203   }
00204 
00205   Disco::ItemList Adhoc::handleDiscoNodeItems( const JID& /*from*/, const std::string& node )
00206   {
00207     Disco::ItemList l;
00208     if( node.empty() )
00209     {
00210       l.push_back( new Disco::Item( m_parent->jid(), XMLNS_ADHOC_COMMANDS, "Ad-Hoc Commands" ) );
00211     }
00212     else if( node == XMLNS_ADHOC_COMMANDS )
00213     {
00214       StringMap::const_iterator it = m_items.begin();
00215       for( ; it != m_items.end(); ++it )
00216       {
00217         l.push_back( new Disco::Item( m_parent->jid(), (*it).first, (*it).second ) );
00218       }
00219     }
00220     return l;
00221   }
00222 
00223   Disco::IdentityList Adhoc::handleDiscoNodeIdentities( const JID& /*from*/, const std::string& node )
00224   {
00225     Disco::IdentityList l;
00226     StringMap::const_iterator it = m_items.find( node );
00227     l.push_back( new Disco::Identity( "automation",
00228                                node == XMLNS_ADHOC_COMMANDS ? "command-list" : "command-node",
00229                                it == m_items.end() ? "Ad-Hoc Commands" : (*it).second ) );
00230     return l;
00231   }
00232 
00233   bool Adhoc::handleIq( const IQ& iq )
00234   {
00235     if( iq.subtype() != IQ::Set )
00236       return false;
00237 
00238     const Adhoc::Command* ac = iq.findExtension<Adhoc::Command>( ExtAdhocCommand );
00239     if( !ac || ac->node().empty())
00240       return false;
00241 
00242     AdhocCommandProviderMap::const_iterator it = m_adhocCommandProviders.find( ac->node() );
00243     if( it != m_adhocCommandProviders.end() )
00244     {
00245       const std::string& sess = ac->sessionID().empty() ? m_parent->getID() : ac->sessionID();
00246       m_activeSessions[sess] = iq.id();
00247       (*it).second->handleAdhocCommand( iq.from(), *ac, sess );
00248       return true;
00249     }
00250 
00251     return false;
00252   }
00253 
00254   void Adhoc::handleIqID( const IQ& iq, int context )
00255   {
00256     if( context != ExecuteAdhocCommand )
00257       return;
00258 
00259     AdhocTrackMap::iterator it = m_adhocTrackMap.find( iq.id() );
00260     if( it == m_adhocTrackMap.end() || (*it).second.context != context
00261         || (*it).second.remote != iq.from() )
00262       return;
00263 
00264     switch( iq.subtype() )
00265     {
00266       case IQ::Error:
00267         (*it).second.ah->handleAdhocError( iq.from(), iq.error() );
00268         break;
00269       case IQ::Result:
00270       {
00271         const Adhoc::Command* ac = iq.findExtension<Adhoc::Command>( ExtAdhocCommand );
00272         if( ac )
00273           (*it).second.ah->handleAdhocExecutionResult( iq.from(), *ac );
00274         break;
00275       }
00276       default:
00277         break;
00278     }
00279     m_adhocTrackMap.erase( it );
00280   }
00281 
00282   void Adhoc::registerAdhocCommandProvider( AdhocCommandProvider* acp, const std::string& command,
00283                                             const std::string& name )
00284   {
00285     if( !m_parent || !m_parent->disco() )
00286       return;
00287 
00288     m_parent->disco()->registerNodeHandler( this, command );
00289     m_adhocCommandProviders[command] = acp;
00290     m_items[command] = name;
00291   }
00292 
00293   void Adhoc::handleDiscoInfo( const JID& from, const Disco::Info& info, int context )
00294   {
00295     if( context != CheckAdhocSupport )
00296       return;
00297 
00298     AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
00299     for( ; it != m_adhocTrackMap.end() && (*it).second.context != context
00300                                        && (*it).second.remote  != from; ++it )
00301       ;
00302     if( it == m_adhocTrackMap.end() )
00303       return;
00304 
00305     (*it).second.ah->handleAdhocSupport( from, info.hasFeature( XMLNS_ADHOC_COMMANDS ) );
00306     m_adhocTrackMap.erase( it );
00307   }
00308 
00309   void Adhoc::handleDiscoItems( const JID& from, const Disco::Items& items, int context )
00310   {
00311     if( context != FetchAdhocCommands )
00312       return;
00313 
00314     AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
00315     for( ; it != m_adhocTrackMap.end(); ++it )
00316     {
00317       if( (*it).second.context == context && (*it).second.remote == from )
00318       {
00319         StringMap commands;
00320         const Disco::ItemList& l = items.items();
00321         Disco::ItemList::const_iterator it2 = l.begin();
00322         for( ; it2 != l.end(); ++it2 )
00323         {
00324           commands[(*it2)->node()] = (*it2)->name();
00325         }
00326         (*it).second.ah->handleAdhocCommands( from, commands );
00327 
00328         m_adhocTrackMap.erase( it );
00329         break;
00330       }
00331     }
00332   }
00333 
00334   void Adhoc::handleDiscoError( const JID& from, const Error* error, int context )
00335   {
00336     AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
00337     for( ; it != m_adhocTrackMap.end(); ++it )
00338     {
00339       if( (*it).second.context == context && (*it).second.remote == from )
00340       {
00341         (*it).second.ah->handleAdhocError( from, error );
00342 
00343         m_adhocTrackMap.erase( it );
00344       }
00345     }
00346   }
00347 
00348   void Adhoc::checkSupport( const JID& remote, AdhocHandler* ah )
00349   {
00350     if( !remote || !ah || !m_parent || !m_parent->disco() )
00351       return;
00352 
00353     TrackStruct track;
00354     track.remote = remote;
00355     track.context = CheckAdhocSupport;
00356     track.ah = ah;
00357     const std::string& id = m_parent->getID();
00358     m_adhocTrackMap[id] = track;
00359     m_parent->disco()->getDiscoInfo( remote, EmptyString, this, CheckAdhocSupport, id );
00360   }
00361 
00362   void Adhoc::getCommands( const JID& remote, AdhocHandler* ah )
00363   {
00364     if( !remote || !ah || !m_parent || !m_parent->disco() )
00365       return;
00366 
00367     TrackStruct track;
00368     track.remote = remote;
00369     track.context = FetchAdhocCommands;
00370     track.ah = ah;
00371     const std::string& id = m_parent->getID();
00372     m_adhocTrackMap[id] = track;
00373     m_parent->disco()->getDiscoItems( remote, XMLNS_ADHOC_COMMANDS, this, FetchAdhocCommands, id );
00374   }
00375 
00376   void Adhoc::execute( const JID& remote, const Adhoc::Command* command, AdhocHandler* ah )
00377   {
00378     if( !remote || !command || !m_parent || !ah )
00379       return;
00380 
00381     const std::string& id = m_parent->getID();
00382     IQ iq( IQ::Set, remote, id );
00383     iq.addExtension( command );
00384 
00385     TrackStruct track;
00386     track.remote = remote;
00387     track.context = ExecuteAdhocCommand;
00388     track.session = command->sessionID();
00389     track.ah = ah;
00390     m_adhocTrackMap[id] = track;
00391 
00392     m_parent->send( iq, this, ExecuteAdhocCommand );
00393   }
00394 
00395   void Adhoc::respond( const JID& remote, const Adhoc::Command* command, const Error* error )
00396   {
00397     if( !remote || !command || !m_parent )
00398       return;
00399 
00400     StringMap::iterator it = m_activeSessions.find( command->sessionID() );
00401     if( it == m_activeSessions.end() )
00402       return;
00403 
00404     IQ re( error ? IQ::Error : IQ::Result, remote, (*it).second );
00405     re.addExtension( command );
00406     if( error )
00407       re.addExtension( error );
00408     m_parent->send( re );
00409     m_activeSessions.erase( it );
00410   }
00411 
00412   void Adhoc::removeAdhocCommandProvider( const std::string& command )
00413   {
00414     if( !m_parent || !m_parent->disco() )
00415       return;
00416 
00417     m_parent->disco()->removeNodeHandler( this, command );
00418     m_adhocCommandProviders.erase( command );
00419     m_items.erase( command );
00420   }
00421 
00422 }

Generated on Sun Dec 28 22:10:15 2008 for gloox by  doxygen 1.4.1