diff options
author | Remko Tronçon <git@el-tramo.be> | 2010-10-17 12:13:36 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2010-10-21 18:25:00 (GMT) |
commit | 1b58ef2af54456004390a0888c3edf104e3baa99 (patch) | |
tree | dbe4ae29de1b765a88ea704dfaa1c03af4b196b3 /Swiften/Parser/PayloadParsers | |
parent | 07402c4e3451f2084a1c3ddc5bacfb38a66899a7 (diff) | |
download | swift-1b58ef2af54456004390a0888c3edf104e3baa99.zip swift-1b58ef2af54456004390a0888c3edf104e3baa99.tar.bz2 |
Added beginnings of outgoing file transfer to Swiften.
Diffstat (limited to 'Swiften/Parser/PayloadParsers')
12 files changed, 516 insertions, 0 deletions
diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp new file mode 100644 index 0000000..154a925 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp @@ -0,0 +1,48 @@ +/* + * 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/PayloadParsers/BytestreamsParser.h" + +#include <boost/lexical_cast.hpp> + +#include "Swiften/Base/foreach.h" + +namespace Swift { + +BytestreamsParser::BytestreamsParser() : level(TopLevel) { +} + +BytestreamsParser::~BytestreamsParser() { +} + +void BytestreamsParser::handleStartElement(const String& element, const String&, const AttributeMap& attributes) { + if (level == TopLevel) { + getPayloadInternal()->setStreamID(attributes.getAttribute("sid")); + } + else if (level == PayloadLevel) { + if (element == "streamhost") { + try { + getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::lexical_cast<int>(attributes.getAttribute("port")))); + } + catch (boost::bad_lexical_cast& e) { + } + } + else if (element == "streamhost-used") { + getPayloadInternal()->setUsedStreamHost(JID(attributes.getAttribute("jid"))); + } + } + ++level; +} + +void BytestreamsParser::handleEndElement(const String&, const String&) { + --level; +} + +void BytestreamsParser::handleCharacterData(const String&) { +} + + +} diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.h b/Swiften/Parser/PayloadParsers/BytestreamsParser.h new file mode 100644 index 0000000..a45baa4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include "Swiften/Elements/Bytestreams.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class BytestreamsParser : public GenericPayloadParser<Bytestreams> { + public: + BytestreamsParser(); + ~BytestreamsParser(); + + virtual void handleStartElement(const String& element, const String&, const AttributeMap& attributes); + virtual void handleEndElement(const String& element, const String&); + virtual void handleCharacterData(const String& data); + + private: + enum Level { + TopLevel = 0, + PayloadLevel = 1, + }; + int level; + }; +} diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h b/Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h new file mode 100644 index 0000000..8defd45 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/Parser/GenericPayloadParserFactory.h" +#include "Swiften/Parser/PayloadParsers/BytestreamsParser.h" + +namespace Swift { + class BytestreamsParserFactory : public GenericPayloadParserFactory<BytestreamsParser> { + public: + BytestreamsParserFactory() : GenericPayloadParserFactory<BytestreamsParser>("query", "http://jabber.org/protocol/bytestreams") {} + }; +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index de0e71c..90e9038 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -27,6 +27,9 @@ #include "Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h" #include "Swiften/Parser/PayloadParsers/FormParserFactory.h" #include "Swiften/Parser/PayloadParsers/CommandParserFactory.h" +#include "Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h" +#include "Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h" +#include "Swiften/Parser/PayloadParsers/IBBParserFactory.h" #include "Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h" #include "Swiften/Parser/PayloadParsers/VCardParserFactory.h" #include "Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h" @@ -40,6 +43,7 @@ using namespace boost; namespace Swift { FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { + factories_.push_back(shared_ptr<PayloadParserFactory>(new IBBParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new StatusParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new StatusShowParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new BodyParserFactory())); @@ -58,6 +62,8 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(shared_ptr<PayloadParserFactory>(new SecurityLabelsCatalogParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new FormParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new CommandParserFactory())); + factories_.push_back(shared_ptr<PayloadParserFactory>(new StreamInitiationParserFactory())); + factories_.push_back(shared_ptr<PayloadParserFactory>(new BytestreamsParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new VCardUpdateParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new VCardParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new PrivateStorageParserFactory(this))); diff --git a/Swiften/Parser/PayloadParsers/IBBParser.cpp b/Swiften/Parser/PayloadParsers/IBBParser.cpp new file mode 100644 index 0000000..b2b4929 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/IBBParser.cpp @@ -0,0 +1,77 @@ +/* + * 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/PayloadParsers/IBBParser.h" + +#include <boost/lexical_cast.hpp> + +#include "Swiften/Base/foreach.h" +#include "Swiften/StringCodecs/Base64.h" + +namespace Swift { + +IBBParser::IBBParser() : level(TopLevel) { +} + +IBBParser::~IBBParser() { +} + +void IBBParser::handleStartElement(const String& element, const String&, const AttributeMap& attributes) { + if (level == TopLevel) { + if (element == "data") { + getPayloadInternal()->setAction(IBB::Data); + getPayloadInternal()->setStreamID(attributes.getAttribute("sid")); + try { + getPayloadInternal()->setSequenceNumber(boost::lexical_cast<int>(attributes.getAttribute("seq"))); + } + catch (boost::bad_lexical_cast& e) { + } + } + else if (element == "open") { + getPayloadInternal()->setAction(IBB::Open); + getPayloadInternal()->setStreamID(attributes.getAttribute("sid")); + if (attributes.getAttribute("stanza") == "message") { + getPayloadInternal()->setStanzaType(IBB::MessageStanza); + } + else { + getPayloadInternal()->setStanzaType(IBB::IQStanza); + } + try { + getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttribute("block-size"))); + } + catch (boost::bad_lexical_cast& e) { + } + } + else if (element == "close") { + getPayloadInternal()->setAction(IBB::Close); + getPayloadInternal()->setStreamID(attributes.getAttribute("sid")); + } + } + ++level; +} + +void IBBParser::handleEndElement(const String& element, const String&) { + --level; + if (level == TopLevel) { + if (element == "data") { + std::vector<char> data; + for (size_t i = 0; i < currentText.getUTF8Size(); ++i) { + char c = currentText[i]; + if (c >= 48 && c <= 122) { + data.push_back(c); + } + } + getPayloadInternal()->setData(Base64::decode(String(&data[0], data.size()))); + } + } +} + +void IBBParser::handleCharacterData(const String& data) { + currentText += data; +} + + +} diff --git a/Swiften/Parser/PayloadParsers/IBBParser.h b/Swiften/Parser/PayloadParsers/IBBParser.h new file mode 100644 index 0000000..1fc062f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/IBBParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include "Swiften/Elements/IBB.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class IBBParser : public GenericPayloadParser<IBB> { + public: + IBBParser(); + ~IBBParser(); + + virtual void handleStartElement(const String& element, const String&, const AttributeMap& attributes); + virtual void handleEndElement(const String& element, const String&); + virtual void handleCharacterData(const String& data); + + private: + enum Level { + TopLevel = 0, + }; + int level; + String currentText; + }; +} diff --git a/Swiften/Parser/PayloadParsers/IBBParserFactory.h b/Swiften/Parser/PayloadParsers/IBBParserFactory.h new file mode 100644 index 0000000..aa323f7 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/IBBParserFactory.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/Parser/GenericPayloadParserFactory.h" +#include "Swiften/Parser/PayloadParsers/IBBParser.h" + +namespace Swift { + class IBBParserFactory : public GenericPayloadParserFactory<IBBParser> { + public: + IBBParserFactory() : GenericPayloadParserFactory<IBBParser>("", "http://jabber.org/protocol/ibb") {} + }; +} diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp new file mode 100644 index 0000000..76925af --- /dev/null +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp @@ -0,0 +1,117 @@ +/* + * 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/PayloadParsers/StreamInitiationParser.h" + +#include <boost/lexical_cast.hpp> + +#include "Swiften/Parser/PayloadParsers/FormParserFactory.h" +#include "Swiften/Parser/PayloadParsers/FormParser.h" +#include "Swiften/Base/foreach.h" + + +#define FILE_TRANSFER_NS "http://jabber.org/protocol/si/profile/file-transfer" +#define FEATURE_NEG_NS "http://jabber.org/protocol/feature-neg" + +namespace Swift { + +StreamInitiationParser::StreamInitiationParser() : level(TopLevel), formParser(0), inFile(false), inFeature(false) { + formParserFactory = new FormParserFactory(); +} + +StreamInitiationParser::~StreamInitiationParser() { + delete formParserFactory; +} + +void StreamInitiationParser::handleStartElement(const String& element, const String& ns, const AttributeMap& attributes) { + if (level == TopLevel) { + getPayloadInternal()->setID(attributes.getAttribute("id")); + if (!attributes.getAttribute("profile").isEmpty()) { + getPayloadInternal()->setIsFileTransfer(attributes.getAttribute("profile") == FILE_TRANSFER_NS); + } + } + else if (level == PayloadLevel) { + if (element == "file") { + inFile = true; + currentFile = StreamInitiation::FileInfo(); + currentFile.name = attributes.getAttribute("name"); + try { + currentFile.size = boost::lexical_cast<int>(attributes.getAttribute("size")); + } + catch (boost::bad_lexical_cast& e) { + } + } + else if (element == "feature" && ns == FEATURE_NEG_NS) { + inFeature = true; + } + } + else if (level == FileOrFeatureLevel) { + if (inFile && element == "desc") { + currentText.clear(); + } + else if (inFeature && formParserFactory->canParse(element, ns, attributes)) { + formParser = dynamic_cast<FormParser*>(formParserFactory->createPayloadParser()); + } + } + + if (formParser) { + formParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void StreamInitiationParser::handleEndElement(const String& element, const String& ns) { + --level; + if (formParser) { + formParser->handleEndElement(element, ns); + } + if (level == TopLevel) { + } + else if (level == PayloadLevel) { + if (element == "file") { + getPayloadInternal()->setFileInfo(currentFile); + inFile = false; + } + else if (element == "feature" && ns == FEATURE_NEG_NS) { + inFeature = false; + } + } + else if (level == FileOrFeatureLevel) { + if (inFile && element == "desc") { + currentFile.description = currentText; + } + else if (formParser) { + Form::ref form = formParser->getPayloadInternal(); + if (form) { + FormField::ref field = boost::dynamic_pointer_cast<FormField>(form->getField("stream-method")); + if (field) { + if (form->getType() == Form::FormType) { + foreach (const FormField::Option& option, field->getOptions()) { + getPayloadInternal()->addProvidedMethod(option.value); + } + } + else if (form->getType() == Form::SubmitType) { + if (field->getRawValues().size() > 0) { + getPayloadInternal()->setRequestedMethod(field->getRawValues()[0]); + } + } + } + } + } + } +} + +void StreamInitiationParser::handleCharacterData(const String& data) { + if (formParser) { + formParser->handleCharacterData(data); + } + else { + currentText += data; + } +} + + +} diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.h b/Swiften/Parser/PayloadParsers/StreamInitiationParser.h new file mode 100644 index 0000000..f01567e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include "Swiften/Elements/StreamInitiation.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class FormParserFactory; + class FormParser; + + class StreamInitiationParser : public GenericPayloadParser<StreamInitiation> { + public: + StreamInitiationParser(); + ~StreamInitiationParser(); + + virtual void handleStartElement(const String& element, const String&, const AttributeMap& attributes); + virtual void handleEndElement(const String& element, const String&); + virtual void handleCharacterData(const String& data); + + private: + enum Level { + TopLevel = 0, + PayloadLevel = 1, + FileOrFeatureLevel = 2, + FormOrDescriptionLevel = 3, + }; + int level; + FormParserFactory* formParserFactory; + FormParser* formParser; + bool inFile; + bool inFeature; + StreamInitiation::FileInfo currentFile; + String currentText; + }; +} diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h b/Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h new file mode 100644 index 0000000..ee5ed09 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/Parser/GenericPayloadParserFactory.h" +#include "Swiften/Parser/PayloadParsers/StreamInitiationParser.h" + +namespace Swift { + class StreamInitiationParserFactory : public GenericPayloadParserFactory<StreamInitiationParser> { + public: + StreamInitiationParserFactory() : GenericPayloadParserFactory<StreamInitiationParser>("si", "http://jabber.org/protocol/si") {} + }; +} diff --git a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp new file mode 100644 index 0000000..f892deb --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include "Swiften/Elements/IBB.h" + +using namespace Swift; + +class IBBParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(IBBParserTest); + CPPUNIT_TEST(testParse_Data); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse_Data() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse( + "<data xmlns='http://jabber.org/protocol/ibb' seq='4'>\n" + "\t YWJjZGVmZ2loamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjEyMzQ1\n" + "\t Njc4OTAK\n" + "</data>" + )); + + IBB::ref ibb = parser.getPayload<IBB>(); + CPPUNIT_ASSERT(ibb->getAction() == IBB::Data); + CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a"), ibb->getData()); + CPPUNIT_ASSERT_EQUAL(4, ibb->getSequenceNumber()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(IBBParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/StreamInitiationParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/StreamInitiationParserTest.cpp new file mode 100644 index 0000000..ca8e353 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/StreamInitiationParserTest.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include "Swiften/Elements/StreamInitiation.h" + +using namespace Swift; + +class StreamInitiationParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(StreamInitiationParserTest); + CPPUNIT_TEST(testParse_Request); + CPPUNIT_TEST(testParse_Response); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse_Request() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse( + "<si xmlns='http://jabber.org/protocol/si' id='a0' mime-type='text/plain' profile='http://jabber.org/protocol/si/profile/file-transfer'>" + "<file xmlns='http://jabber.org/protocol/si/profile/file-transfer' name='test.txt' size='1022'>" + "<desc>This is info about the file.</desc>" + "</file>" + "<feature xmlns='http://jabber.org/protocol/feature-neg'>" + "<x xmlns='jabber:x:data' type='form'>" + "<field var='stream-method' type='list-single'>" + "<option><value>http://jabber.org/protocol/bytestreams</value></option>" + "<option><value>jabber:iq:oob</value></option>" + "<option><value>http://jabber.org/protocol/ibb</value></option>" + "</field>" + "</x>" + "</feature>" + "</si>" + )); + + StreamInitiation::ref si = parser.getPayload<StreamInitiation>(); + CPPUNIT_ASSERT(si->getIsFileTransfer()); + CPPUNIT_ASSERT(si->getFileInfo()); + CPPUNIT_ASSERT_EQUAL(String("test.txt"), si->getFileInfo()->name); + CPPUNIT_ASSERT_EQUAL(1022, si->getFileInfo()->size); + CPPUNIT_ASSERT_EQUAL(String("This is info about the file."), si->getFileInfo()->description); + CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(si->getProvidedMethods().size())); + CPPUNIT_ASSERT_EQUAL(String("http://jabber.org/protocol/bytestreams"), si->getProvidedMethods()[0]); + CPPUNIT_ASSERT_EQUAL(String("jabber:iq:oob"), si->getProvidedMethods()[1]); + CPPUNIT_ASSERT_EQUAL(String("http://jabber.org/protocol/ibb"), si->getProvidedMethods()[2]); + } + + void testParse_Response() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse( + "<si xmlns='http://jabber.org/protocol/si'>" + "<feature xmlns='http://jabber.org/protocol/feature-neg'>" + "<x xmlns='jabber:x:data' type='submit'>" + "<field var='stream-method'>" + "<value>http://jabber.org/protocol/bytestreams</value>" + "</field>" + "</x>" + "</feature>" + "</si>" + )); + + StreamInitiation::ref si = parser.getPayload<StreamInitiation>(); + CPPUNIT_ASSERT(si->getIsFileTransfer()); + CPPUNIT_ASSERT_EQUAL(String("http://jabber.org/protocol/bytestreams"), si->getRequestedMethod()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(StreamInitiationParserTest); |