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