gloox  0.9.9.12
adhoc.cpp
1 /*
2  Copyright (c) 2004-2008 by Jakob Schroeter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 
14 #include "adhoc.h"
15 #include "adhochandler.h"
16 #include "adhoccommandprovider.h"
17 #include "disco.h"
18 #include "discohandler.h"
19 #include "client.h"
20 #include "dataform.h"
21 
22 
23 namespace gloox
24 {
25 
27  : m_parent( parent )
28  {
29  if( m_parent )
30  {
31  m_parent->registerIqHandler( this, XMLNS_ADHOC_COMMANDS );
32  m_parent->disco()->addFeature( XMLNS_ADHOC_COMMANDS );
33  m_parent->disco()->registerNodeHandler( this, XMLNS_ADHOC_COMMANDS );
34  m_parent->disco()->registerNodeHandler( this, std::string() );
35  }
36  }
37 
39  {
40  if( m_parent )
41  {
43  m_parent->disco()->removeNodeHandler( this, XMLNS_ADHOC_COMMANDS );
44  m_parent->disco()->removeNodeHandler( this, std::string() );
46  m_parent->removeIDHandler( this );
47  }
48  }
49 
50  StringList Adhoc::handleDiscoNodeFeatures( const std::string& /*node*/ )
51  {
52  StringList features;
53  features.push_back( XMLNS_ADHOC_COMMANDS );
54  return features;
55  }
56 
58  {
60  if( node.empty() )
61  {
62  DiscoNodeItem item;
64  item.jid = m_parent->jid().full();
65  item.name = "Ad-Hoc Commands";
66  l.push_back( item );
67  }
68  else if( node == XMLNS_ADHOC_COMMANDS )
69  {
70  StringMap::const_iterator it = m_items.begin();
71  for( ; it != m_items.end(); ++it )
72  {
73  DiscoNodeItem item;
74  item.node = (*it).first;
75  item.jid = m_parent->jid().full();
76  item.name = (*it).second;
77  l.push_back( item );
78  }
79  }
80  return l;
81  }
82 
83  StringMap Adhoc::handleDiscoNodeIdentities( const std::string& node, std::string& name )
84  {
85  StringMap::const_iterator it = m_items.find( node );
86  if( it != m_items.end() )
87  name = (*it).second;
88  else
89  name = "Ad-Hoc Commands";
90 
91  StringMap ident;
92  if( node == XMLNS_ADHOC_COMMANDS )
93  ident["automation"] = "command-list";
94  else
95  ident["automation"] = "command-node";
96  return ident;
97  }
98 
99  bool Adhoc::handleIq( Stanza *stanza )
100  {
101  if( stanza->subtype() != StanzaIqSet )
102  return false;
103 
104  if( stanza->hasChild( "command" ) )
105  {
106  Tag *c = stanza->findChild( "command" );
107  const std::string& node = c->findAttribute( "node" );
108  AdhocCommandProviderMap::const_iterator it = m_adhocCommandProviders.find( node );
109  if( !node.empty() && ( it != m_adhocCommandProviders.end() ) )
110  {
111  (*it).second->handleAdhocCommand( node, c, stanza->from(), stanza->id() );
112  return true;
113  }
114  }
115 
116  return false;
117  }
118 
119  bool Adhoc::handleIqID( Stanza * stanza, int context )
120  {
121  if( context != ExecuteAdhocCommand || stanza->subtype() != StanzaIqResult )
122  return false;
123 
124  AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
125  for( ; it != m_adhocTrackMap.end(); ++it )
126  {
127  if( (*it).second.context == context && (*it).second.remote == stanza->from() )
128  {
129  Tag *c = stanza->findChild( "command", "xmlns", XMLNS_ADHOC_COMMANDS );
130  if( c )
131  {
132  const std::string& command = c->findAttribute( "node" );
133  const std::string& id = c->findAttribute( "sessionid" );
134  Tag *a = c->findChild( "actions" );
135  int actions = ActionCancel;
137  if( a )
138  {
139  if( a->hasChild( "prev" ) )
140  actions |= ActionPrevious;
141  if( a->hasChild( "next" ) )
142  actions |= ActionNext;
143  if( a->hasChild( "complete" ) )
144  actions |= ActionComplete;
145  const std::string& d = a->findAttribute( "execute" );
146  if( d == "next" )
147  def = ActionNext;
148  else if( d == "prev" )
149  def = ActionPrevious;
150  else if( d == "complete" )
151  def = ActionComplete;
152  }
153  Tag *n = c->findChild( "note" );
154  std::string note;
156  if( n )
157  {
158  note = n->cdata();
159  if( n->hasAttribute( "type", "warn" ) )
160  type = AdhocNoteWarn;
161  else if( n->hasAttribute( "type", "error" ) )
162  type = AdhocNoteError;
163  }
164  const std::string& s = c->findAttribute( "status" );
166  if( s == "executing" )
167  status = AdhocCommandExecuting;
168  else if( s == "completed" )
169  status = AdhocCommandCompleted;
170  else if( s == "canceled" )
171  status = AdhocCommandCanceled;
172  DataForm form;
173  Tag *x = c->findChild( "x", "xmlns", XMLNS_X_DATA );
174  if( x )
175  form.parse( x );
176 
177  (*it).second.ah->handleAdhocExecutionResult( stanza->from(), command, status, id, form,
178  actions, def, note, type );
179  }
180 
181  m_adhocTrackMap.erase( it );
182  return true;
183  }
184  }
185 
186  return false;
187  }
188 
189  void Adhoc::registerAdhocCommandProvider( AdhocCommandProvider *acp, const std::string& command,
190  const std::string& name )
191  {
192  m_parent->disco()->registerNodeHandler( this, command );
193  m_adhocCommandProviders[command] = acp;
194  m_items[command] = name;
195  }
196 
197  void Adhoc::handleDiscoInfoResult( Stanza *stanza, int context )
198  {
199  if( context != CheckAdhocSupport )
200  return;
201 
202  AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
203  for( ; it != m_adhocTrackMap.end(); ++it )
204  {
205  if( (*it).second.context == context && (*it).second.remote == stanza->from() )
206  {
207  Tag *q = stanza->findChild( "query", "xmlns", XMLNS_DISCO_INFO );
208  if( q )
209  (*it).second.ah->handleAdhocSupport( (*it).second.remote,
210  q->hasChild( "feature", "var", XMLNS_ADHOC_COMMANDS ) );
211  m_adhocTrackMap.erase( it );
212  break;
213  }
214  }
215  }
216 
217  void Adhoc::handleDiscoItemsResult( Stanza *stanza, int context )
218  {
219  if( context != FetchAdhocCommands )
220  return;
221 
222  AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
223  for( ; it != m_adhocTrackMap.end(); ++it )
224  {
225  if( (*it).second.context == context && (*it).second.remote == stanza->from() )
226  {
227  Tag *q = stanza->findChild( "query", "xmlns", XMLNS_DISCO_ITEMS );
228  if( q )
229  {
230  StringMap commands;
231  const Tag::TagList& l = q->children();
232  Tag::TagList::const_iterator itt = l.begin();
233  for( ; itt != l.end(); ++itt )
234  {
235  const std::string& name = (*itt)->findAttribute( "name" );
236  const std::string& node = (*itt)->findAttribute( "node" );
237  if( (*itt)->name() == "item" && !name.empty() && !node.empty() )
238  {
239  commands[node] = name;
240  }
241  }
242  (*it).second.ah->handleAdhocCommands( (*it).second.remote, commands );
243  }
244 
245  m_adhocTrackMap.erase( it );
246  break;
247  }
248  }
249  }
250 
251  void Adhoc::handleDiscoError( Stanza *stanza, int context )
252  {
253  AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
254  for( ; it != m_adhocTrackMap.end(); ++it )
255  {
256  if( (*it).second.context == context && (*it).second.remote == stanza->from() )
257  {
258  (*it).second.ah->handleAdhocError( (*it).second.remote, stanza->error() );
259 
260  m_adhocTrackMap.erase( it );
261  }
262  }
263  }
264 
265  void Adhoc::checkSupport( const JID& remote, AdhocHandler *ah )
266  {
267  if( !remote || !ah )
268  return;
269 
270  TrackStruct track;
271  track.remote = remote;
272  track.context = CheckAdhocSupport;
273  track.ah = ah;
274  m_adhocTrackMap[m_parent->getID()] = track;
275  m_parent->disco()->getDiscoInfo( remote, "", this, CheckAdhocSupport );
276  }
277 
278  void Adhoc::getCommands( const JID& remote, AdhocHandler *ah )
279  {
280  if( !remote || !ah )
281  return;
282 
283  TrackStruct track;
284  track.remote = remote;
285  track.context = FetchAdhocCommands;
286  track.ah = ah;
287  m_adhocTrackMap[m_parent->getID()] = track;
288  m_parent->disco()->getDiscoItems( remote, XMLNS_ADHOC_COMMANDS, this, FetchAdhocCommands );
289  }
290 
291  void Adhoc::execute( const JID& remote, const std::string& command, AdhocHandler *ah,
292  const std::string& sessionid, DataForm *form,
293  AdhocExecuteActions action )
294  {
295  if( !remote || command.empty() || !ah )
296  return;
297 
298  const std::string& id = m_parent->getID();
299  Tag *iq = new Tag( "iq" );
300  iq->addAttribute( "type", "set" );
301  iq->addAttribute( "to", remote.full() );
302  iq->addAttribute( "id", id );
303  Tag *c = new Tag( iq, "command" );
304  c->addAttribute( "xmlns", XMLNS_ADHOC_COMMANDS );
305  c->addAttribute( "node", command );
306  c->addAttribute( "action", "execute" );
307  if( !sessionid.empty() )
308  c->addAttribute( "sessionid", sessionid );
309  if( action != ActionDefault )
310  {
311  switch( action )
312  {
313  case ActionPrevious:
314  c->addAttribute( "action", "prev" );
315  break;
316  case ActionNext:
317  c->addAttribute( "action", "next" );
318  break;
319  case ActionCancel:
320  c->addAttribute( "action", "cancel" );
321  break;
322  case ActionComplete:
323  c->addAttribute( "action", "complete" );
324  break;
325  default:
326  break;
327  }
328  }
329  if( form )
330  c->addChild( form->tag() );
331 
332  TrackStruct track;
333  track.remote = remote;
334  track.context = ExecuteAdhocCommand;
335  track.ah = ah;
336  m_adhocTrackMap[id] = track;
337 
338  m_parent->trackID( this, id, ExecuteAdhocCommand );
339  m_parent->send( iq );
340  }
341 
342  void Adhoc::removeAdhocCommandProvider( const std::string& command )
343  {
344  m_parent->disco()->removeNodeHandler( this, command );
345  m_adhocCommandProviders.erase( command );
346  m_items.erase( command );
347  }
348 
349 }