gloox  1.0.10
jinglesession.cpp
1 /*
2  Copyright (c) 2007-2013 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 "jinglesession.h"
15 
16 #include "clientbase.h"
17 #include "error.h"
18 #include "jinglecontent.h"
19 #include "jinglesessionhandler.h"
20 #include "tag.h"
21 #include "util.h"
22 
23 namespace gloox
24 {
25 
26  namespace Jingle
27  {
28 
29  static const char* actionValues [] = {
30  "content-accept",
31  "content-add",
32  "content-modify",
33  "content-reject",
34  "content-remove",
35  "description-info",
36  "security-info",
37  "session-accept",
38  "session-info",
39  "session-initiate",
40  "session-terminate",
41  "transport-accept",
42  "transport-info",
43  "transport-reject",
44  "transport-replace"
45  };
46 
47  static inline Action actionType( const std::string& type )
48  {
49  return (Action)util::lookup( type, actionValues );
50  }
51 
52  // ---- Session::Reason ----
53  static const char* reasonValues [] = {
54  "alternative-session",
55  "busy",
56  "cancel",
57  "connectivity-error",
58  "decline",
59  "expired",
60  "failed-application",
61  "failed-transport",
62  "general-error",
63  "gone",
64  "incompatible-parameters",
65  "media-error",
66  "security-error",
67  "success",
68  "timeout",
69  "unsupported-applications",
70  "unsupported-transports"
71  };
72 
73  static inline Session::Reason::Reasons reasonType( const std::string& type )
74  {
75  return (Session::Reason::Reasons)util::lookup( type, reasonValues );
76  }
77 
79  const std::string& sid,
80  const std::string& text)
81  : Plugin( PluginReason ), m_reason( reason ), m_sid( sid ), m_text( text )
82  {
83  }
84 
86  : Plugin( PluginReason )
87  {
88  if( !tag || tag->name() != "reason" )
89  return;
90 
91  const TagList& l = tag->children();
92  TagList::const_iterator it = l.begin();
93  for( ; it != l.end(); ++it )
94  {
95  if( (*it)->name() == "text" )
96  m_text = (*it)->cdata();
97  else if( (*it)->xmlns() == XMLNS_JINGLE )
98  m_reason = reasonType( (*it)->name() );
99  }
100  }
101 
102  const std::string& Session::Reason::filterString() const
103  {
104  static const std::string filter = "jingle/reason";
105  return filter;
106  }
107 
109  {
110  if( m_reason == InvalidReason )
111  return 0;
112 
113  Tag* t = new Tag( "reason" );
114  Tag* r = new Tag( t, util::lookup( m_reason, reasonValues ) );
115  if( m_reason == AlternativeSession && !m_sid.empty() )
116  new Tag( r, "sid", m_sid );
117 
118  if( !m_text.empty() )
119  new Tag( t, "text", m_text );
120 
121  return t;
122  }
123 
125  {
126  return new Reason( *this );
127  }
128  // ---- ~Session::Reason ----
129 
130  // ---- Session::Jingle ----
131  Session::Jingle::Jingle( Action action, const JID& initiator, const JID& responder,
132  const PluginList& plugins, const std::string& sid )
133  : StanzaExtension( ExtJingle ), m_action( action ), m_sid( sid ),
134  m_initiator( initiator ), m_responder( responder ), m_plugins( plugins ), m_tag( 0 )
135  {
136  }
137 
138 #ifdef JINGLE_TEST
139  Session::Jingle::Jingle( Action action, const JID& initiator, const JID& responder,
140  const Plugin* plugin, const std::string& sid )
141  : StanzaExtension( ExtJingle ), m_action( action ), m_sid( sid ),
142  m_initiator( initiator ), m_responder( responder ), m_tag( 0 )
143  {
144  if( plugin )
145  m_plugins.push_back( plugin );
146  }
147 #endif
148 
149  Session::Jingle::Jingle( const Tag* tag )
150  : StanzaExtension( ExtJingle ), m_action( InvalidAction ), m_tag( 0 )
151  {
152  if( !tag || tag->name() != "jingle" )
153  return;
154 
155  m_action = actionType( tag->findAttribute( "action" ) );
156  m_initiator.setJID( tag->findAttribute( "initiator" ) );
157  m_responder.setJID( tag->findAttribute( "responder" ) );
158  m_sid = tag->findAttribute( "sid" );
159 
160  m_tag = tag->clone();
161  }
162 
163 // Session::Jingle::Jingle( const Jingle& right )
164 // : StanzaExtension( ExtJingle ), m_action( right.m_action ),
165 // m_sid( right.m_sid ), m_initiator( right.m_initiator ),
166 // m_responder( right.m_responder )
167 // {
168 // PluginList::const_iterator it = right.m_plugins.begin();
169 // for( ; it != right.m_plugins.end(); ++it )
170 // m_plugins.push_back( (*it)->clone() );
171 // }
172 
173  Session::Jingle::~Jingle()
174  {
175  util::clearList( m_plugins );
176  }
177 
178  const std::string& Session::Jingle::filterString() const
179  {
180  static const std::string filter = "/iq/jingle[@xmlns='" + XMLNS_JINGLE + "']";
181  return filter;
182  }
183 
184  Tag* Session::Jingle::tag() const
185  {
186  if( m_action == InvalidAction || m_sid.empty() )
187  return 0;
188 
189  Tag* t = new Tag( "jingle" );
190  t->setXmlns( XMLNS_JINGLE );
191  t->addAttribute( "action", util::lookup( m_action, actionValues ) );
192 
193  if( m_initiator && m_action == SessionInitiate )
194  t->addAttribute( "initiator", m_initiator.full() );
195 
196  if( m_responder && m_action == SessionAccept )
197  t->addAttribute( "responder", m_responder.full() );
198 
199  t->addAttribute( "sid", m_sid );
200 
201  PluginList::const_iterator it = m_plugins.begin();
202  for( ; it != m_plugins.end(); ++it )
203  t->addChild( (*it)->tag() );
204 
205  return t;
206  }
207 
208  StanzaExtension* Session::Jingle::clone() const
209  {
210  return new Jingle( *this );
211  }
212  // ---- ~Session::Jingle ----
213 
214  // ---- Session ----
215  Session::Session( ClientBase* parent, const JID& callee, SessionHandler* jsh )
216  : m_parent( parent ), m_state( Ended ), m_remote( callee ),
217  m_handler( jsh ), m_valid( false )
218  {
219  if( !m_parent || !m_handler || !m_remote )
220  return;
221 
222  m_initiator = m_parent->jid();
223  m_sid = m_parent->getID();
224 
225  m_valid = true;
226  }
227 
228  Session::Session( ClientBase* parent, const JID& callee, const Session::Jingle* jingle, SessionHandler* jsh )
229  : m_parent( parent ), m_state( Ended ), m_handler( jsh ), m_valid( false )
230  {
231  if( !m_parent || !m_handler || !callee /*|| jingle->action() != SessionInitiate*/ )
232  return;
233 
234  m_remote = callee;
235  m_sid = jingle->sid();
236 
237  m_valid = true;
238  }
239 
241  {
242  if( m_parent )
243  m_parent->removeIDHandler( this );
244  }
245 
246  bool Session::contentAccept( const Content* content )
247  {
248  if( m_state < Pending )
249  return false;
250 
251  return doAction( ContentAccept, content );
252  }
253 
254  bool Session::contentAdd( const Content* content )
255  {
256  if( m_state < Pending )
257  return false;
258 
259  return doAction( ContentAdd, content );
260  }
261 
262  bool Session::contentAdd( const PluginList& contents )
263  {
264  if( m_state < Pending )
265  return false;
266 
267  return doAction( ContentAdd, contents );
268  }
269 
270  bool Session::contentModify( const Content* content )
271  {
272  if( m_state < Pending )
273  return false;
274 
275  return doAction( ContentModify, content );
276  }
277 
278  bool Session::contentReject( const Content* content )
279  {
280  if( m_state < Pending )
281  return false;
282 
283  return doAction( ContentReject, content );
284  }
285 
286  bool Session::contentRemove( const Content* content )
287  {
288  if( m_state < Pending )
289  return false;
290 
291  return doAction( ContentRemove, content );
292  }
293 
294  bool Session::descriptionInfo( const Plugin* info )
295  {
296  if( m_state < Pending )
297  return false;
298 
299  return doAction( DescriptionInfo, info );
300  }
301 
302  bool Session::securityInfo( const Plugin* info )
303  {
304  if( m_state < Pending )
305  return false;
306 
307  return doAction( SecurityInfo, info );
308  }
309 
310  bool Session::sessionAccept( const Content* content )
311  {
312  if( !content || m_state > Pending )
313  return false;
314 
315  m_state = Active;
316  return doAction( SessionAccept, content );
317  }
318 
319  bool Session::sessionAccept( const PluginList& plugins )
320  {
321  if( plugins.empty() || m_state >= Pending )
322  return false;
323 
324  m_state = Active;
325  return doAction( SessionAccept, plugins );
326  }
327 
328  bool Session::sessionInfo( const Plugin* info )
329  {
330  if( m_state < Pending )
331  return false;
332 
333  return doAction( SessionInfo, info );
334  }
335 
336  bool Session::sessionInitiate( const Content* content )
337  {
338  if( !content || !m_initiator || m_state >= Pending )
339  return false;
340 
341  m_state = Pending;
342  return doAction( SessionInitiate, content );
343  }
344 
345  bool Session::sessionInitiate( const PluginList& plugins )
346  {
347  if( plugins.empty() || !m_initiator || m_state >= Pending )
348  return false;
349 
350  m_state = Pending;
351  return doAction( SessionInitiate, plugins );
352  }
353 
355  {
356  if( m_state < Pending /*|| !m_initiator*/ )
357  return false;
358 
359  m_state = Ended;
360 
361  return doAction( SessionTerminate, reason );
362  }
363 
364  bool Session::transportAccept( const Content* content )
365  {
366  if( m_state < Pending )
367  return false;
368 
369  return doAction( TransportAccept, content );
370  }
371 
372  bool Session::transportInfo( const Plugin* info )
373  {
374  if( m_state < Pending )
375  return false;
376 
377  return doAction( TransportInfo, info );
378  }
379 
380  bool Session::transportReject( const Content* content )
381  {
382  if( m_state < Pending )
383  return false;
384 
385  return doAction( TransportReject, content );
386  }
387 
388  bool Session::transportReplace( const Content* content )
389  {
390  if( m_state < Pending )
391  return false;
392 
393  return doAction( TransportReplace, content );
394  }
395 
396  bool Session::doAction( Action action, const Plugin* plugin )
397  {
398  PluginList pl;
399  pl.push_back( plugin );
400  return doAction( action, pl );
401  }
402 
403  bool Session::doAction( Action action, const PluginList& plugins )
404  {
405  if( !m_valid || !m_parent )
406  return false;
407 
408  IQ init( IQ::Set, m_remote, m_parent->getID() );
409  init.addExtension( new Jingle( action, m_initiator, m_responder, plugins, m_sid ) );
410  m_parent->send( init, this, action );
411 
412  return true;
413  }
414 
415  bool Session::handleIq( const IQ& iq )
416  {
417  const Jingle* j = iq.findExtension<Jingle>( ExtJingle );
418  if( !j || j->sid() != m_sid || !m_handler || !m_parent )
419  return false;
420 
421  switch( j->action() )
422  {
423  case SessionAccept:
424  m_state = Active;
425  m_responder = j->responder();
426  break;
427  case SessionInitiate:
428  m_state = Pending;
429  m_initiator = j->initiator();
430  if( !m_responder )
431  m_responder = m_parent->jid();
432  break;
433  case SessionTerminate:
434  m_state = Ended;
435  break;
436  default:
437  break;
438  }
439 
440  IQ re( IQ::Result, iq.from(), iq.id() );
441  m_parent->send( re );
442 
443  m_handler->handleSessionAction( j->action(), this, j );
444 
445  return true;
446  }
447 
448  void Session::handleIqID( const IQ& iq, int context )
449  {
450  if( iq.subtype() == IQ::Error )
451  {
452 
453  const Error* e = iq.findExtension<Error>( ExtError );
454  m_handler->handleSessionActionError( (Action)context, this, e );
455 
456  switch( context )
457  {
458  case ContentAccept:
459  break;
460  case ContentAdd:
461  break;
462  case ContentModify:
463  break;
464  case ContentReject:
465  break;
466  case ContentRemove:
467  break;
468  case DescriptionInfo:
469  break;
470  case SessionAccept:
471  break;
472  case SessionInfo:
473  break;
474  case SessionInitiate:
475  m_state = Ended;
476  break;
477  case SessionTerminate:
478  break;
479  case TransportAccept:
480  break;
481  case TransportInfo:
482  break;
483  case TransportReject:
484  break;
485  case TransportReplace:
486  break;
487  case InvalidAction:
488  break;
489  default:
490  break;
491  }
492  }
493  }
494 
495  }
496 
497 }