00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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& )
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 }