00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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 }