/* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "Swiften/Parser/XMPPParser.h" #include <iostream> #include <cassert> #include "Swiften/Elements/ProtocolHeader.h" #include "Swiften/Base/String.h" #include "Swiften/Parser/XMLParser.h" #include "Swiften/Parser/PlatformXMLParserFactory.h" #include "Swiften/Parser/XMPPParserClient.h" #include "Swiften/Parser/XMPPParser.h" #include "Swiften/Parser/ElementParser.h" #include "Swiften/Parser/PresenceParser.h" #include "Swiften/Parser/IQParser.h" #include "Swiften/Parser/MessageParser.h" #include "Swiften/Parser/StreamFeaturesParser.h" #include "Swiften/Parser/AuthRequestParser.h" #include "Swiften/Parser/AuthSuccessParser.h" #include "Swiften/Parser/AuthFailureParser.h" #include "Swiften/Parser/AuthChallengeParser.h" #include "Swiften/Parser/AuthResponseParser.h" #include "Swiften/Parser/EnableStreamManagementParser.h" #include "Swiften/Parser/StreamManagementEnabledParser.h" #include "Swiften/Parser/StreamManagementFailedParser.h" #include "Swiften/Parser/StanzaAckParser.h" #include "Swiften/Parser/StanzaAckRequestParser.h" #include "Swiften/Parser/StartTLSParser.h" #include "Swiften/Parser/StartTLSFailureParser.h" #include "Swiften/Parser/CompressParser.h" #include "Swiften/Parser/CompressFailureParser.h" #include "Swiften/Parser/CompressedParser.h" #include "Swiften/Parser/UnknownElementParser.h" #include "Swiften/Parser/TLSProceedParser.h" #include "Swiften/Parser/ComponentHandshakeParser.h" // TODO: Whenever an error occurs in the handlers, stop the parser by returing // a bool value, and stopping the XML parser namespace Swift { XMPPParser::XMPPParser( XMPPParserClient* client, PayloadParserFactoryCollection* payloadParserFactories) : xmlParser_(0), client_(client), payloadParserFactories_(payloadParserFactories), level_(0), currentElementParser_(0), parseErrorOccurred_(false) { xmlParser_ = PlatformXMLParserFactory().createXMLParser(this); } XMPPParser::~XMPPParser() { delete currentElementParser_; delete xmlParser_; } bool XMPPParser::parse(const String& data) { bool xmlParseResult = xmlParser_->parse(data); return xmlParseResult && !parseErrorOccurred_; } void XMPPParser::handleStartElement(const String& element, const String& ns, const AttributeMap& attributes) { if (level_ == TopLevel) { if (element == "stream" && ns == "http://etherx.jabber.org/streams") { ProtocolHeader header; header.setFrom(attributes.getAttribute("from")); header.setTo(attributes.getAttribute("to")); header.setID(attributes.getAttribute("id")); header.setVersion(attributes.getAttribute("version")); client_->handleStreamStart(header); } else { parseErrorOccurred_ = true; } } else { if (level_ == StreamLevel) { assert(!currentElementParser_); currentElementParser_ = createElementParser(element, ns); } currentElementParser_->handleStartElement(element, ns, attributes); } ++level_; } void XMPPParser::handleEndElement(const String& element, const String& ns) { assert(level_ > TopLevel); --level_; if (level_ == TopLevel) { assert(element == "stream"); client_->handleStreamEnd(); } else { assert(currentElementParser_); currentElementParser_->handleEndElement(element, ns); if (level_ == StreamLevel) { client_->handleElement(currentElementParser_->getElement()); delete currentElementParser_; currentElementParser_ = NULL; } } } void XMPPParser::handleCharacterData(const String& data) { if (currentElementParser_) { currentElementParser_->handleCharacterData(data); } //else { // std::cerr << "XMPPParser: Ignoring stray character data: " << data << std::endl; //} } ElementParser* XMPPParser::createElementParser(const String& element, const String& ns) { if (element == "presence") { return new PresenceParser(payloadParserFactories_); } else if (element == "iq") { return new IQParser(payloadParserFactories_); } else if (element == "message") { return new MessageParser(payloadParserFactories_); } else if (element == "features" && ns == "http://etherx.jabber.org/streams") { return new StreamFeaturesParser(); } else if (element == "auth") { return new AuthRequestParser(); } else if (element == "success") { return new AuthSuccessParser(); } else if (element == "failure" && ns == "urn:ietf:params:xml:ns:xmpp-sasl") { return new AuthFailureParser(); } else if (element == "challenge" && ns == "urn:ietf:params:xml:ns:xmpp-sasl") { return new AuthChallengeParser(); } else if (element == "response" && ns == "urn:ietf:params:xml:ns:xmpp-sasl") { return new AuthResponseParser(); } else if (element == "starttls") { return new StartTLSParser(); } else if (element == "failure" && ns == "urn:ietf:params:xml:ns:xmpp-tls") { return new StartTLSFailureParser(); } else if (element == "compress") { return new CompressParser(); } else if (element == "compressed") { return new CompressedParser(); } else if (element == "failure" && ns == "http://jabber.org/protocol/compress") { return new CompressFailureParser(); } else if (element == "proceed") { return new TLSProceedParser(); } else if (element == "enable" && ns == "urn:xmpp:sm:2") { return new EnableStreamManagementParser(); } else if (element == "enabled" && ns == "urn:xmpp:sm:2") { return new StreamManagementEnabledParser(); } else if (element == "failed" && ns == "urn:xmpp:sm:2") { return new StreamManagementFailedParser(); } else if (element == "a" && ns == "urn:xmpp:sm:2") { return new StanzaAckParser(); } else if (element == "r" && ns == "urn:xmpp:sm:2") { return new StanzaAckRequestParser(); } else if (element == "handshake") { return new ComponentHandshakeParser(); } return new UnknownElementParser(); } }