gloox  0.9.9.12
stanza.cpp
1 /*
2  Copyright (c) 2005-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 "stanza.h"
15 #include "jid.h"
16 #include "stanzaextension.h"
17 #include "stanzaextensionfactory.h"
18 
19 #include <cstdlib>
20 
21 namespace gloox
22 {
23 
24  Stanza::Stanza( const std::string& name, const std::string& cdata, const std::string& xmllang,
25  bool incoming )
26  : Tag( name, cdata, incoming ), m_subtype( StanzaSubUndefined ), m_presence( PresenceUnknown ),
27  m_stanzaError( StanzaErrorUndefined ), m_stanzaErrorType( StanzaErrorTypeUndefined ),
28  m_stanzaErrorAppCondition( 0 ), m_xmllang( xmllang ), m_priority( -300 )
29  {
30  }
31 
32  Stanza::Stanza( const Tag *tag )
33  : Tag( tag->name(), tag->cdata(), false ), m_presence( PresenceUnknown ),
34  m_stanzaError( StanzaErrorUndefined ), m_stanzaErrorType( StanzaErrorTypeUndefined ),
35  m_stanzaErrorAppCondition( 0 ), m_xmllang( "default" )
36  {
37  m_attribs = tag->attributes();
38  const Tag::TagList& l = tag->children();
39  Tag::TagList::const_iterator it = l.begin();
40  for( ; it != l.end(); ++it )
41  {
42  addChild( (*it)->clone() );
43  }
44 
45  init();
46  }
47 
49  {
50  StanzaExtensionList::iterator it = m_extensionList.begin();
51  for( ; it != m_extensionList.end(); ++it )
52  {
53  delete (*it);
54  }
55  }
56 
57  void Stanza::init()
58  {
59  m_from.setJID( findAttribute( "from" ) );
60  m_to.setJID( findAttribute( "to" ) );
61  m_id = findAttribute( "id" );
62 
63  if( m_name == "iq" )
64  {
65  m_type = StanzaIq;
66  if( hasAttribute( "type", "get" ) )
67  m_subtype = StanzaIqGet;
68  else if( hasAttribute( "type", "set" ) )
69  m_subtype = StanzaIqSet;
70  else if( hasAttribute( "type", "result" ) )
71  m_subtype = StanzaIqResult;
72  else if( hasAttribute( "type", "error" ) )
73  m_subtype = StanzaIqError;
74  else
75  m_subtype = StanzaSubUndefined;
76 
77  Tag *t = findChildWithAttrib( "xmlns" );
78  if( t )
79  m_xmlns = t->findAttribute( "xmlns" );
80 
81  const TagList& c = children();
82  TagList::const_iterator it = c.begin();
83  for( ; it != c.end(); ++it )
84  {
86  if( se )
87  m_extensionList.push_back( se );
88  }
89  }
90  else if( m_name == "message" )
91  {
92  m_type = StanzaMessage;
93  if( hasAttribute( "type", "chat" ) )
94  m_subtype = StanzaMessageChat;
95  else if( hasAttribute( "type", "error" ) )
96  m_subtype = StanzaMessageError;
97  else if( hasAttribute( "type", "headline" ) )
98  m_subtype = StanzaMessageHeadline;
99  else if( hasAttribute( "type", "groupchat" ) )
100  m_subtype = StanzaMessageGroupchat;
101  else
102  m_subtype = StanzaMessageNormal;
103 
104  const TagList& c = children();
105  TagList::const_iterator it = c.begin();
106  for( ; it != c.end(); ++it )
107  {
108  if( (*it)->name() == "body" )
109  {
110  setLang( m_body, (*it) );
111  }
112  else if( (*it)->name() == "subject" )
113  {
114  setLang( m_subject, (*it) );
115  }
116  else if( (*it)->name() == "thread" )
117  {
118  m_thread = (*it)->cdata();
119  }
120  else
121  {
122  StanzaExtension *se = StanzaExtensionFactory::create( (*it) );
123  if( se )
124  m_extensionList.push_back( se );
125  }
126  }
127  }
128  else if( m_name == "presence" )
129  {
130  if( hasAttribute( "type", "subscribe" ) )
131  {
132  m_type = StanzaS10n;
133  m_subtype = StanzaS10nSubscribe;
134  }
135  else if( hasAttribute( "type", "subscribed" ) )
136  {
137  m_type = StanzaS10n;
138  m_subtype = StanzaS10nSubscribed;
139  }
140  else if( hasAttribute( "type", "unsubscribe" ) )
141  {
142  m_type = StanzaS10n;
143  m_subtype = StanzaS10nUnsubscribe;
144  }
145  else if( hasAttribute( "type", "unsubscribed" ) )
146  {
147  m_type = StanzaS10n;
148  m_subtype = StanzaS10nUnsubscribed;
149  }
150  else if( hasAttribute( "type", "unavailable" ) )
151  {
152  m_type = StanzaPresence;
153  m_subtype = StanzaPresenceUnavailable;
154  }
155  else if( hasAttribute( "type", "probe" ) )
156  {
157  m_type = StanzaPresence;
158  m_subtype = StanzaPresenceProbe;
159  }
160  else if( hasAttribute( "type", "error" ) )
161  {
162  m_type = StanzaPresence;
163  m_subtype = StanzaPresenceError;
164  }
165  else if( !hasAttribute( "type" ) )
166  {
167  m_type = StanzaPresence;
168  m_subtype = StanzaPresenceAvailable;
169  }
170  else
171  {
172  m_type = StanzaPresence;
173  m_subtype = StanzaSubUndefined;
174  }
175  }
176  else
177  {
178  m_type = StanzaUndefined;
179  m_subtype = StanzaSubUndefined;
180  }
181 
182  if( m_type == StanzaPresence )
183  {
184  if( !hasAttribute( "type" ) )
185  m_presence = PresenceAvailable;
186 
187  if( hasChildWithCData( "show", "chat" ) )
188  m_presence = PresenceChat;
189  else if( hasChildWithCData( "show", "away" ) )
190  m_presence = PresenceAway;
191  else if( hasChildWithCData( "show", "dnd" ) )
192  m_presence = PresenceDnd;
193  else if( hasChildWithCData( "show", "xa" ) )
194  m_presence = PresenceXa;
195  else if( hasAttribute( "type", "unavailable" ) )
196  m_presence = PresenceUnavailable;
197 
198  if( hasChild( "priority" ) )
199  m_priority = atoi( findChild( "priority" )->cdata().c_str() );
200  }
201 
202  if( m_type == StanzaPresence || m_type == StanzaS10n )
203  {
204  const TagList& c = children();
205  TagList::const_iterator it = c.begin();
206  for( ; it != c.end(); ++it )
207  {
208  if( (*it)->name() == "status" )
209  {
210  setLang( m_status, (*it) );
211  }
212  else
213  {
214  StanzaExtension *se = StanzaExtensionFactory::create( (*it) );
215  if( se )
216  m_extensionList.push_back( se );
217  }
218  }
219  }
220 
221  m_xmllang = findAttribute( "xml:lang" );
222 
223  if( hasAttribute( "type", "error" ) && hasChild( "error" ) )
224  {
225  Tag *e = findChild( "error" );
226 
227  if( e->hasAttribute( "type", "cancel" ) )
228  m_stanzaErrorType = StanzaErrorTypeCancel;
229  else if( e->hasAttribute( "type", "continue" ) )
230  m_stanzaErrorType = StanzaErrorTypeContinue;
231  else if( e->hasAttribute( "type", "modify" ) )
232  m_stanzaErrorType = StanzaErrorTypeModify;
233  else if( e->hasAttribute( "type", "auth" ) )
234  m_stanzaErrorType = StanzaErrorTypeAuth;
235  else if( e->hasAttribute( "type", "wait" ) )
236  m_stanzaErrorType = StanzaErrorTypeWait;
237 
238  const TagList& c = e->children();
239  TagList::const_iterator it = c.begin();
241  for( ; it != c.end(); ++it )
242  {
243  if( (*it)->name() == "bad-request" )
244  err = StanzaErrorBadRequest;
245  else if( (*it)->name() == "conflict" )
246  err = StanzaErrorConflict;
247  else if( (*it)->name() == "feature-not-implemented" )
249  else if( (*it)->name() == "forbidden" )
250  err = StanzaErrorForbidden;
251  else if( (*it)->name() == "gone" )
252  err = StanzaErrorGone;
253  else if( (*it)->name() == "internal-server-error" )
255  else if( (*it)->name() == "item-not-found" )
257  else if( (*it)->name() == "jid-malformed" )
259  else if( (*it)->name() == "not-acceptable" )
261  else if( (*it)->name() == "not-allowed" )
262  err = StanzaErrorNotAllowed;
263  else if( (*it)->name() == "not-authorized" )
265  else if( (*it)->name() == "recipient-unavailable" )
267  else if( (*it)->name() == "redirect" )
268  err = StanzaErrorRedirect;
269  else if( (*it)->name() == "registration-required" )
271  else if( (*it)->name() == "remote-server-not-found" )
273  else if( (*it)->name() == "remote-server-timeout" )
275  else if( (*it)->name() == "resource-constraint" )
277  else if( (*it)->name() == "service-unavailable" )
279  else if( (*it)->name() == "subscription-required" )
281  else if( (*it)->name() == "undefined-condition" )
283  else if( (*it)->name() == "unexpected-request" )
285  else if( (*it)->name() == "text" )
286  {
287  setLang( m_errorText, (*it) );
288  }
289  else {
290  m_stanzaErrorAppCondition = (*it);
291  }
292 
293  if( err != StanzaErrorUndefined && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STANZAS ) )
294  {
295  m_stanzaError = err;
296  }
297  }
298  }
299  }
300 
302  {
303  m_extensionList.push_back( se );
304  addChild( se->tag() );
305  }
306 
307  Stanza* Stanza::createIqStanza( const JID& to, const std::string& id,
308  StanzaSubType subtype, const std::string& xmlns, Tag* tag )
309  {
310  Stanza *s = new Stanza( "iq" );
311  switch( subtype )
312  {
313  case StanzaIqError:
314  s->addAttribute( "type", "error" );
315  break;
316  case StanzaIqSet:
317  s->addAttribute( "type", "set" );
318  break;
319  case StanzaIqResult:
320  s->addAttribute( "type", "result" );
321  break;
322  case StanzaIqGet:
323  default:
324  s->addAttribute( "type", "get" );
325  break;
326  }
327 
328  if( !xmlns.empty() )
329  {
330  Tag *q = new Tag( s, "query" );
331  q->addAttribute( "xmlns", xmlns );
332  if( tag )
333  q->addChild( tag );
334  }
335  s->addAttribute( "to", to.full() );
336  s->addAttribute( "id", id );
337 
338  s->finalize();
339 
340  return s;
341  }
342 
343  Stanza* Stanza::createPresenceStanza( const JID& to, const std::string& msg,
344  Presence status, const std::string& xmllang )
345  {
346  Stanza *s = new Stanza( "presence" );
347  switch( status )
348  {
349  case PresenceUnavailable:
350  s->addAttribute( "type", "unavailable" );
351  break;
352  case PresenceChat:
353  new Tag( s, "show", "chat" );
354  break;
355  case PresenceAway:
356  new Tag( s, "show", "away" );
357  break;
358  case PresenceDnd:
359  new Tag( s, "show", "dnd" );
360  break;
361  case PresenceXa:
362  new Tag( s, "show", "xa" );
363  break;
364  default:
365  break;
366  }
367 
368  if( to )
369  s->addAttribute( "to", to.full() );
370 
371  if( !msg.empty() )
372  {
373  Tag *t = new Tag( s, "status", msg );
374  t->addAttribute( "xml:lang", xmllang );
375  }
376 
377  s->finalize();
378 
379  return s;
380  }
381 
382  Stanza* Stanza::createMessageStanza( const JID& to, const std::string& body,
383  StanzaSubType subtype, const std::string& subject,
384  const std::string& thread, const std::string& xmllang )
385  {
386  Stanza *s = new Stanza( "message" );
387  switch( subtype )
388  {
389  case StanzaMessageError:
390  s->addAttribute( "type", "error" );
391  break;
392  case StanzaMessageNormal:
393  s->addAttribute( "type", "normal" );
394  break;
396  s->addAttribute( "type", "headline" );
397  break;
399  s->addAttribute( "type", "groupchat" );
400  break;
401  case StanzaMessageChat:
402  default:
403  s->addAttribute( "type", "chat" );
404  break;
405  }
406 
407  s->addAttribute( "to", to.full() );
408 
409  if( !body.empty() )
410  {
411  Tag *b = new Tag( s, "body", body );
412  b->addAttribute( "xml:lang", xmllang );
413  }
414  if( !subject.empty() )
415  {
416  Tag *su = new Tag( s, "subject", subject );
417  su->addAttribute( "xml:lang", xmllang );
418  }
419  if( !thread.empty() )
420  new Tag( s, "thread", thread );
421 
422  s->finalize();
423 
424  return s;
425  }
426 
427  Stanza* Stanza::createSubscriptionStanza( const JID& to, const std::string& msg,
428  StanzaSubType subtype, const std::string& xmllang )
429  {
430  Stanza *s = new Stanza( "presence" );
431  switch( subtype )
432  {
434  s->addAttribute( "type", "subscribed" );
435  break;
437  s->addAttribute( "type", "unsubscribe" );
438  break;
440  s->addAttribute( "type", "unsubscribed" );
441  break;
442  case StanzaS10nSubscribe:
443  default:
444  s->addAttribute( "type", "subscribe" );
445  break;
446  }
447 
448  s->addAttribute( "to", to.full() );
449  if( !msg.empty() )
450  {
451  Tag *t = new Tag( s, "status", msg );
452  t->addAttribute( "xml:lang", xmllang );
453  }
454 
455  s->finalize();
456 
457  return s;
458  }
459 
460  void Stanza::setLang( StringMap& map, const Tag *tag )
461  {
462  const std::string& lang = tag->findAttribute( "xml:lang" );
463  map[ lang.empty() ? "default" : lang ] = tag->cdata();
464  }
465 
466  const std::string Stanza::findLang( const StringMap& map, const std::string& lang )
467  {
468  StringMap::const_iterator it = map.find( lang );
469  return ( it != map.end() ) ? (*it).second : std::string();
470  }
471 
472 }