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