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 }
00047 }
00048
00049 StringList Adhoc::handleDiscoNodeFeatures( const std::string& )
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 }