From ef5a4dc3a5b0224628a225ef0dccc679287478be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Tue, 14 Sep 2010 18:17:30 +0200 Subject: Add extended disco support to caps verifier. diff --git a/Swiften/Disco/CapsInfoGenerator.cpp b/Swiften/Disco/CapsInfoGenerator.cpp index 67ed979..94f2a7a 100644 --- a/Swiften/Disco/CapsInfoGenerator.cpp +++ b/Swiften/Disco/CapsInfoGenerator.cpp @@ -10,9 +10,16 @@ #include "Swiften/Base/foreach.h" #include "Swiften/Elements/DiscoInfo.h" +#include "Swiften/Elements/FormField.h" #include "Swiften/StringCodecs/SHA1.h" #include "Swiften/StringCodecs/Base64.h" +namespace { + bool compareFields(Swift::FormField::ref f1, Swift::FormField::ref f2) { + return f1->getName() < f2->getName(); + } +} + namespace Swift { CapsInfoGenerator::CapsInfoGenerator(const String& node) : node_(node) { @@ -33,6 +40,23 @@ CapsInfo CapsInfoGenerator::generateCapsInfo(const DiscoInfo& discoInfo) const { serializedCaps += feature + "<"; } + foreach(Form::ref extension, discoInfo.getExtensions()) { + serializedCaps += extension->getFormType() + "<"; + std::vector fields(extension->getFields()); + std::sort(fields.begin(), fields.end(), &compareFields); + foreach(FormField::ref field, fields) { + if (field->getName() == "FORM_TYPE") { + continue; + } + serializedCaps += field->getName() + "<"; + std::vector values(field->getRawValues()); + std::sort(values.begin(), values.end()); + foreach(const String& value, values) { + serializedCaps += value + "<"; + } + } + } + String version(Base64::encode(SHA1::getHash(serializedCaps))); return CapsInfo(node_, version, "sha-1"); } diff --git a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp index a8fe5b7..aec3a92 100644 --- a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp +++ b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp @@ -12,15 +12,13 @@ using namespace Swift; -class CapsInfoGeneratorTest : public CppUnit::TestFixture -{ +class CapsInfoGeneratorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CapsInfoGeneratorTest); CPPUNIT_TEST(testGenerate_XEP0115SimpleExample); + CPPUNIT_TEST(testGenerate_XEP0115ComplexExample); CPPUNIT_TEST_SUITE_END(); public: - CapsInfoGeneratorTest() {} - void testGenerate_XEP0115SimpleExample() { DiscoInfo discoInfo; discoInfo.addIdentity(DiscoInfo::Identity("Exodus 0.9.1", "client", "pc")); @@ -36,6 +34,51 @@ class CapsInfoGeneratorTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(String("sha-1"), result.getHash()); CPPUNIT_ASSERT_EQUAL(String("QgayPKawpkPSDYmwT/WM94uAlu0="), result.getVersion()); } + + void testGenerate_XEP0115ComplexExample() { + DiscoInfo discoInfo; + discoInfo.addIdentity(DiscoInfo::Identity("Psi 0.11", "client", "pc", "en")); + discoInfo.addIdentity(DiscoInfo::Identity("\xce\xa8 0.11", "client", "pc", "el")); + discoInfo.addFeature("http://jabber.org/protocol/disco#items"); + discoInfo.addFeature("http://jabber.org/protocol/caps"); + discoInfo.addFeature("http://jabber.org/protocol/disco#info"); + discoInfo.addFeature("http://jabber.org/protocol/muc"); + + Form::ref extension(new Form(Form::ResultType)); + FormField::ref field = HiddenFormField::create("urn:xmpp:dataforms:softwareinfo"); + field->setName("FORM_TYPE"); + extension->addField(field); + std::vector ipVersions; + ipVersions.push_back("ipv6"); + ipVersions.push_back("ipv4"); + field = ListMultiFormField::create(ipVersions); + field->addRawValue("ipv6"); + field->addRawValue("ipv4"); + field->setName("ip_version"); + extension->addField(field); + field = TextSingleFormField::create("Psi"); + field->addRawValue("Psi"); + field->setName("software"); + extension->addField(field); + field = TextSingleFormField::create("0.11"); + field->addRawValue("0.11"); + field->setName("software_version"); + extension->addField(field); + field = TextSingleFormField::create("Mac"); + field->setName("os"); + field->addRawValue("Mac"); + extension->addField(field); + field = TextSingleFormField::create("10.5.1"); + field->setName("os_version"); + field->addRawValue("10.5.1"); + extension->addField(field); + discoInfo.addExtension(extension); + + CapsInfoGenerator testling("http://psi-im.org"); + CapsInfo result = testling.generateCapsInfo(discoInfo); + + CPPUNIT_ASSERT_EQUAL(String("q07IKJEyjvHSyhy//CH0CxmKi8w="), result.getVersion()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(CapsInfoGeneratorTest); diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h index cee9200..2cc914a 100644 --- a/Swiften/Elements/DiscoInfo.h +++ b/Swiften/Elements/DiscoInfo.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_DiscoInfo_H -#define SWIFTEN_DiscoInfo_H +#pragma once #include #include @@ -13,6 +12,7 @@ #include "Swiften/Elements/Payload.h" #include "Swiften/Base/String.h" #include "Swiften/Base/Shared.h" +#include "Swiften/Elements/Form.h" namespace Swift { class DiscoInfo : public Payload, public Shared { @@ -60,7 +60,7 @@ namespace Swift { node_ = node; } - const std::vector getIdentities() const { + const std::vector& getIdentities() const { return identities_; } @@ -80,11 +80,18 @@ namespace Swift { return std::find(features_.begin(), features_.end(), feature) != features_.end(); } + void addExtension(Form::ref form) { + extensions_.push_back(form); + } + + const std::vector getExtensions() const { + return extensions_; + } + private: String node_; std::vector identities_; std::vector features_; + std::vector extensions_; }; } - -#endif diff --git a/Swiften/Elements/Form.cpp b/Swiften/Elements/Form.cpp new file mode 100644 index 0000000..9420fb9 --- /dev/null +++ b/Swiften/Elements/Form.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Elements/Form.h" +#include "Swiften/Base/foreach.h" + +namespace Swift { + +String Form::getFormType() const { + foreach(FormField::ref field, fields_) { + boost::shared_ptr f = boost::dynamic_pointer_cast(field); + if (f && f->getName() == "FORM_TYPE") { + return f->getValue(); + } + } + return ""; +} + +} diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h index 34068ee..f5826a5 100644 --- a/Swiften/Elements/Form.h +++ b/Swiften/Elements/Form.h @@ -38,6 +38,8 @@ namespace Swift { Type getType() { return type_; } void setType(Type type) { type_ = type; } + String getFormType() const; + private: std::vector > fields_; String title_; diff --git a/Swiften/Elements/FormField.h b/Swiften/Elements/FormField.h index 732203a..a0240e1 100644 --- a/Swiften/Elements/FormField.h +++ b/Swiften/Elements/FormField.h @@ -4,6 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ +// FIXME: We currently keep 2 values: the raw values, and the actual value. +// We should only store the raw values, and deduce the actual values from this + #pragma once #include @@ -45,6 +48,14 @@ namespace Swift { return options; } + const std::vector getRawValues() const { + return rawValues; + } + + void addRawValue(const String& value) { + rawValues.push_back(value); + } + protected: FormField() : required(false) {} @@ -54,6 +65,7 @@ namespace Swift { String description; bool required; std::vector