stanza.cpp

00001 /*
00002   Copyright (c) 2005-2008 by Jakob Schroeter <js@camaya.net>
00003   This file is part of the gloox library. http://camaya.net/gloox
00004 
00005   This software is distributed under a license. The full license
00006   agreement can be found in the file LICENSE in this distribution.
00007   This software may not be copied, modified, sold or distributed
00008   other than expressed in the named license agreement.
00009 
00010   This software is distributed without any warranty.
00011 */
00012 
00013 
00014 #include "stanza.h"
00015 #include "jid.h"
00016 #include "stanzaextension.h"
00017 #include "stanzaextensionfactory.h"
00018 
00019 #include <cstdlib>
00020 
00021 namespace gloox
00022 {
00023 
00024   Stanza::Stanza( const std::string& name, const std::string& cdata, const std::string& xmllang,
00025                   bool incoming )
00026     : Tag( name, cdata, incoming ), m_subtype( StanzaSubUndefined ), m_presence( PresenceUnknown ),
00027       m_stanzaError( StanzaErrorUndefined ), m_stanzaErrorType( StanzaErrorTypeUndefined ),
00028       m_stanzaErrorAppCondition( 0 ), m_xmllang( xmllang ), m_priority( -300 )
00029   {
00030   }
00031 
00032   Stanza::Stanza( const Tag *tag )
00033     : Tag( tag->name(), tag->cdata(), false ), m_presence( PresenceUnknown ),
00034       m_stanzaError( StanzaErrorUndefined ), m_stanzaErrorType( StanzaErrorTypeUndefined ),
00035       m_stanzaErrorAppCondition( 0 ), m_xmllang( "default" )
00036   {
00037     m_attribs = tag->attributes();
00038     const Tag::TagList& l = tag->children();
00039     Tag::TagList::const_iterator it = l.begin();
00040     for( ; it != l.end(); ++it )
00041     {
00042       addChild( (*it)->clone() );
00043     }
00044 
00045     init();
00046   }
00047 
00048   Stanza::~Stanza()
00049   {
00050     StanzaExtensionList::iterator it = m_extensionList.begin();
00051     for( ; it != m_extensionList.end(); ++it )
00052     {
00053       delete (*it);
00054     }
00055   }
00056 
00057   void Stanza::init()
00058   {
00059     m_from.setJID( findAttribute( "from" ) );
00060     m_to.setJID( findAttribute( "to" ) );
00061     m_id = findAttribute( "id" );
00062 
00063     if( m_name == "iq" )
00064     {
00065       m_type = StanzaIq;
00066       if( hasAttribute( "type", "get" ) )
00067         m_subtype = StanzaIqGet;
00068       else if( hasAttribute( "type", "set" ) )
00069         m_subtype = StanzaIqSet;
00070       else if( hasAttribute( "type", "result" ) )
00071         m_subtype = StanzaIqResult;
00072       else if( hasAttribute( "type", "error" ) )
00073         m_subtype = StanzaIqError;
00074       else
00075         m_subtype = StanzaSubUndefined;
00076 
00077       Tag *t = findChildWithAttrib( "xmlns" );
00078       if( t )
00079         m_xmlns = t->findAttribute( "xmlns" );
00080 
00081       const TagList& c = children();
00082       TagList::const_iterator it = c.begin();
00083       for( ; it != c.end(); ++it )
00084       {
00085         StanzaExtension *se = StanzaExtensionFactory::create( (*it) );
00086         if( se )
00087           m_extensionList.push_back( se );
00088       }
00089     }
00090     else if( m_name == "message" )
00091     {
00092       m_type = StanzaMessage;
00093       if( hasAttribute( "type", "chat" ) )
00094         m_subtype = StanzaMessageChat;
00095       else if( hasAttribute( "type", "error" ) )
00096         m_subtype = StanzaMessageError;
00097       else if( hasAttribute( "type", "headline" ) )
00098         m_subtype = StanzaMessageHeadline;
00099       else if( hasAttribute( "type", "groupchat" ) )
00100         m_subtype = StanzaMessageGroupchat;
00101       else
00102         m_subtype = StanzaMessageNormal;
00103 
00104       const TagList& c = children();
00105       TagList::const_iterator it = c.begin();
00106       for( ; it != c.end(); ++it )
00107       {
00108         if( (*it)->name() == "body" )
00109         {
00110           setLang( m_body, (*it) );
00111         }
00112         else if( (*it)->name() == "subject" )
00113         {
00114           setLang( m_subject, (*it) );
00115         }
00116         else if( (*it)->name() == "thread" )
00117         {
00118           m_thread = (*it)->cdata();
00119         }
00120         else
00121         {
00122           StanzaExtension *se = StanzaExtensionFactory::create( (*it) );
00123           if( se )
00124             m_extensionList.push_back( se );
00125         }
00126       }
00127     }
00128     else if( m_name == "presence" )
00129     {
00130       if( hasAttribute( "type", "subscribe" ) )
00131       {
00132         m_type = StanzaS10n;
00133         m_subtype = StanzaS10nSubscribe;
00134       }
00135       else if( hasAttribute( "type", "subscribed" ) )
00136       {
00137         m_type = StanzaS10n;
00138         m_subtype = StanzaS10nSubscribed;
00139       }
00140       else if( hasAttribute( "type", "unsubscribe" ) )
00141       {
00142         m_type = StanzaS10n;
00143         m_subtype = StanzaS10nUnsubscribe;
00144       }
00145       else if( hasAttribute( "type", "unsubscribed" ) )
00146       {
00147         m_type = StanzaS10n;
00148         m_subtype = StanzaS10nUnsubscribed;
00149       }
00150       else if( hasAttribute( "type", "unavailable" ) )
00151       {
00152         m_type = StanzaPresence;
00153         m_subtype = StanzaPresenceUnavailable;
00154       }
00155       else if( hasAttribute( "type", "probe" ) )
00156       {
00157         m_type = StanzaPresence;
00158         m_subtype = StanzaPresenceProbe;
00159       }
00160       else if( hasAttribute( "type", "error" ) )
00161       {
00162         m_type = StanzaPresence;
00163         m_subtype = StanzaPresenceError;
00164       }
00165       else if( !hasAttribute( "type" ) )
00166       {
00167         m_type = StanzaPresence;
00168         m_subtype = StanzaPresenceAvailable;
00169       }
00170       else
00171       {
00172         m_type = StanzaPresence;
00173         m_subtype = StanzaSubUndefined;
00174       }
00175     }
00176     else
00177     {
00178       m_type = StanzaUndefined;
00179       m_subtype = StanzaSubUndefined;
00180     }
00181 
00182     if( m_type == StanzaPresence )
00183     {
00184       if( !hasAttribute( "type" ) )
00185         m_presence = PresenceAvailable;
00186 
00187       if( hasChildWithCData( "show", "chat" ) )
00188         m_presence = PresenceChat;
00189       else if( hasChildWithCData( "show", "away" ) )
00190         m_presence = PresenceAway;
00191       else if( hasChildWithCData( "show", "dnd" ) )
00192         m_presence = PresenceDnd;
00193       else if( hasChildWithCData( "show", "xa" ) )
00194         m_presence = PresenceXa;
00195       else if( hasAttribute( "type", "unavailable" ) )
00196         m_presence = PresenceUnavailable;
00197 
00198       if( hasChild( "priority" ) )
00199         m_priority = atoi( findChild( "priority" )->cdata().c_str() );
00200     }
00201 
00202     if( m_type == StanzaPresence || m_type == StanzaS10n )
00203     {
00204       const TagList& c = children();
00205       TagList::const_iterator it = c.begin();
00206       for( ; it != c.end(); ++it )
00207       {
00208         if( (*it)->name() == "status" )
00209         {
00210           setLang( m_status, (*it) );
00211         }
00212         else
00213         {
00214           StanzaExtension *se = StanzaExtensionFactory::create( (*it) );
00215           if( se )
00216             m_extensionList.push_back( se );
00217         }
00218       }
00219     }
00220 
00221     m_xmllang = findAttribute( "xml:lang" );
00222 
00223     if( hasAttribute( "type", "error" ) && hasChild( "error" ) )
00224     {
00225       Tag *e = findChild( "error" );
00226 
00227       if( e->hasAttribute( "type", "cancel" ) )
00228         m_stanzaErrorType = StanzaErrorTypeCancel;
00229       else if( e->hasAttribute( "type", "continue" ) )
00230         m_stanzaErrorType = StanzaErrorTypeContinue;
00231       else if( e->hasAttribute( "type", "modify" ) )
00232         m_stanzaErrorType = StanzaErrorTypeModify;
00233       else if( e->hasAttribute( "type", "auth" ) )
00234         m_stanzaErrorType = StanzaErrorTypeAuth;
00235       else if( e->hasAttribute( "type", "wait" ) )
00236         m_stanzaErrorType = StanzaErrorTypeWait;
00237 
00238       const TagList& c = e->children();
00239       TagList::const_iterator it = c.begin();
00240       StanzaError err = StanzaErrorUndefined;
00241       for( ; it != c.end(); ++it )
00242       {
00243         if( (*it)->name() == "bad-request" )
00244           err = StanzaErrorBadRequest;
00245         else if( (*it)->name() == "conflict" )
00246           err = StanzaErrorConflict;
00247         else if( (*it)->name() == "feature-not-implemented" )
00248           err = StanzaErrorFeatureNotImplemented;
00249         else if( (*it)->name() == "forbidden" )
00250           err = StanzaErrorForbidden;
00251         else if( (*it)->name() == "gone" )
00252           err = StanzaErrorGone;
00253         else if( (*it)->name() == "internal-server-error" )
00254           err = StanzaErrorInternalServerError;
00255         else if( (*it)->name() == "item-not-found" )
00256           err = StanzaErrorItemNotFound;
00257         else if( (*it)->name() == "jid-malformed" )
00258           err = StanzaErrorJidMalformed;
00259         else if( (*it)->name() == "not-acceptable" )
00260           err = StanzaErrorNotAcceptable;
00261         else if( (*it)->name() == "not-allowed" )
00262           err = StanzaErrorNotAllowed;
00263         else if( (*it)->name() == "not-authorized" )
00264           err = StanzaErrorNotAuthorized;
00265         else if( (*it)->name() == "recipient-unavailable" )
00266           err = StanzaErrorRecipientUnavailable;
00267         else if( (*it)->name() == "redirect" )
00268           err = StanzaErrorRedirect;
00269         else if( (*it)->name() == "registration-required" )
00270           err = StanzaErrorRegistrationRequired;
00271         else if( (*it)->name() == "remote-server-not-found" )
00272           err = StanzaErrorRemoteServerNotFound;
00273         else if( (*it)->name() == "remote-server-timeout" )
00274           err = StanzaErrorRemoteServerTimeout;
00275         else if( (*it)->name() == "resource-constraint" )
00276           err = StanzaErrorResourceConstraint;
00277         else if( (*it)->name() == "service-unavailable" )
00278           err = StanzaErrorServiceUnavailable;
00279         else if( (*it)->name() == "subscription-required" )
00280           err = StanzaErrorSubscribtionRequired;
00281         else if( (*it)->name() == "undefined-condition" )
00282           err = StanzaErrorUndefinedCondition;
00283         else if( (*it)->name() == "unexpected-request" )
00284           err = StanzaErrorUnexpectedRequest;
00285         else if( (*it)->name() == "text" )
00286         {
00287           setLang( m_errorText, (*it) );
00288         }
00289         else {
00290           m_stanzaErrorAppCondition = (*it);
00291         }
00292 
00293         if( err != StanzaErrorUndefined && (*it)->hasAttribute( "xmlns", XMLNS_XMPP_STANZAS ) )
00294         {
00295           m_stanzaError = err;
00296         }
00297       }
00298     }
00299   }
00300 
00301   void Stanza::addExtension( StanzaExtension *se )
00302   {
00303     m_extensionList.push_back( se );
00304     addChild( se->tag() );
00305   }
00306 
00307   Stanza* Stanza::createIqStanza( const JID& to, const std::string& id,
00308                                   StanzaSubType subtype, const std::string& xmlns, Tag* tag )
00309   {
00310     Stanza *s = new Stanza( "iq" );
00311     switch( subtype )
00312     {
00313       case StanzaIqError:
00314         s->addAttribute( "type", "error" );
00315         break;
00316       case StanzaIqSet:
00317         s->addAttribute( "type", "set" );
00318         break;
00319       case StanzaIqResult:
00320         s->addAttribute( "type", "result" );
00321         break;
00322       case StanzaIqGet:
00323       default:
00324         s->addAttribute( "type", "get" );
00325         break;
00326     }
00327 
00328     if( !xmlns.empty() )
00329     {
00330       Tag *q = new Tag( s, "query" );
00331       q->addAttribute( "xmlns", xmlns );
00332       if( tag )
00333         q->addChild( tag );
00334     }
00335     s->addAttribute( "to", to.full() );
00336     s->addAttribute( "id", id );
00337 
00338     s->finalize();
00339 
00340     return s;
00341   }
00342 
00343   Stanza* Stanza::createPresenceStanza( const JID& to, const std::string& msg,
00344                                         Presence status, const std::string& xmllang )
00345   {
00346     Stanza *s = new Stanza( "presence" );
00347     switch( status )
00348     {
00349       case PresenceUnavailable:
00350         s->addAttribute( "type", "unavailable" );
00351         break;
00352       case PresenceChat:
00353         new Tag( s, "show", "chat" );
00354         break;
00355       case PresenceAway:
00356         new Tag( s, "show", "away" );
00357         break;
00358       case PresenceDnd:
00359         new Tag( s, "show", "dnd" );
00360         break;
00361       case PresenceXa:
00362         new Tag( s, "show", "xa" );
00363         break;
00364       default:
00365         break;
00366     }
00367 
00368     if( to )
00369       s->addAttribute( "to", to.full() );
00370 
00371     if( !msg.empty() )
00372     {
00373       Tag *t = new Tag( s, "status", msg );
00374       t->addAttribute( "xml:lang", xmllang );
00375     }
00376 
00377     s->finalize();
00378 
00379     return s;
00380   }
00381 
00382   Stanza* Stanza::createMessageStanza( const JID& to, const std::string& body,
00383                                        StanzaSubType subtype, const std::string& subject,
00384                                        const std::string& thread, const std::string& xmllang )
00385   {
00386     Stanza *s = new Stanza( "message" );
00387     switch( subtype )
00388     {
00389       case StanzaMessageError:
00390         s->addAttribute( "type", "error" );
00391         break;
00392       case StanzaMessageNormal:
00393         s->addAttribute( "type", "normal" );
00394         break;
00395       case StanzaMessageHeadline:
00396         s->addAttribute( "type", "headline" );
00397         break;
00398       case StanzaMessageGroupchat:
00399         s->addAttribute( "type", "groupchat" );
00400         break;
00401       case StanzaMessageChat:
00402       default:
00403         s->addAttribute( "type", "chat" );
00404         break;
00405     }
00406 
00407     s->addAttribute( "to", to.full() );
00408 
00409     if( !body.empty() )
00410     {
00411       Tag *b = new Tag( s, "body", body );
00412       b->addAttribute( "xml:lang", xmllang );
00413     }
00414     if( !subject.empty() )
00415     {
00416       Tag *su = new Tag( s, "subject", subject );
00417       su->addAttribute( "xml:lang", xmllang );
00418     }
00419     if( !thread.empty() )
00420       new Tag( s, "thread", thread );
00421 
00422     s->finalize();
00423 
00424     return s;
00425   }
00426 
00427   Stanza* Stanza::createSubscriptionStanza( const JID& to, const std::string& msg,
00428                                             StanzaSubType subtype, const std::string& xmllang )
00429   {
00430     Stanza *s = new Stanza( "presence" );
00431     switch( subtype )
00432     {
00433       case StanzaS10nSubscribed:
00434         s->addAttribute( "type", "subscribed" );
00435         break;
00436       case StanzaS10nUnsubscribe:
00437         s->addAttribute( "type", "unsubscribe" );
00438         break;
00439       case StanzaS10nUnsubscribed:
00440         s->addAttribute( "type", "unsubscribed" );
00441         break;
00442       case StanzaS10nSubscribe:
00443       default:
00444         s->addAttribute( "type", "subscribe" );
00445         break;
00446     }
00447 
00448     s->addAttribute( "to", to.full() );
00449     if( !msg.empty() )
00450     {
00451       Tag *t = new Tag( s, "status", msg );
00452       t->addAttribute( "xml:lang", xmllang );
00453     }
00454 
00455     s->finalize();
00456 
00457     return s;
00458   }
00459 
00460   void Stanza::setLang( StringMap& map, const Tag *tag )
00461   {
00462     const std::string& lang = tag->findAttribute( "xml:lang" );
00463     map[ lang.empty() ? "default" : lang ] = tag->cdata();
00464   }
00465 
00466   const std::string Stanza::findLang( const StringMap& map, const std::string& lang )
00467   {
00468     StringMap::const_iterator it = map.find( lang );
00469     return ( it != map.end() ) ? (*it).second : std::string();
00470   }
00471 
00472 }

Generated on Fri Oct 10 15:26:12 2008 for gloox by  doxygen 1.5.6