gloox  1.0.28
jinglesession.cpp
1 /*
2  Copyright (c) 2007-2023 by Jakob Schröter <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 static_cast<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 static_cast<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 
103  {
104  }
105 
106  const std::string& Session::Reason::filterString() const
107  {
108  static const std::string filter = "jingle/reason";
109  return filter;
110  }
111 
113  {
114  if( m_reason == InvalidReason )
115  return 0;
116 
117  Tag* t = new Tag( "reason" );
118  Tag* r = new Tag( t, util::lookup( m_reason, reasonValues ) );
119  if( m_reason == AlternativeSession && !m_sid.empty() )
120  new Tag( r, "sid", m_sid );
121 
122  if( !m_text.empty() )
123  new Tag( t, "text", m_text );
124 
125  return t;
126  }
127 
129  {
130  return new Reason( *this );
131  }
132  // ---- ~Session::Reason ----
133 
134  // ---- Session::Jingle ----
135  Session::Jingle::Jingle( Action action, const JID& initiator, const JID& responder,
136  const PluginList& plugins, const std::string& sid )
137  : StanzaExtension( ExtJingle ), m_action( action ), m_sid( sid ),
138  m_initiator( initiator ), m_responder( responder ), m_plugins( plugins ), m_tag( 0 )
139  {
140  }
141 
142 #ifdef JINGLE_TEST
143  Session::Jingle::Jingle( Action action, const JID& initiator, const JID& responder,
144  const Plugin* plugin, const std::string& sid )
145  : StanzaExtension( ExtJingle ), m_action( action ), m_sid( sid ),
146  m_initiator( initiator ), m_responder( responder ), m_tag( 0 )
147  {
148  if( plugin )
149  m_plugins.push_back( plugin );
150  }
151 #endif
152 
153  Session::Jingle::Jingle( const Tag* tag )
154  : StanzaExtension( ExtJingle ), m_action( InvalidAction ), m_tag( 0 )
155  {
156  if( !tag || tag->name() != "jingle" )
157  return;
158 
159  m_action = actionType( tag->findAttribute( "action" ) );
160  m_initiator.setJID( tag->findAttribute( "initiator" ) );
161  m_responder.setJID( tag->findAttribute( "responder" ) );
162  m_sid = tag->findAttribute( "sid" );
163 
164  m_tag = tag->clone();
165  }
166 
167 // Session::Jingle::Jingle( const Jingle& right )
168 // : StanzaExtension( ExtJingle ), m_action( right.m_action ),
169 // m_sid( right.m_sid ), m_initiator( right.m_initiator ),
170 // m_responder( right.m_responder )
171 // {
172 // PluginList::const_iterator it = right.m_plugins.begin();
173 // for( ; it != right.m_plugins.end(); ++it )
174 // m_plugins.push_back( (*it)->clone() );
175 // }
176 
177  Session::Jingle::~Jingle()
178  {
179  util::clearList( m_plugins );
180  }
181 
182  const std::string& Session::Jingle::filterString() const
183  {
184  static const std::string filter = "/iq/jingle[@xmlns='" + XMLNS_JINGLE + "']";
185  return filter;
186  }
187 
188  Tag* Session::Jingle::tag() const
189  {
190  if( m_action == InvalidAction || m_sid.empty() )
191  return 0;
192 
193  Tag* t = new Tag( "jingle" );
194  t->setXmlns( XMLNS_JINGLE );
195  t->addAttribute( "action", util::lookup( m_action, actionValues ) );
196 
197  if( m_initiator && m_action == SessionInitiate )
198  t->addAttribute( "initiator", m_initiator.full() );
199 
200  if( m_responder && m_action == SessionAccept )
201  t->addAttribute( "responder", m_responder.full() );
202 
203  t->addAttribute( "sid", m_sid );
204 
205  PluginList::const_iterator it = m_plugins.begin();
206  for( ; it != m_plugins.end(); ++it )
207  t->addChild( (*it)->tag() );
208 
209  return t;
210  }
211 
212  StanzaExtension* Session::Jingle::clone() const
213  {
214  return new Jingle( *this );
215  }
216  // ---- ~Session::Jingle ----
217 
218  // ---- Session ----
219  Session::Session( ClientBase* parent, const JID& callee, SessionHandler* jsh )
220  : m_parent( parent ), m_state( Ended ), m_remote( callee ),
221  m_handler( jsh ), m_valid( false )
222  {
223  if( !m_parent || !m_handler || !m_remote )
224  return;
225 
226  m_initiator = m_parent->jid();
227  m_sid = m_parent->getID();
228 
229  m_valid = true;
230  }
231 
232  Session::Session( ClientBase* parent, const JID& callee, const Session::Jingle* jingle, SessionHandler* jsh )
233  : m_parent( parent ), m_state( Ended ), m_handler( jsh ), m_valid( false )
234  {
235  if( !m_parent || !m_handler || !callee /*|| jingle->action() != SessionInitiate*/ )
236  return;
237 
238  m_remote = callee;
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::contentAccept( const Content* content )
251  {
252  if( m_state < Pending )
253  return false;
254 
255  return doAction( ContentAccept, content );
256  }
257 
258  bool Session::contentAdd( const Content* content )
259  {
260  if( m_state < Pending )
261  return false;
262 
263  return doAction( ContentAdd, content );
264  }
265 
266  bool Session::contentAdd( const PluginList& contents )
267  {
268  if( m_state < Pending )
269  return false;
270 
271  return doAction( ContentAdd, contents );
272  }
273 
274  bool Session::contentModify( const Content* content )
275  {
276  if( m_state < Pending )
277  return false;
278 
279  return doAction( ContentModify, content );
280  }
281 
282  bool Session::contentReject( const Content* content )
283  {
284  if( m_state < Pending )
285  return false;
286 
287  return doAction( ContentReject, content );
288  }
289 
290  bool Session::contentRemove( const Content* content )
291  {
292  if( m_state < Pending )
293  return false;
294 
295  return doAction( ContentRemove, content );
296  }
297 
298  bool Session::descriptionInfo( const Plugin* info )
299  {
300  if( m_state < Pending )
301  return false;
302 
303  return doAction( DescriptionInfo, info );
304  }
305 
306  bool Session::securityInfo( const Plugin* info )
307  {
308  if( m_state < Pending )
309  return false;
310 
311  return doAction( SecurityInfo, info );
312  }
313 
314  bool Session::sessionAccept( const Content* content )
315  {
316  if( !content || m_state > Pending )
317  return false;
318 
319  m_state = Active;
320  return doAction( SessionAccept, content );
321  }
322 
323  bool Session::sessionAccept( const PluginList& plugins )
324  {
325  if( plugins.empty() || m_state != Pending )
326  return false;
327 
328  m_state = Active;
329  return doAction( SessionAccept, plugins );
330  }
331 
332  bool Session::sessionInfo( const Plugin* info )
333  {
334  if( m_state < Pending )
335  return false;
336 
337  return doAction( SessionInfo, info );
338  }
339 
340  bool Session::sessionInitiate( const Content* content )
341  {
342  if( !content || !m_initiator || m_state >= Pending )
343  return false;
344 
345  m_state = Pending;
346  return doAction( SessionInitiate, content );
347  }
348 
349  bool Session::sessionInitiate( const PluginList& plugins )
350  {
351  if( plugins.empty() || !m_initiator || m_state >= Pending )
352  return false;
353 
354  m_state = Pending;
355  return doAction( SessionInitiate, plugins );
356  }
357 
359  {
360  if( m_state < Pending /*|| !m_initiator*/ )
361  return false;
362 
363  m_state = Ended;
364 
365  return doAction( SessionTerminate, reason );
366  }
367 
368  bool Session::transportAccept( const Content* content )
369  {
370  if( m_state < Pending )
371  return false;
372 
373  return doAction( TransportAccept, content );
374  }
375 
376  bool Session::transportInfo( const Plugin* info )
377  {
378  if( m_state < Pending )
379  return false;
380 
381  return doAction( TransportInfo, info );
382  }
383 
384  bool Session::transportReject( const Content* content )
385  {
386  if( m_state < Pending )
387  return false;
388 
389  return doAction( TransportReject, content );
390  }
391 
392  bool Session::transportReplace( const Content* content )
393  {
394  if( m_state < Pending )
395  return false;
396 
397  return doAction( TransportReplace, content );
398  }
399 
400  bool Session::doAction( Action action, const Plugin* plugin )
401  {
402  PluginList pl;
403  pl.push_back( plugin );
404  return doAction( action, pl );
405  }
406 
407  bool Session::doAction( Action action, const PluginList& plugins )
408  {
409  if( !m_valid || !m_parent )
410  return false;
411 
412  IQ init( IQ::Set, m_remote, m_parent->getID() );
413  init.addExtension( new Jingle( action, m_initiator, m_responder, plugins, m_sid ) );
414  m_parent->send( init, this, action );
415 
416  return true;
417  }
418 
419  bool Session::handleIq( const IQ& iq )
420  {
421  const Jingle* j = iq.findExtension<Jingle>( ExtJingle );
422  if( !j || j->sid() != m_sid || !m_handler || !m_parent )
423  return false;
424 
425  switch( j->action() )
426  {
427  case SessionAccept:
428  m_state = Active;
429  m_responder = j->responder();
430  break;
431  case SessionInitiate:
432  m_state = Pending;
433  m_initiator = j->initiator();
434  if( !m_responder )
435  m_responder = m_parent->jid();
436  break;
437  case SessionTerminate:
438  m_state = Ended;
439  break;
440  default:
441  break;
442  }
443 
444  IQ re( IQ::Result, iq.from(), iq.id() );
445  m_parent->send( re );
446 
447  m_handler->handleSessionAction( j->action(), this, j );
448 
449  return true;
450  }
451 
452  void Session::handleIqID( const IQ& iq, int context )
453  {
454  if( iq.subtype() == IQ::Error )
455  {
456 
457  const Error* e = iq.findExtension<Error>( ExtError );
458  m_handler->handleSessionActionError( static_cast<Action>( context ), this, e );
459 
460  switch( context )
461  {
462  case ContentAccept:
463  break;
464  case ContentAdd:
465  break;
466  case ContentModify:
467  break;
468  case ContentReject:
469  break;
470  case ContentRemove:
471  break;
472  case DescriptionInfo:
473  break;
474  case SessionAccept:
475  break;
476  case SessionInfo:
477  break;
478  case SessionInitiate:
479  m_state = Ended;
480  break;
481  case SessionTerminate:
482  break;
483  case TransportAccept:
484  break;
485  case TransportInfo:
486  break;
487  case TransportReject:
488  break;
489  case TransportReplace:
490  break;
491  case InvalidAction:
492  break;
493  default:
494  break;
495  }
496  }
497  }
498 
499  }
500 
501 }
This is the common base class for a Jabber/XMPP Client and a Jabber Component.
Definition: clientbase.h:79
const std::string getID()
const JID & jid()
Definition: clientbase.h:147
void removeIDHandler(IqHandler *ih)
void send(Tag *tag)
A stanza error abstraction implemented as a StanzaExtension.
Definition: error.h:35
An abstraction of an IQ stanza.
Definition: iq.h:34
IqType subtype() const
Definition: iq.h:74
@ Set
Definition: iq.h:46
@ Error
Definition: iq.h:49
@ Result
Definition: iq.h:48
An abstraction of a JID.
Definition: jid.h:31
bool setJID(const std::string &jid)
Definition: jid.cpp:21
const std::string & full() const
Definition: jid.h:61
An abstraction of a Jingle Content Type. This is part of Jingle (XEP-0166).
Definition: jinglecontent.h:42
An abstraction of a Jingle plugin. This is part of Jingle (XEP-0166 et al.)
Definition: jingleplugin.h:68
A Jingle session handler.
virtual void handleSessionActionError(Action action, Session *session, const Error *error)=0
virtual void handleSessionAction(Action action, Session *session, const Session::Jingle *jingle)=0
This is an abstraction of Jingle's (XEP-0166) <jingle> element as a StanzaExtension.
const std::string & sid() const
An abstraction of a Jingle (XEP-0166) session terminate reason.
Reason(Reasons reason, const std::string &sid=EmptyString, const std::string &text=EmptyString)
virtual Plugin * clone() const
virtual const std::string & filterString() const
bool contentReject(const Content *content)
bool transportReplace(const Content *content)
bool sessionAccept(const Content *content)
bool contentRemove(const Content *content)
bool sessionInfo(const Plugin *info)
bool transportReject(const Content *content)
bool transportInfo(const Plugin *info)
bool contentAdd(const Content *content)
bool sessionInitiate(const Content *content)
bool transportAccept(const Content *content)
virtual void handleIqID(const IQ &iq, int context)
virtual bool handleIq(const IQ &iq)
bool contentModify(const Content *content)
const std::string & sid() const
const JID & responder() const
bool securityInfo(const Plugin *info)
bool descriptionInfo(const Plugin *info)
const JID & initiator() const
bool contentAccept(const Content *content)
bool sessionTerminate(Session::Reason *reason)
This class abstracts a stanza extension, which is usually an XML child element in a specific namespac...
const std::string & id() const
Definition: stanza.h:63
const JID & from() const
Definition: stanza.h:51
const StanzaExtension * findExtension(int type) const
Definition: stanza.cpp:57
This is an abstraction of an XML element.
Definition: tag.h:47
bool addAttribute(Attribute *attr)
Definition: tag.cpp:354
void addChild(Tag *child)
Definition: tag.cpp:424
const std::string & findAttribute(const std::string &name) const
Definition: tag.cpp:589
const std::string & name() const
Definition: tag.h:394
Tag * clone() const
Definition: tag.cpp:670
const TagList & children() const
Definition: tag.cpp:510
bool setXmlns(const std::string &xmlns, const std::string &prefix=EmptyString)
Definition: tag.cpp:522
std::list< const Plugin * > PluginList
Definition: jingleplugin.h:52
void clearList(std::list< T * > &L)
Definition: util.h:152
The namespace for the gloox library.
Definition: adhoc.cpp:28
std::list< Tag * > TagList
Definition: tag.h:26
const std::string XMLNS_JINGLE
Definition: gloox.cpp:101