/*
* 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 <string>
#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/StreamErrorParser.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 std::string& data) {
bool xmlParseResult = xmlParser_->parse(data);
return xmlParseResult && !parseErrorOccurred_;
}
void XMPPParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) {
if (!parseErrorOccurred_) {
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 std::string& element, const std::string& ns) {
assert(level_ > TopLevel);
--level_;
if (!parseErrorOccurred_) {
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 std::string& data) {
if (!parseErrorOccurred_) {
if (currentElementParser_) {
currentElementParser_->handleCharacterData(data);
}
//else {
// std::cerr << "XMPPParser: Ignoring stray character data: " << data << std::endl;
//}
}
}
ElementParser* XMPPParser::createElementParser(const std::string& element, const std::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 == "error" && ns == "http://etherx.jabber.org/streams") {
return new StreamErrorParser();
}
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();
}
}