diff options
Diffstat (limited to 'Swiften')
1113 files changed, 30042 insertions, 7299 deletions
diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.h b/Swiften/AdHoc/OutgoingAdHocCommandSession.h index 7c7cc99..74d6c59 100644 --- a/Swiften/AdHoc/OutgoingAdHocCommandSession.h +++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.h @@ -11,4 +11,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <Swiften/Base/boost_bsignals.h> @@ -22,5 +23,5 @@ namespace Swift { class UIEventStream; - class OutgoingAdHocCommandSession { + class SWIFTEN_API OutgoingAdHocCommandSession { public: diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h index 3461973..1e92328 100644 --- a/Swiften/Avatars/AvatarManager.h +++ b/Swiften/Avatars/AvatarManager.h @@ -9,4 +9,5 @@ #include <boost/filesystem/path.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/ByteArray.h> @@ -15,5 +16,5 @@ namespace Swift { class JID; - class AvatarManager { + class SWIFTEN_API AvatarManager { public: virtual ~AvatarManager(); diff --git a/Swiften/Avatars/AvatarManagerImpl.cpp b/Swiften/Avatars/AvatarManagerImpl.cpp index 78d94dc..3aaae33 100644 --- a/Swiften/Avatars/AvatarManagerImpl.cpp +++ b/Swiften/Avatars/AvatarManagerImpl.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,9 +17,9 @@ namespace Swift { -AvatarManagerImpl::AvatarManagerImpl(VCardManager* vcardManager, StanzaChannel* stanzaChannel, AvatarStorage* avatarStorage, MUCRegistry* mucRegistry) : avatarStorage(avatarStorage) { - vcardUpdateAvatarManager = new VCardUpdateAvatarManager(vcardManager, stanzaChannel, avatarStorage, mucRegistry); +AvatarManagerImpl::AvatarManagerImpl(VCardManager* vcardManager, StanzaChannel* stanzaChannel, AvatarStorage* avatarStorage, CryptoProvider* crypto, MUCRegistry* mucRegistry) : avatarStorage(avatarStorage) { + vcardUpdateAvatarManager = new VCardUpdateAvatarManager(vcardManager, stanzaChannel, avatarStorage, crypto, mucRegistry); combinedAvatarProvider.addProvider(vcardUpdateAvatarManager); - vcardAvatarManager = new VCardAvatarManager(vcardManager, avatarStorage, mucRegistry); + vcardAvatarManager = new VCardAvatarManager(vcardManager, avatarStorage, crypto, mucRegistry); combinedAvatarProvider.addProvider(vcardAvatarManager); @@ -42,7 +42,7 @@ AvatarManagerImpl::~AvatarManagerImpl() { boost::filesystem::path AvatarManagerImpl::getAvatarPath(const JID& jid) const { - std::string hash = combinedAvatarProvider.getAvatarHash(jid); - if (!hash.empty()) { - return avatarStorage->getAvatarPath(hash); + boost::optional<std::string> hash = combinedAvatarProvider.getAvatarHash(jid); + if (hash && !hash->empty()) { + return avatarStorage->getAvatarPath(*hash); } return boost::filesystem::path(); @@ -50,7 +50,7 @@ boost::filesystem::path AvatarManagerImpl::getAvatarPath(const JID& jid) const { ByteArray AvatarManagerImpl::getAvatar(const JID& jid) const { - std::string hash = combinedAvatarProvider.getAvatarHash(jid); - if (!hash.empty()) { - return avatarStorage->getAvatar(hash); + boost::optional<std::string> hash = combinedAvatarProvider.getAvatarHash(jid); + if (hash && !hash->empty()) { + return avatarStorage->getAvatar(*hash); } return ByteArray(); @@ -58,5 +58,7 @@ ByteArray AvatarManagerImpl::getAvatar(const JID& jid) const { void AvatarManagerImpl::handleCombinedAvatarChanged(const JID& jid) { - offlineAvatarManager->setAvatar(jid, combinedAvatarProvider.getAvatarHash(jid)); + boost::optional<std::string> hash = combinedAvatarProvider.getAvatarHash(jid); + assert(hash); + offlineAvatarManager->setAvatar(jid, *hash); onAvatarChanged(jid); } diff --git a/Swiften/Avatars/AvatarManagerImpl.h b/Swiften/Avatars/AvatarManagerImpl.h index c2b8956..4f59fe5 100644 --- a/Swiften/Avatars/AvatarManagerImpl.h +++ b/Swiften/Avatars/AvatarManagerImpl.h @@ -18,8 +18,9 @@ namespace Swift { class VCardAvatarManager; class OfflineAvatarManager; + class CryptoProvider; class AvatarManagerImpl : public AvatarManager { public: - AvatarManagerImpl(VCardManager*, StanzaChannel*, AvatarStorage*, MUCRegistry* = NULL); + AvatarManagerImpl(VCardManager*, StanzaChannel*, AvatarStorage*, CryptoProvider* crypto, MUCRegistry* = NULL); virtual ~AvatarManagerImpl(); diff --git a/Swiften/Avatars/AvatarProvider.h b/Swiften/Avatars/AvatarProvider.h index d2d408e..3606376 100644 --- a/Swiften/Avatars/AvatarProvider.h +++ b/Swiften/Avatars/AvatarProvider.h @@ -9,4 +9,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> @@ -14,9 +15,9 @@ namespace Swift { class JID; - class AvatarProvider { + class SWIFTEN_API AvatarProvider { public: virtual ~AvatarProvider(); - virtual std::string getAvatarHash(const JID&) const = 0; + virtual boost::optional<std::string> getAvatarHash(const JID&) const = 0; boost::signal<void (const JID&)> onAvatarChanged; diff --git a/Swiften/Avatars/AvatarStorage.h b/Swiften/Avatars/AvatarStorage.h index c33d38b..7f61ca2 100644 --- a/Swiften/Avatars/AvatarStorage.h +++ b/Swiften/Avatars/AvatarStorage.h @@ -9,4 +9,6 @@ #include <boost/filesystem/path.hpp> #include <string> + +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> @@ -14,5 +16,5 @@ namespace Swift { class JID; - class AvatarStorage { + class SWIFTEN_API AvatarStorage { public: virtual ~AvatarStorage(); diff --git a/Swiften/Avatars/CombinedAvatarProvider.cpp b/Swiften/Avatars/CombinedAvatarProvider.cpp index d283664..30f9f52 100644 --- a/Swiften/Avatars/CombinedAvatarProvider.cpp +++ b/Swiften/Avatars/CombinedAvatarProvider.cpp @@ -14,5 +14,5 @@ namespace Swift { -std::string CombinedAvatarProvider::getAvatarHash(const JID& jid) const { +boost::optional<std::string> CombinedAvatarProvider::getAvatarHash(const JID& jid) const { return getCombinedAvatarAndCache(jid); } @@ -37,19 +37,23 @@ void CombinedAvatarProvider::handleAvatarChanged(const JID& jid) { oldHash = i->second; } - std::string newHash = getCombinedAvatarAndCache(jid); + boost::optional<std::string> newHash = getCombinedAvatarAndCache(jid); if (newHash != oldHash) { - SWIFT_LOG(debug) << "Avatar changed: " << jid << ": " << oldHash << " -> " << newHash << std::endl; + SWIFT_LOG(debug) << "Avatar changed: " << jid << ": " << oldHash << " -> " << (newHash ? newHash.get() : "NULL") << std::endl; onAvatarChanged(jid); } } -std::string CombinedAvatarProvider::getCombinedAvatarAndCache(const JID& jid) const { +boost::optional<std::string> CombinedAvatarProvider::getCombinedAvatarAndCache(const JID& jid) const { SWIFT_LOG(debug) << "JID: " << jid << std::endl; - std::string hash; - for (size_t i = 0; i < providers.size() && hash.empty(); ++i) { + boost::optional<std::string> hash; + for (size_t i = 0; i < providers.size() && !hash; ++i) { hash = providers[i]->getAvatarHash(jid); - SWIFT_LOG(debug) << "Provider " << providers[i] << ": " << hash << std::endl; + SWIFT_LOG(debug) << "Provider " << providers[i] << ": " << (hash ? hash.get() : "NULL") << std::endl; + } + if (hash) { + avatars[jid] = *hash; + } else { + avatars[jid] = ""; } - avatars[jid] = hash; return hash; } diff --git a/Swiften/Avatars/CombinedAvatarProvider.h b/Swiften/Avatars/CombinedAvatarProvider.h index 7b29efc..ec06e72 100644 --- a/Swiften/Avatars/CombinedAvatarProvider.h +++ b/Swiften/Avatars/CombinedAvatarProvider.h @@ -10,11 +10,12 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Avatars/AvatarProvider.h> #include <Swiften/JID/JID.h> namespace Swift { - class CombinedAvatarProvider : public AvatarProvider { + class SWIFTEN_API CombinedAvatarProvider : public AvatarProvider { public: - virtual std::string getAvatarHash(const JID&) const; + virtual boost::optional<std::string> getAvatarHash(const JID&) const; void addProvider(AvatarProvider*); @@ -23,5 +24,5 @@ namespace Swift { private: void handleAvatarChanged(const JID&); - std::string getCombinedAvatarAndCache(const JID&) const; + boost::optional<std::string> getCombinedAvatarAndCache(const JID&) const; private: diff --git a/Swiften/Avatars/OfflineAvatarManager.cpp b/Swiften/Avatars/OfflineAvatarManager.cpp index 02c6a35..8492e86 100644 --- a/Swiften/Avatars/OfflineAvatarManager.cpp +++ b/Swiften/Avatars/OfflineAvatarManager.cpp @@ -19,5 +19,5 @@ OfflineAvatarManager::~OfflineAvatarManager() { } -std::string OfflineAvatarManager::getAvatarHash(const JID& jid) const { +boost::optional<std::string> OfflineAvatarManager::getAvatarHash(const JID& jid) const { return avatarStorage->getAvatarForJID(jid); } diff --git a/Swiften/Avatars/OfflineAvatarManager.h b/Swiften/Avatars/OfflineAvatarManager.h index 2098990..baceae8 100644 --- a/Swiften/Avatars/OfflineAvatarManager.h +++ b/Swiften/Avatars/OfflineAvatarManager.h @@ -17,5 +17,5 @@ namespace Swift { ~OfflineAvatarManager(); - virtual std::string getAvatarHash(const JID&) const; + virtual boost::optional<std::string> getAvatarHash(const JID&) const; void setAvatar(const JID&, const std::string& hash); diff --git a/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp b/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp new file mode 100644 index 0000000..9b7515d --- /dev/null +++ b/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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 <boost/bind.hpp> + +#include <Swiften/JID/JID.h> +#include <string> +#include <Swiften/Avatars/AvatarManagerImpl.h> +#include <Swiften/Avatars/CombinedAvatarProvider.h> +#include <Swiften/Avatars/VCardAvatarManager.h> +#include <Swiften/Avatars/OfflineAvatarManager.h> +#include <Swiften/Elements/VCardUpdate.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Avatars/AvatarMemoryStorage.h> +#include <Swiften/VCards/VCardMemoryStorage.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/Avatars/VCardUpdateAvatarManager.h> +#include <Swiften/StringCodecs/Hexify.h> + +using namespace Swift; + +class AvatarManagerImplTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(AvatarManagerImplTest); + CPPUNIT_TEST(testGetSetAvatar); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + ownerJID = JID("owner@domain.com/theowner"); + stanzaChannel = boost::make_shared<DummyStanzaChannel>(); + iqRouter = boost::make_shared<IQRouter>(stanzaChannel.get()); + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + vcardStorage = boost::make_shared<VCardMemoryStorage>(crypto.get()); + vcardManager = boost::make_shared<VCardManager>(ownerJID, iqRouter.get(), vcardStorage.get()); + avatarStorage = boost::make_shared<AvatarMemoryStorage>(); + mucRegistry = boost::make_shared<DummyMUCRegistry>(); + avatarManager = boost::make_shared<AvatarManagerImpl>(vcardManager.get(), stanzaChannel.get(), avatarStorage.get(), crypto.get(), mucRegistry.get()); + } + + void testGetSetAvatar() { + /* initially we have no knowledge of the user or their avatar */ + JID personJID("person@domain.com/theperson"); + ByteArray avatar = avatarManager->getAvatar(personJID.toBare()); + CPPUNIT_ASSERT(!avatar.size()); + + /* notify the 'owner' JID that our avatar has changed */ + + ByteArray fullAvatar = createByteArray("abcdefg"); + boost::shared_ptr<VCardUpdate> vcardUpdate = boost::make_shared<VCardUpdate>(); + vcardUpdate->setPhotoHash(Hexify::hexify(crypto->getSHA1Hash(fullAvatar))); + boost::shared_ptr<Presence> presence = boost::make_shared<Presence>(); + presence->setTo(ownerJID); + presence->setFrom(personJID); + presence->setType(Presence::Available); + presence->addPayload(vcardUpdate); + stanzaChannel->onPresenceReceived(presence); + + /* reply to the avatar request with our new avatar */ + + CPPUNIT_ASSERT_EQUAL(size_t(1), stanzaChannel->sentStanzas.size()); + boost::shared_ptr<IQ> request = boost::dynamic_pointer_cast<IQ>(stanzaChannel->sentStanzas[0]); + stanzaChannel->sentStanzas.pop_back(); + CPPUNIT_ASSERT(!!request); + boost::shared_ptr<VCard> vcard = request->getPayload<VCard>(); + CPPUNIT_ASSERT(!!vcard); + + boost::shared_ptr<IQ> reply = boost::make_shared<IQ>(IQ::Result); + reply->setTo(request->getFrom()); + reply->setFrom(request->getTo()); + reply->setID(request->getID()); + vcard->setPhoto(fullAvatar); + reply->addPayload(vcard); + stanzaChannel->onIQReceived(reply); + + /* check hash through avatarManager that it received the correct photo */ + + ByteArray reportedAvatar = avatarManager->getAvatar(personJID.toBare()); + CPPUNIT_ASSERT_EQUAL(byteArrayToString(fullAvatar), byteArrayToString(reportedAvatar)); + + /* send new presence to notify of blank avatar */ + + vcardUpdate = boost::make_shared<VCardUpdate>(); + presence = boost::make_shared<Presence>(); + presence->setTo(ownerJID); + presence->setFrom(personJID); + presence->setType(Presence::Available); + presence->addPayload(vcardUpdate); + stanzaChannel->onPresenceReceived(presence); + + /* reply to the avatar request with our EMPTY avatar */ + + CPPUNIT_ASSERT_EQUAL(size_t(1), stanzaChannel->sentStanzas.size()); + request = boost::dynamic_pointer_cast<IQ>(stanzaChannel->sentStanzas[0]); + stanzaChannel->sentStanzas.pop_back(); + CPPUNIT_ASSERT(!!request); + vcard = request->getPayload<VCard>(); + CPPUNIT_ASSERT(!!vcard); + + ByteArray blankAvatar = createByteArray(""); + reply = boost::make_shared<IQ>(IQ::Result); + reply->setTo(request->getFrom()); + reply->setFrom(request->getTo()); + reply->setID(request->getID()); + vcard->setPhoto(blankAvatar); + reply->addPayload(vcard); + stanzaChannel->onIQReceived(reply); + + /* check hash through avatarManager that it received the correct photo */ + + reportedAvatar = avatarManager->getAvatar(personJID.toBare()); + CPPUNIT_ASSERT_EQUAL(byteArrayToString(blankAvatar), byteArrayToString(reportedAvatar)); + } + + struct DummyMUCRegistry : public MUCRegistry { + bool isMUC(const JID& jid) const { return std::find(mucs_.begin(), mucs_.end(), jid) != mucs_.end(); } + std::vector<JID> mucs_; + }; + + private: + + JID ownerJID; + boost::shared_ptr<DummyStanzaChannel> stanzaChannel; + boost::shared_ptr<IQRouter> iqRouter; + boost::shared_ptr<CryptoProvider> crypto; + boost::shared_ptr<VCardMemoryStorage> vcardStorage; + boost::shared_ptr<VCardManager> vcardManager; + boost::shared_ptr<AvatarMemoryStorage> avatarStorage; + boost::shared_ptr<DummyMUCRegistry> mucRegistry; + boost::shared_ptr<AvatarManagerImpl> avatarManager; + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(AvatarManagerImplTest); diff --git a/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp b/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp index 50b0adb..715b7fc 100644 --- a/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp +++ b/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp @@ -12,4 +12,16 @@ #include <string> #include <Swiften/Avatars/CombinedAvatarProvider.h> +#include <Swiften/Avatars/VCardAvatarManager.h> +#include <Swiften/Avatars/OfflineAvatarManager.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Avatars/AvatarMemoryStorage.h> +#include <Swiften/VCards/VCardMemoryStorage.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/Avatars/VCardUpdateAvatarManager.h> +#include <Swiften/StringCodecs/Hexify.h> using namespace Swift; @@ -29,4 +41,5 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { CPPUNIT_TEST(testProviderUpdateBareJIDAfterGetFullJID); CPPUNIT_TEST(testRemoveProviderDisconnectsUpdates); + CPPUNIT_TEST(testAddRemoveFallthrough); CPPUNIT_TEST_SUITE_END(); @@ -50,5 +63,6 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); - CPPUNIT_ASSERT(testling->getAvatarHash(user1).empty()); + boost::optional<std::string> hash = testling->getAvatarHash(user1); + CPPUNIT_ASSERT(!hash); } @@ -58,5 +72,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { testling->addProvider(avatarProvider1); - CPPUNIT_ASSERT_EQUAL(avatarHash1, testling->getAvatarHash(user1)); + boost::optional<std::string> hash = testling->getAvatarHash(user1); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(avatarHash1, *hash); } @@ -68,5 +84,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { testling->addProvider(avatarProvider2); - CPPUNIT_ASSERT_EQUAL(avatarHash1, testling->getAvatarHash(user1)); + boost::optional<std::string> hash = testling->getAvatarHash(user1); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(avatarHash1, *hash); } @@ -77,5 +95,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { testling->addProvider(avatarProvider2); - CPPUNIT_ASSERT_EQUAL(avatarHash2, testling->getAvatarHash(user1)); + boost::optional<std::string> hash = testling->getAvatarHash(user1); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(avatarHash2, *hash); } @@ -180,5 +200,131 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { avatarProvider1->onAvatarChanged(user1.toBare()); - CPPUNIT_ASSERT_EQUAL(avatarHash2, testling->getAvatarHash(user1)); + boost::optional<std::string> hash = testling->getAvatarHash(user1); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(avatarHash2, *hash); + } + + void testAddRemoveFallthrough() { + JID ownJID = JID("user0@own.com/res"); + JID user1 = JID("user1@bar.com/bla"); + + boost::shared_ptr<CryptoProvider> crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + DummyStanzaChannel* stanzaChannel = new DummyStanzaChannel(); + stanzaChannel->setAvailable(true); + IQRouter* iqRouter = new IQRouter(stanzaChannel); + DummyMUCRegistry* mucRegistry = new DummyMUCRegistry(); + AvatarMemoryStorage* avatarStorage = new AvatarMemoryStorage(); + VCardMemoryStorage* vcardStorage = new VCardMemoryStorage(crypto.get()); + VCardManager* vcardManager = new VCardManager(ownJID, iqRouter, vcardStorage); + + boost::shared_ptr<VCardUpdateAvatarManager> updateManager(new VCardUpdateAvatarManager(vcardManager, stanzaChannel, avatarStorage, crypto.get(), mucRegistry)); + updateManager->onAvatarChanged.connect(boost::bind(&CombinedAvatarProviderTest::handleAvatarChanged, this, _1)); + + boost::shared_ptr<VCardAvatarManager> manager(new VCardAvatarManager(vcardManager, avatarStorage, crypto.get(), mucRegistry)); + manager->onAvatarChanged.connect(boost::bind(&CombinedAvatarProviderTest::handleAvatarChanged, this, _1)); + + boost::shared_ptr<OfflineAvatarManager> offlineManager(new OfflineAvatarManager(avatarStorage)); + offlineManager->onAvatarChanged.connect(boost::bind(&CombinedAvatarProviderTest::handleAvatarChanged, this, _1)); + + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); + avatarProvider1->useBare = true; + testling->addProvider(updateManager.get()); + testling->addProvider(manager.get()); + testling->addProvider(offlineManager.get()); + + /* place an avatar in the cache, check that it reads back OK */ + + CPPUNIT_ASSERT_EQUAL(size_t(0), changes.size()); + + ByteArray avatar1 = createByteArray("abcdefg"); + std::string avatar1Hash = Hexify::hexify(crypto->getSHA1Hash(avatar1)); + VCard::ref vcard1(new VCard()); + vcard1->setPhoto(avatar1); + + vcardStorage->setVCard(user1.toBare(), vcard1); + boost::optional<std::string> testHash = testling->getAvatarHash(user1.toBare()); + CPPUNIT_ASSERT(testHash); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, *testHash); + + VCard::ref storedVCard = vcardStorage->getVCard(user1.toBare()); + CPPUNIT_ASSERT(!!storedVCard); + testHash = Hexify::hexify(crypto->getSHA1Hash(storedVCard->getPhoto())); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, *testHash); + + /* change the avatar by sending an VCard IQ */ + + vcardManager->requestVCard(user1.toBare()); + CPPUNIT_ASSERT_EQUAL(size_t(1), stanzaChannel->sentStanzas.size()); + IQ::ref request = boost::dynamic_pointer_cast<IQ>(stanzaChannel->sentStanzas.back()); + VCard::ref payload = request->getPayload<VCard>(); + CPPUNIT_ASSERT(!!payload); + stanzaChannel->sentStanzas.pop_back(); + + ByteArray avatar2 = createByteArray("1234567"); + std::string avatar2Hash = Hexify::hexify(crypto->getSHA1Hash(avatar2)); + VCard::ref vcard2(new VCard()); + vcard2->setPhoto(avatar2); + + IQ::ref reply = boost::make_shared<IQ>(); + reply->setTo(request->getFrom()); + reply->setFrom(request->getTo()); + reply->setID(request->getID()); + reply->addPayload(vcard2); + reply->setType(IQ::Result); + + stanzaChannel->onIQReceived(reply); + + /* check that we changed the avatar successfully and that we were notified about the changes */ + + testHash = testling->getAvatarHash(user1.toBare()); + CPPUNIT_ASSERT(testHash); + CPPUNIT_ASSERT_EQUAL(avatar2Hash, *testHash); + CPPUNIT_ASSERT_EQUAL(size_t(3), changes.size()); + CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[0]); + CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[1]); + CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[2]); + changes.clear(); + storedVCard = vcardStorage->getVCard(user1.toBare()); + CPPUNIT_ASSERT(!!storedVCard); + testHash = Hexify::hexify(crypto->getSHA1Hash(storedVCard->getPhoto())); + CPPUNIT_ASSERT_EQUAL(avatar2Hash, *testHash); + + /* change the avatar to the empty avatar */ + + vcardManager->requestVCard(user1.toBare()); + CPPUNIT_ASSERT_EQUAL(size_t(1), stanzaChannel->sentStanzas.size()); + request = boost::dynamic_pointer_cast<IQ>(stanzaChannel->sentStanzas.back()); + payload = request->getPayload<VCard>(); + CPPUNIT_ASSERT(!!payload); + stanzaChannel->sentStanzas.pop_back(); + + VCard::ref vcard3(new VCard()); + reply = boost::make_shared<IQ>(); + reply->setTo(request->getFrom()); + reply->setFrom(request->getTo()); + reply->setID(request->getID()); + reply->addPayload(vcard3); + reply->setType(IQ::Result); + stanzaChannel->onIQReceived(reply); + + /* check that we changed the avatar successfully */ + + testHash = testling->getAvatarHash(user1.toBare()); + CPPUNIT_ASSERT(testHash); + CPPUNIT_ASSERT_EQUAL(std::string(""), *testHash); + CPPUNIT_ASSERT_EQUAL(size_t(3), changes.size()); + CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[0]); + CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[1]); + CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[2]); + changes.clear(); + storedVCard = vcardStorage->getVCard(user1.toBare()); + CPPUNIT_ASSERT(!!storedVCard); + CPPUNIT_ASSERT(!storedVCard->getPhoto().size()); + + delete vcardManager; + delete vcardStorage; + delete mucRegistry; + delete iqRouter; + delete stanzaChannel; } @@ -199,5 +345,5 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } - std::string getAvatarHash(const JID& jid) const { + boost::optional<std::string> getAvatarHash(const JID& jid) const { JID actualJID = useBare ? jid.toBare() : jid; std::map<JID, std::string>::const_iterator i = avatars.find(actualJID); @@ -206,5 +352,5 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } else { - return std::string(); + return boost::optional<std::string>(); } } @@ -214,4 +360,9 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { }; + struct DummyMUCRegistry : public MUCRegistry { + bool isMUC(const JID& jid) const { return std::find(mucs_.begin(), mucs_.end(), jid) != mucs_.end(); } + std::vector<JID> mucs_; + }; + DummyAvatarProvider* avatarProvider1; DummyAvatarProvider* avatarProvider2; diff --git a/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp b/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp index 81dc12c..778b001 100644 --- a/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp +++ b/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,11 +14,12 @@ #include <Swiften/Elements/VCard.h> #include <Swiften/Avatars/VCardAvatarManager.h> +#include <Swiften/VCards/VCardMemoryStorage.h> #include <Swiften/Avatars/AvatarMemoryStorage.h> #include <Swiften/VCards/VCardManager.h> -#include <Swiften/VCards/VCardStorage.h> #include <Swiften/MUC/MUCRegistry.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/StringCodecs/Hexify.h> @@ -36,41 +37,6 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { public: - class TestVCardStorage : public VCardStorage { - public: - virtual VCard::ref getVCard(const JID& jid) const { - VCardMap::const_iterator i = vcards.find(jid); - if (i != vcards.end()) { - return i->second; - } - else { - return VCard::ref(); - } - } - - virtual void setVCard(const JID& jid, VCard::ref v) { - vcards[jid] = v; - } - - std::string getPhotoHash(const JID& jid) const { - if (photoHashes.find(jid) != photoHashes.end()) { - return photoHashes.find(jid)->second; - } - VCard::ref vCard = getVCard(jid); - if (vCard && !vCard->getPhoto().empty()) { - return Hexify::hexify(SHA1::getHash(vCard->getPhoto())); - } - else { - return ""; - } - } - - std::map<JID, std::string> photoHashes; - - private: - typedef std::map<JID, VCard::ref> VCardMap; - VCardMap vcards; - }; - void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); ownJID = JID("foo@fum.com/bum"); stanzaChannel = new DummyStanzaChannel(); @@ -79,8 +45,8 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { mucRegistry = new DummyMUCRegistry(); avatarStorage = new AvatarMemoryStorage(); - vcardStorage = new TestVCardStorage(); + vcardStorage = new VCardMemoryStorage(crypto.get()); vcardManager = new VCardManager(ownJID, iqRouter, vcardStorage); avatar1 = createByteArray("abcdefg"); - avatar1Hash = Hexify::hexify(SHA1::getHash(avatar1)); + avatar1Hash = Hexify::hexify(crypto->getSHA1Hash(avatar1)); user1 = JID("user1@bar.com/bla"); user2 = JID("user2@foo.com/baz"); @@ -101,7 +67,8 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { avatarStorage->addAvatar(avatar1Hash, avatar1); - std::string result = testling->getAvatarHash(user1); + boost::optional<std::string> result = testling->getAvatarHash(user1); - CPPUNIT_ASSERT_EQUAL(avatar1Hash, result); + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, *result); } @@ -110,7 +77,8 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { storeEmptyVCard(user1.toBare()); - std::string result = testling->getAvatarHash(user1); + boost::optional<std::string> result = testling->getAvatarHash(user1); - CPPUNIT_ASSERT_EQUAL(std::string(), result); + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(std::string(), *result); } @@ -119,7 +87,8 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { storeVCardWithPhoto(user1.toBare(), avatar1); - std::string result = testling->getAvatarHash(user1); + boost::optional<std::string> result = testling->getAvatarHash(user1); - CPPUNIT_ASSERT_EQUAL(avatar1Hash, result); + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, *result); CPPUNIT_ASSERT(avatarStorage->hasAvatar(avatar1Hash)); CPPUNIT_ASSERT_EQUAL(avatar1, avatarStorage->getAvatar(avatar1Hash)); @@ -129,16 +98,19 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { boost::shared_ptr<VCardAvatarManager> testling = createManager(); - std::string result = testling->getAvatarHash(user1); + boost::optional<std::string> result = testling->getAvatarHash(user1); - CPPUNIT_ASSERT_EQUAL(std::string(), result); + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(std::string(), *result); } void testGetAvatarHashKnownAvatarUnknownVCard() { boost::shared_ptr<VCardAvatarManager> testling = createManager(); - vcardStorage->photoHashes[user1.toBare()] = avatar1Hash; - std::string result = testling->getAvatarHash(user1); + avatarStorage->setAvatarForJID(user1, avatar1Hash); + + boost::optional<std::string> result = testling->getAvatarHash(user1); - CPPUNIT_ASSERT_EQUAL(std::string(), result); + CPPUNIT_ASSERT(result); + CPPUNIT_ASSERT_EQUAL(std::string(), *result); } @@ -154,5 +126,5 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { private: boost::shared_ptr<VCardAvatarManager> createManager() { - boost::shared_ptr<VCardAvatarManager> result(new VCardAvatarManager(vcardManager, avatarStorage, mucRegistry)); + boost::shared_ptr<VCardAvatarManager> result(new VCardAvatarManager(vcardManager, avatarStorage, crypto.get(), mucRegistry)); result->onAvatarChanged.connect(boost::bind(&VCardAvatarManagerTest::handleAvatarChanged, this, _1)); return result; @@ -192,5 +164,5 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { AvatarMemoryStorage* avatarStorage; VCardManager* vcardManager; - TestVCardStorage* vcardStorage; + VCardMemoryStorage* vcardStorage; ByteArray avatar1; std::string avatar1Hash; @@ -198,4 +170,5 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { JID user1; JID user2; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp b/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp index 60e76f8..c29a763 100644 --- a/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp +++ b/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -20,6 +20,7 @@ #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> -#include <Swiften/StringCodecs/SHA1.h> #include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -38,4 +39,5 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { public: void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); ownJID = JID("foo@fum.com/bum"); stanzaChannel = new DummyStanzaChannel(); @@ -44,12 +46,13 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { mucRegistry = new DummyMUCRegistry(); avatarStorage = new AvatarMemoryStorage(); - vcardStorage = new VCardMemoryStorage(); + vcardStorage = new VCardMemoryStorage(crypto.get()); vcardManager = new VCardManager(ownJID, iqRouter, vcardStorage); avatar1 = createByteArray("abcdefg"); - avatar1Hash = Hexify::hexify(SHA1::getHash(avatar1)); + avatar1Hash = Hexify::hexify(crypto->getSHA1Hash(avatar1)); user1 = JID("user1@bar.com/bla"); user2 = JID("user2@foo.com/baz"); } + void tearDown() { delete vcardManager; @@ -76,5 +79,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[0]); - CPPUNIT_ASSERT_EQUAL(avatar1Hash, testling->getAvatarHash(user1.toBare())); + boost::optional<std::string> hash = testling->getAvatarHash(user1.toBare()); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, *hash); CPPUNIT_ASSERT(avatarStorage->hasAvatar(avatar1Hash)); CPPUNIT_ASSERT_EQUAL(avatar1, avatarStorage->getAvatar(avatar1Hash)); @@ -106,5 +111,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user2.toBare(), changes[0]); - CPPUNIT_ASSERT_EQUAL(avatar1Hash, testling->getAvatarHash(user2.toBare())); + boost::optional<std::string> hash = testling->getAvatarHash(user2.toBare()); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, *hash); } @@ -114,6 +121,8 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { stanzaChannel->onIQReceived(createVCardResult(ByteArray())); - CPPUNIT_ASSERT(!avatarStorage->hasAvatar(Hexify::hexify(SHA1::getHash(ByteArray())))); - CPPUNIT_ASSERT_EQUAL(std::string(), testling->getAvatarHash(JID("foo@bar.com"))); + CPPUNIT_ASSERT(!avatarStorage->hasAvatar(Hexify::hexify(crypto->getSHA1Hash(ByteArray())))); + boost::optional<std::string> hash = testling->getAvatarHash(JID("foo@bar.com")); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(std::string(), *hash); } @@ -130,5 +139,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[0]); - CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getAvatarHash(user1.toBare())); + boost::optional<std::string> hash = testling->getAvatarHash(user1.toBare()); + CPPUNIT_ASSERT(!hash); + //CPPUNIT_ASSERT_EQUAL(std::string(""), *hash); } @@ -146,10 +157,12 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1.toBare(), changes[1]); - CPPUNIT_ASSERT_EQUAL(avatar1Hash, testling->getAvatarHash(user1.toBare())); + boost::optional<std::string> hash = testling->getAvatarHash(user1.toBare()); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(avatar1Hash, *hash); } private: boost::shared_ptr<VCardUpdateAvatarManager> createManager() { - boost::shared_ptr<VCardUpdateAvatarManager> result(new VCardUpdateAvatarManager(vcardManager, stanzaChannel, avatarStorage, mucRegistry)); + boost::shared_ptr<VCardUpdateAvatarManager> result(new VCardUpdateAvatarManager(vcardManager, stanzaChannel, avatarStorage, crypto.get(), mucRegistry)); result->onAvatarChanged.connect(boost::bind(&VCardUpdateAvatarManagerTest::handleAvatarChanged, this, _1)); return result; @@ -193,4 +206,5 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { JID user1; JID user2; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Avatars/VCardAvatarManager.cpp b/Swiften/Avatars/VCardAvatarManager.cpp index ef1d293..539b7a0 100644 --- a/Swiften/Avatars/VCardAvatarManager.cpp +++ b/Swiften/Avatars/VCardAvatarManager.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,5 +10,5 @@ #include <Swiften/Elements/VCard.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/Avatars/AvatarStorage.h> @@ -19,5 +19,5 @@ namespace Swift { -VCardAvatarManager::VCardAvatarManager(VCardManager* vcardManager, AvatarStorage* avatarStorage, MUCRegistry* mucRegistry) : vcardManager_(vcardManager), avatarStorage_(avatarStorage), mucRegistry_(mucRegistry) { +VCardAvatarManager::VCardAvatarManager(VCardManager* vcardManager, AvatarStorage* avatarStorage, CryptoProvider* crypto, MUCRegistry* mucRegistry) : vcardManager_(vcardManager), avatarStorage_(avatarStorage), crypto_(crypto), mucRegistry_(mucRegistry) { vcardManager_->onVCardChanged.connect(boost::bind(&VCardAvatarManager::handleVCardChanged, this, _1)); } @@ -30,5 +30,5 @@ void VCardAvatarManager::handleVCardChanged(const JID& from) { } -std::string VCardAvatarManager::getAvatarHash(const JID& jid) const { +boost::optional<std::string> VCardAvatarManager::getAvatarHash(const JID& jid) const { JID avatarJID = getAvatarJID(jid); std::string hash = vcardManager_->getPhotoHash(avatarJID); @@ -37,5 +37,5 @@ std::string VCardAvatarManager::getAvatarHash(const JID& jid) const { VCard::ref vCard = vcardManager_->getVCard(avatarJID); if (vCard) { - std::string newHash = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); + std::string newHash = Hexify::hexify(crypto_->getSHA1Hash(vCard->getPhoto())); if (newHash != hash) { // Shouldn't happen, but sometimes seem to. Might be fixed if we diff --git a/Swiften/Avatars/VCardAvatarManager.h b/Swiften/Avatars/VCardAvatarManager.h index cb3945d..a907fa5 100644 --- a/Swiften/Avatars/VCardAvatarManager.h +++ b/Swiften/Avatars/VCardAvatarManager.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Avatars/AvatarProvider.h> #include <Swiften/JID/JID.h> @@ -14,10 +15,11 @@ namespace Swift { class AvatarStorage; class VCardManager; + class CryptoProvider; - class VCardAvatarManager : public AvatarProvider { + class SWIFTEN_API VCardAvatarManager : public AvatarProvider { public: - VCardAvatarManager(VCardManager*, AvatarStorage*, MUCRegistry* = NULL); + VCardAvatarManager(VCardManager*, AvatarStorage*, CryptoProvider* crypto, MUCRegistry* = NULL); - std::string getAvatarHash(const JID&) const; + boost::optional<std::string> getAvatarHash(const JID&) const; private: @@ -28,4 +30,5 @@ namespace Swift { VCardManager* vcardManager_; AvatarStorage* avatarStorage_; + CryptoProvider* crypto_; MUCRegistry* mucRegistry_; }; diff --git a/Swiften/Avatars/VCardUpdateAvatarManager.cpp b/Swiften/Avatars/VCardUpdateAvatarManager.cpp index 0c3ad23..55537ff 100644 --- a/Swiften/Avatars/VCardUpdateAvatarManager.cpp +++ b/Swiften/Avatars/VCardUpdateAvatarManager.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,5 +12,5 @@ #include <Swiften/Elements/VCardUpdate.h> #include <Swiften/VCards/GetVCardRequest.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/Avatars/AvatarStorage.h> @@ -21,5 +21,5 @@ namespace Swift { -VCardUpdateAvatarManager::VCardUpdateAvatarManager(VCardManager* vcardManager, StanzaChannel* stanzaChannel, AvatarStorage* avatarStorage, MUCRegistry* mucRegistry) : vcardManager_(vcardManager), stanzaChannel_(stanzaChannel), avatarStorage_(avatarStorage), mucRegistry_(mucRegistry) { +VCardUpdateAvatarManager::VCardUpdateAvatarManager(VCardManager* vcardManager, StanzaChannel* stanzaChannel, AvatarStorage* avatarStorage, CryptoProvider* crypto, MUCRegistry* mucRegistry) : vcardManager_(vcardManager), avatarStorage_(avatarStorage), crypto_(crypto), mucRegistry_(mucRegistry) { stanzaChannel->onPresenceReceived.connect(boost::bind(&VCardUpdateAvatarManager::handlePresenceReceived, this, _1)); stanzaChannel->onAvailableChanged.connect(boost::bind(&VCardUpdateAvatarManager::handleStanzaChannelAvailableChanged, this, _1)); @@ -47,5 +47,5 @@ void VCardUpdateAvatarManager::handlePresenceReceived(boost::shared_ptr<Presence void VCardUpdateAvatarManager::handleVCardChanged(const JID& from, VCard::ref vCard) { if (!vCard) { - std::cerr << "Warning: " << from << ": null vcard payload" << std::endl; + SWIFT_LOG(debug) << "Missing element: " << from << ": null vcard payload" << std::endl; return; } @@ -55,5 +55,5 @@ void VCardUpdateAvatarManager::handleVCardChanged(const JID& from, VCard::ref vC } else { - std::string hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); + std::string hash = Hexify::hexify(crypto_->getSHA1Hash(vCard->getPhoto())); if (!avatarStorage_->hasAvatar(hash)) { avatarStorage_->addAvatar(hash, vCard->getPhoto()); @@ -77,5 +77,5 @@ void VCardUpdateAvatarManager::setAvatar(const JID& jid, const ByteArray& avatar */ -std::string VCardUpdateAvatarManager::getAvatarHash(const JID& jid) const { +boost::optional<std::string> VCardUpdateAvatarManager::getAvatarHash(const JID& jid) const { std::map<JID, std::string>::const_iterator i = avatarHashes_.find(getAvatarJID(jid)); if (i != avatarHashes_.end()) { @@ -83,5 +83,5 @@ std::string VCardUpdateAvatarManager::getAvatarHash(const JID& jid) const { } else { - return ""; + return boost::optional<std::string>(); } } diff --git a/Swiften/Avatars/VCardUpdateAvatarManager.h b/Swiften/Avatars/VCardUpdateAvatarManager.h index de68672..333516b 100644 --- a/Swiften/Avatars/VCardUpdateAvatarManager.h +++ b/Swiften/Avatars/VCardUpdateAvatarManager.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Avatars/AvatarProvider.h> #include <Swiften/JID/JID.h> @@ -21,10 +22,11 @@ namespace Swift { class StanzaChannel; class VCardManager; + class CryptoProvider; - class VCardUpdateAvatarManager : public AvatarProvider, public boost::bsignals::trackable { + class SWIFTEN_API VCardUpdateAvatarManager : public AvatarProvider, public boost::bsignals::trackable { public: - VCardUpdateAvatarManager(VCardManager*, StanzaChannel*, AvatarStorage*, MUCRegistry* = NULL); + VCardUpdateAvatarManager(VCardManager*, StanzaChannel*, AvatarStorage*, CryptoProvider* crypto, MUCRegistry* = NULL); - std::string getAvatarHash(const JID&) const; + boost::optional<std::string> getAvatarHash(const JID&) const; private: @@ -37,6 +39,6 @@ namespace Swift { private: VCardManager* vcardManager_; - StanzaChannel* stanzaChannel_; AvatarStorage* avatarStorage_; + CryptoProvider* crypto_; MUCRegistry* mucRegistry_; std::map<JID, std::string> avatarHashes_; diff --git a/Swiften/Base/API.h b/Swiften/Base/API.h new file mode 100644 index 0000000..0913181 --- /dev/null +++ b/Swiften/Base/API.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012-2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Platform.h> +#include <boost/config.hpp> + +#ifdef SWIFTEN_STATIC +# define SWIFTEN_API +#else +# ifdef SWIFTEN_PLATFORM_WINDOWS +# ifdef SWIFTEN_BUILDING +# define SWIFTEN_API __declspec(dllexport) +# else +# define SWIFTEN_API __declspec(dllimport) +# endif +# elif __GNUC__ >= 4 +# define SWIFTEN_API __attribute__((visibility("default"))) +# else +# define SWIFTEN_API +# endif +#endif + +#ifdef BOOST_NO_DEFAULTED_FUNCTIONS +# define SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(cls) +# define SWIFTEN_DEFAULT_COPY_ASSIGMNENT_OPERATOR(cls) +#else +# define SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(cls) \ + cls(const cls&) = default; +# define SWIFTEN_DEFAULT_COPY_ASSIGMNENT_OPERATOR(cls) \ + cls& operator=(const cls&) = default; +#endif + +#ifdef BOOST_NO_NOEXCEPT +#define SWIFTEN_NOEXCEPT throw() +#else +#define SWIFTEN_NOEXCEPT noexcept +#endif diff --git a/Swiften/Base/Algorithm.h b/Swiften/Base/Algorithm.h index 4e68e70..d5edab1 100644 --- a/Swiften/Base/Algorithm.h +++ b/Swiften/Base/Algorithm.h @@ -100,4 +100,9 @@ namespace Swift { } + template<typename Source, typename Target> + void assign(Target& target, const Source& source) { + target.assign(source.begin(), source.end()); + } + template<typename A, typename B, typename C, typename D> B get(const std::map<A, B, C, D>& map, const A& key, const B& defaultValue) { diff --git a/Swiften/Base/BoostFilesystemVersion.h b/Swiften/Base/BoostFilesystemVersion.h new file mode 100644 index 0000000..1b1676c --- /dev/null +++ b/Swiften/Base/BoostFilesystemVersion.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2010-2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ +#pragma once + +#ifndef BOOST_FILESYSTEM_VERSION +#define BOOST_FILESYSTEM_VERSION 2 +#endif diff --git a/Swiften/Base/BoostRandomGenerator.h b/Swiften/Base/BoostRandomGenerator.h index b5a6cac..6065ff3 100644 --- a/Swiften/Base/BoostRandomGenerator.h +++ b/Swiften/Base/BoostRandomGenerator.h @@ -8,4 +8,5 @@ #include <Swiften/Base/RandomGenerator.h> +#include <Swiften/Base/Override.h> #include <boost/random/mersenne_twister.hpp> @@ -16,5 +17,5 @@ namespace Swift { BoostRandomGenerator(); - int generateRandomInteger(int max); + int generateRandomInteger(int max) SWIFTEN_OVERRIDE; private: diff --git a/Swiften/Base/ByteArray.cpp b/Swiften/Base/ByteArray.cpp index 6be96aa..466db5f 100644 --- a/Swiften/Base/ByteArray.cpp +++ b/Swiften/Base/ByteArray.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,5 +7,6 @@ #include <Swiften/Base/ByteArray.h> -#include <fstream> +#include <boost/numeric/conversion/cast.hpp> +#include <boost/filesystem/fstream.hpp> namespace Swift { @@ -13,11 +14,11 @@ namespace Swift { static const int BUFFER_SIZE = 4096; -void readByteArrayFromFile(ByteArray& data, const std::string& file) { - std::ifstream input(file.c_str(), std::ios_base::in|std::ios_base::binary); +void readByteArrayFromFile(ByteArray& data, const boost::filesystem::path& file) { + boost::filesystem::ifstream input(file, std::ios_base::in|std::ios_base::binary); while (input.good()) { size_t oldSize = data.size(); data.resize(oldSize + BUFFER_SIZE); input.read(reinterpret_cast<char*>(&data[oldSize]), BUFFER_SIZE); - data.resize(oldSize + input.gcount()); + data.resize(oldSize + boost::numeric_cast<size_t>(input.gcount())); } input.close(); diff --git a/Swiften/Base/ByteArray.h b/Swiften/Base/ByteArray.h index 01cd5d0..133b75f 100644 --- a/Swiften/Base/ByteArray.h +++ b/Swiften/Base/ByteArray.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,9 +10,12 @@ #include <string> +#include <Swiften/Base/API.h> +#include <boost/filesystem/path.hpp> + namespace Swift { typedef std::vector<unsigned char> ByteArray; - ByteArray createByteArray(const std::string& s); - ByteArray createByteArray(const char* c); + SWIFTEN_API ByteArray createByteArray(const std::string& s); + SWIFTEN_API ByteArray createByteArray(const char* c); inline ByteArray createByteArray(const unsigned char* c, size_t n) { @@ -25,5 +28,5 @@ namespace Swift { inline ByteArray createByteArray(char c) { - return std::vector<unsigned char>(1, c); + return std::vector<unsigned char>(1, static_cast<unsigned char>(c)); } @@ -38,7 +41,7 @@ namespace Swift { } - std::string byteArrayToString(const ByteArray& b); + SWIFTEN_API std::string byteArrayToString(const ByteArray& b); - void readByteArrayFromFile(ByteArray&, const std::string& file); + SWIFTEN_API void readByteArrayFromFile(ByteArray&, const boost::filesystem::path& file); } diff --git a/Swiften/Base/DateTime.cpp b/Swiften/Base/DateTime.cpp index fae26d4..5d192c4 100644 --- a/Swiften/Base/DateTime.cpp +++ b/Swiften/Base/DateTime.cpp @@ -11,4 +11,5 @@ #include <boost/date_time/local_time/local_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/date_time/c_local_time_adjustor.hpp> #include <Swiften/Base/String.h> @@ -32,3 +33,7 @@ std::string dateTimeToString(const boost::posix_time::ptime& time) { } +std::string dateTimeToLocalString(const boost::posix_time::ptime& time) { + return boost::posix_time::to_simple_string(boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local(time)); +} + } diff --git a/Swiften/Base/DateTime.h b/Swiften/Base/DateTime.h index 2407ddc..891b170 100644 --- a/Swiften/Base/DateTime.h +++ b/Swiften/Base/DateTime.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <boost/date_time/posix_time/ptime.hpp> @@ -14,9 +15,14 @@ namespace Swift { * object (in UTC). */ - boost::posix_time::ptime stringToDateTime(const std::string& string); + SWIFTEN_API boost::posix_time::ptime stringToDateTime(const std::string& string); /** * Converts a UTC ptime object to a XEP-0082 formatted string. */ - std::string dateTimeToString(const boost::posix_time::ptime& time); + SWIFTEN_API std::string dateTimeToString(const boost::posix_time::ptime& time); + + /** + * Converts a UTC ptime object to a localized human readable string. + */ + SWIFTEN_API std::string dateTimeToLocalString(const boost::posix_time::ptime& time); } diff --git a/Swiften/Base/Error.h b/Swiften/Base/Error.h index e99f175..00287fc 100644 --- a/Swiften/Base/Error.h +++ b/Swiften/Base/Error.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,12 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { - class Error { + class SWIFTEN_API Error { public: + Error() {} + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(Error) virtual ~Error(); }; -}; +} diff --git a/Swiften/Base/FileSize.cpp b/Swiften/Base/FileSize.cpp new file mode 100644 index 0000000..90fdc9a --- /dev/null +++ b/Swiften/Base/FileSize.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/FileSize.h> +#include <boost/format.hpp> + +namespace Swift { + +std::string formatSize(const boost::uintmax_t bytes) { + static const char *siPrefix[] = {"k", "M", "G", "T", "P", "E", "Z", "Y", NULL}; + int power = 0; + double engBytes = bytes; + while (engBytes >= 1000) { + ++power; + engBytes = engBytes / 1000.0; + } + return str( boost::format("%.1lf %sB") % engBytes % (power > 0 ? siPrefix[power-1] : "") ); +} + +} diff --git a/Swiften/Base/FileSize.h b/Swiften/Base/FileSize.h new file mode 100644 index 0000000..c9ed5fe --- /dev/null +++ b/Swiften/Base/FileSize.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010-2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <boost/cstdint.hpp> +#include <string> + +namespace Swift { + +SWIFTEN_API std::string formatSize(const boost::uintmax_t bytes); + +} diff --git a/Swiften/Base/IDGenerator.h b/Swiften/Base/IDGenerator.h index 44eeb76..14ecfdc 100644 --- a/Swiften/Base/IDGenerator.h +++ b/Swiften/Base/IDGenerator.h @@ -9,6 +9,8 @@ #include <string> +#include <Swiften/Base/API.h> + namespace Swift { - class IDGenerator { + class SWIFTEN_API IDGenerator { public: IDGenerator(); diff --git a/Swiften/Base/Listenable.h b/Swiften/Base/Listenable.h new file mode 100644 index 0000000..445dfd7 --- /dev/null +++ b/Swiften/Base/Listenable.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <boost/bind.hpp> +#include <algorithm> + +namespace Swift { + template<typename T> + class SWIFTEN_API Listenable { + public: + void addListener(T* listener) { + listeners.push_back(listener); + } + + void removeListener(T* listener) { + listeners.erase(std::remove(listeners.begin(), listeners.end(), listener), listeners.end()); + } + + protected: + template<typename F> + void notifyListeners(F event) { + for (typename std::vector<T*>::iterator i = listeners.begin(); i != listeners.end(); ++i) { + event(*i); + } + } + + template<typename F, typename A1> + void notifyListeners(F f, const A1& a1) { + notifyListeners(boost::bind(f, _1, a1)); + } + + template<typename F, typename A1, typename A2> + void notifyListeners(F f, const A1& a1, const A2& a2) { + notifyListeners(boost::bind(f, _1, a1, a2)); + } + + template<typename F, typename A1, typename A2, typename A3> + void notifyListeners(F f, const A1& a1, const A2& a2, const A3& a3) { + notifyListeners(boost::bind(f, _1, a1, a2, a3)); + } + + private: + std::vector<T*> listeners; + }; +} + diff --git a/Swiften/Base/Log.cpp b/Swiften/Base/Log.cpp index 4132353..317798c 100644 --- a/Swiften/Base/Log.cpp +++ b/Swiften/Base/Log.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,7 +7,37 @@ #include <Swiften/Base/Log.h> +#include <cstdio> + + namespace Swift { -bool logging = false; +static Log::Severity logLevel = Log::warning; + +Log::Log() { +} + +Log::~Log() { + // Using stdio for thread safety (POSIX file i/o calls are guaranteed to be atomic) + fprintf(stderr, "%s", stream.str().c_str()); + fflush(stderr); +} + +std::ostringstream& Log::getStream( + Severity /*severity*/, + const std::string& severityString, + const std::string& file, + int line, + const std::string& function) { + stream << "[" << severityString << "] " << file << ":" << line << " " << function << ": "; + return stream; +} + +Log::Severity Log::getLogLevel() { + return logLevel; +} + +void Log::setLogLevel(Severity level) { + logLevel = level; +} } diff --git a/Swiften/Base/Log.h b/Swiften/Base/Log.h index 06f5b55..a46860f 100644 --- a/Swiften/Base/Log.h +++ b/Swiften/Base/Log.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010-2012 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,18 +7,38 @@ #pragma once -#include <iostream> +#include <sstream> + +#include <Swiften/Base/API.h> namespace Swift { - extern bool logging; - namespace LogDetail { - // Only here to be able to statically check the correctness of the severity levers - namespace Severity { - enum { - debug, info, warning, error + class SWIFTEN_API Log { + public: + enum Severity { + error, warning, info, debug + }; + + Log(); + ~Log(); + + std::ostringstream& getStream( + Severity severity, + const std::string& severityString, + const std::string& file, + int line, + const std::string& function); + + static Severity getLogLevel(); + static void setLogLevel(Severity level); + + private: + std::ostringstream stream; }; - } - } } #define SWIFT_LOG(severity) \ - if (!Swift::logging) {} else (void) LogDetail::Severity::severity, std::cerr << "[" << #severity << "] " << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << ": " + if (Log::severity > Log::getLogLevel()) ; \ + else Log().getStream(Log::severity, #severity, __FILE__, __LINE__, __FUNCTION__) + +#define SWIFT_LOG_ASSERT(test, severity) \ + if (Log::severity > Log::getLogLevel() || (test)) ; \ + else Log().getStream(Log::severity, #severity, __FILE__, __LINE__, __FUNCTION__) << "Assertion failed: " << #test << ". " diff --git a/Swiften/Base/Override.h b/Swiften/Base/Override.h new file mode 100644 index 0000000..6d9baaa --- /dev/null +++ b/Swiften/Base/Override.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#if defined(__clang__) +# if __has_feature(cxx_override_control) || __has_extension(cxx_override_control) +# define SWIFTEN_OVERRIDE override +# else +# define SWIFTEN_OVERRIDE +# endif + +#elif defined(__GNUC__) +# if ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))) && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define SWIFTEN_OVERRIDE override +# else +# define SWIFTEN_OVERRIDE +# endif + +#elif defined(_MSC_VER) +// Actually, 1700 is the first version that supports the C++11 override, but +// older versions apparently support a similar keyword. +# if _MSC_VER >= 1400 +# define SWIFTEN_OVERRIDE override +# else +# define SWIFTEN_OVERRIDE +# endif + +#else +# define SWIFTEN_OVERRIDE +#endif diff --git a/Swiften/Base/Path.cpp b/Swiften/Base/Path.cpp new file mode 100644 index 0000000..2a49676 --- /dev/null +++ b/Swiften/Base/Path.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Base/Path.h> + +#include <Swiften/Base/Platform.h> +#include <Swiften/Base/String.h> + +using namespace Swift; + +boost::filesystem::path Swift::stringToPath(const std::string& path) { +#ifdef SWIFTEN_PLATFORM_WINDOWS + return boost::filesystem::path(convertStringToWString(path)); +#else + return boost::filesystem::path(path); +#endif +} + +std::string Swift::pathToString(const boost::filesystem::path& path) { +#ifdef SWIFTEN_PLATFORM_WINDOWS + return convertWStringToString(path.native()); +#else + return path.native(); +#endif +} diff --git a/Swiften/Base/Path.h b/Swiften/Base/Path.h new file mode 100644 index 0000000..ea99be9 --- /dev/null +++ b/Swiften/Base/Path.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <boost/filesystem/path.hpp> +#include <string> + +namespace Swift { + /** + * Creates a path for the given UTF-8 encoded string. + * This works independently of global locale settings. + */ + SWIFTEN_API boost::filesystem::path stringToPath(const std::string&); + + /** + * Returns the UTF-8 representation of the given path + * This works independently of global locale settings. + */ + SWIFTEN_API std::string pathToString(const boost::filesystem::path&); +} + + diff --git a/Swiften/Base/Paths.cpp b/Swiften/Base/Paths.cpp index edebc30..8ad1159 100644 --- a/Swiften/Base/Paths.cpp +++ b/Swiften/Base/Paths.cpp @@ -31,5 +31,5 @@ boost::filesystem::path Paths::getExecutablePath() { ByteArray path; path.resize(4096); - ssize_t size = readlink("/proc/self/exe", reinterpret_cast<char*>(vecptr(path)), path.size()); + size_t size = static_cast<size_t>(readlink("/proc/self/exe", reinterpret_cast<char*>(vecptr(path)), path.size())); if (size > 0) { path.resize(size); @@ -37,8 +37,9 @@ boost::filesystem::path Paths::getExecutablePath() { } #elif defined(SWIFTEN_PLATFORM_WINDOWS) - ByteArray data; + std::vector<wchar_t> data; data.resize(2048); - GetModuleFileName(NULL, reinterpret_cast<char*>(vecptr(data)), data.size()); - return boost::filesystem::path(std::string(reinterpret_cast<const char*>(vecptr(data)), data.size()).c_str()).parent_path(); + GetModuleFileNameW(NULL, vecptr(data), data.size()); + return boost::filesystem::path( + std::wstring(vecptr(data), data.size())).parent_path(); #endif return boost::filesystem::path(); diff --git a/Swiften/Base/Paths.h b/Swiften/Base/Paths.h index 8ac4640..94e62d1 100644 --- a/Swiften/Base/Paths.h +++ b/Swiften/Base/Paths.h @@ -9,6 +9,8 @@ #include <boost/filesystem/path.hpp> +#include <Swiften/Base/API.h> + namespace Swift { - class Paths { + class SWIFTEN_API Paths { public: static boost::filesystem::path getExecutablePath(); diff --git a/Swiften/Base/RandomGenerator.h b/Swiften/Base/RandomGenerator.h index 4a3550d..eb5b84d 100644 --- a/Swiften/Base/RandomGenerator.h +++ b/Swiften/Base/RandomGenerator.h @@ -7,11 +7,16 @@ #pragma once +#include <Swiften/Base/API.h> #include <vector> namespace Swift { - class RandomGenerator { + class SWIFTEN_API RandomGenerator { public: virtual ~RandomGenerator(); + /** + * Generates a random integer between 0 and 'max', + * 'max' inclusive. + */ virtual int generateRandomInteger(int max) = 0; }; diff --git a/Swiften/Base/Regex.cpp b/Swiften/Base/Regex.cpp new file mode 100644 index 0000000..5e3d89a --- /dev/null +++ b/Swiften/Base/Regex.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +/* + * Copyright (c) 2012 Maciej Niedzielski + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Base/Regex.h> + +#include <string> + +#include <boost/regex.hpp> + +namespace Swift { + + namespace Regex { + std::string escape(const std::string& source) { + // escape regex special characters: ^.$| etc + // these need to be escaped: [\^\$\|.........] + // and then C++ requires '\' to be escaped, too.... + static const boost::regex esc("([\\^\\.\\$\\|\\(\\)\\[\\]\\*\\+\\?\\/\\{\\}\\\\])"); + // matched character should be prepended with '\' + // replace matched special character with \\\1 + // and escape once more for C++ rules... + static const std::string rep("\\\\\\1"); + return boost::regex_replace(source, esc, rep); + } + + } + +} + diff --git a/Swiften/IDN/IDNA.h b/Swiften/Base/Regex.h index 19af1e6..6d12a60 100644 --- a/Swiften/IDN/IDNA.h +++ b/Swiften/Base/Regex.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,8 +9,11 @@ #include <string> +#include <Swiften/Base/API.h> + namespace Swift { - class IDNA { - public: - static std::string getEncoded(const std::string& s); - }; + + namespace Regex { + SWIFTEN_API std::string escape(const std::string& source); + } + } diff --git a/Swiften/Base/SConscript b/Swiften/Base/SConscript index a5f3592..d7fd7cc 100644 --- a/Swiften/Base/SConscript +++ b/Swiften/Base/SConscript @@ -5,6 +5,8 @@ objects = swiften_env.SwiftenObject([ "DateTime.cpp", "SafeByteArray.cpp", + "SafeAllocator.cpp", "Error.cpp", "Log.cpp", + "Path.cpp", "Paths.cpp", "String.cpp", @@ -14,4 +16,7 @@ objects = swiften_env.SwiftenObject([ "BoostRandomGenerator.cpp", "sleep.cpp", + "URL.cpp", + "Regex.cpp", + "FileSize.cpp" ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Base/SafeAllocator.cpp b/Swiften/Base/SafeAllocator.cpp new file mode 100644 index 0000000..d61d8b9 --- /dev/null +++ b/Swiften/Base/SafeAllocator.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/SafeByteArray.h> + +#include <Swiften/Base/Platform.h> +#ifdef SWIFTEN_PLATFORM_WINDOWS +#include <windows.h> +#endif + +namespace Swift { + +void secureZeroMemory(char* memory, size_t numberOfBytes) { +#ifdef SWIFTEN_PLATFORM_WINDOWS + SecureZeroMemory(memory, numberOfBytes); +#else + volatile char* p = memory; + for (size_t i = 0; i < numberOfBytes; ++i) { + *(p++) = 0; + } +#endif +} + +} diff --git a/Swiften/Base/SafeAllocator.h b/Swiften/Base/SafeAllocator.h index 9f9dd42..8a8b25e 100644 --- a/Swiften/Base/SafeAllocator.h +++ b/Swiften/Base/SafeAllocator.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,5 +10,9 @@ #include <algorithm> +#include <Swiften/Base/API.h> + namespace Swift { + void secureZeroMemory(char* memory, size_t numberOfBytes); + template<typename T> class SafeAllocator : public std::allocator<T> { @@ -18,13 +22,15 @@ namespace Swift { }; - SafeAllocator() throw() {} - SafeAllocator(const SafeAllocator&) throw() : std::allocator<T>() {} - template <class U> SafeAllocator(const SafeAllocator<U>&) throw() {} - ~SafeAllocator() throw() {} + SafeAllocator() SWIFTEN_NOEXCEPT {} + SafeAllocator(const SafeAllocator&) SWIFTEN_NOEXCEPT : std::allocator<T>() {} + template <class U> SafeAllocator(const SafeAllocator<U>&) SWIFTEN_NOEXCEPT {} + ~SafeAllocator() SWIFTEN_NOEXCEPT {} void deallocate (T* p, size_t num) { - std::fill(reinterpret_cast<char*>(p), reinterpret_cast<char*>(p + num), 0); + secureZeroMemory(reinterpret_cast<char*>(p), num); std::allocator<T>::deallocate(p, num); } + + SWIFTEN_DEFAULT_COPY_ASSIGMNENT_OPERATOR(SafeAllocator) }; -}; +} diff --git a/Swiften/Base/SafeByteArray.h b/Swiften/Base/SafeByteArray.h index 1ef1d84..b85373c 100644 --- a/Swiften/Base/SafeByteArray.h +++ b/Swiften/Base/SafeByteArray.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,4 +9,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeAllocator.h> #include <Swiften/Base/ByteArray.h> @@ -20,5 +21,5 @@ namespace Swift { } - SafeByteArray createSafeByteArray(const char* c); + SWIFTEN_API SafeByteArray createSafeByteArray(const char* c); inline SafeByteArray createSafeByteArray(const std::string& s) { @@ -31,5 +32,5 @@ namespace Swift { inline SafeByteArray createSafeByteArray(char c) { - return SafeByteArray(1, c); + return SafeByteArray(1, static_cast<unsigned char>(c)); } diff --git a/Swiften/Base/SimpleIDGenerator.h b/Swiften/Base/SimpleIDGenerator.h index 677c8d1..fee857d 100644 --- a/Swiften/Base/SimpleIDGenerator.h +++ b/Swiften/Base/SimpleIDGenerator.h @@ -9,6 +9,8 @@ #include <string> +#include <Swiften/Base/API.h> + namespace Swift { - class SimpleIDGenerator { + class SWIFTEN_API SimpleIDGenerator { public: SimpleIDGenerator(); diff --git a/Swiften/Base/String.cpp b/Swiften/Base/String.cpp index 7ddf614..40ea2e1 100644 --- a/Swiften/Base/String.cpp +++ b/Swiften/Base/String.cpp @@ -1,12 +1,20 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <Swiften/Base/Platform.h> + #include <cassert> #include <algorithm> +#include <sstream> +#include <iomanip> +#ifdef SWIFTEN_PLATFORM_WINDOWS +#include <windows.h> +#endif #include <Swiften/Base/String.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { @@ -96,3 +104,50 @@ std::vector<std::string> String::split(const std::string& s, char c) { } +std::string String::convertIntToHexString(int h) { + std::stringstream ss; + ss << std::setbase(16); + ss << h; + return ss.str(); +} + +int String::convertHexStringToInt(const std::string& s) { + std::stringstream ss; + int h; + ss << std::setbase(16); + ss << s; + ss >> h; + return h; +} + + +#ifdef SWIFTEN_PLATFORM_WINDOWS +std::string convertWStringToString(const std::wstring& s) { + int utf8Size = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, NULL, 0, NULL, NULL); + if (utf8Size < 0) { + throw std::runtime_error("Conversion error"); + } + std::vector<char> utf8Data(utf8Size); + int result = WideCharToMultiByte( + CP_UTF8, 0, s.c_str(), -1, vecptr(utf8Data), utf8Data.size(), NULL, NULL); + if (result < 0) { + throw std::runtime_error("Conversion error"); + } + return std::string(vecptr(utf8Data), utf8Size-1 /* trailing 0 character */); +} + +std::wstring convertStringToWString(const std::string& s) { + int utf16Size = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + if (utf16Size < 0) { + throw std::runtime_error("Conversion error"); + } + std::vector<wchar_t> utf16Data(utf16Size); + int result = MultiByteToWideChar( + CP_UTF8, 0, s.c_str(), -1, vecptr(utf16Data), utf16Data.size()); + if (result < 0) { + throw std::runtime_error("Conversion error"); + } + return std::wstring(vecptr(utf16Data), utf16Size-1 /* trailing 0 character */); +} +#endif + } diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h index db6c28b..5a5642e 100644 --- a/Swiften/Base/String.h +++ b/Swiften/Base/String.h @@ -11,4 +11,7 @@ #include <sstream> +#include <Swiften/Base/API.h> +#include <Swiften/Base/Platform.h> + #define SWIFTEN_STRING_TO_CFSTRING(a) \ CFStringCreateWithBytes(NULL, reinterpret_cast<const UInt8*>(a.c_str()), a.size(), kCFStringEncodingUTF8, false) @@ -16,8 +19,8 @@ namespace Swift { namespace String { - std::vector<unsigned int> getUnicodeCodePoints(const std::string&); - std::pair<std::string, std::string> getSplittedAtFirst(const std::string&, char c); - std::vector<std::string> split(const std::string&, char c); - void replaceAll(std::string&, char c, const std::string& s); + SWIFTEN_API std::vector<unsigned int> getUnicodeCodePoints(const std::string&); + SWIFTEN_API std::pair<std::string, std::string> getSplittedAtFirst(const std::string&, char c); + SWIFTEN_API std::vector<std::string> split(const std::string&, char c); + SWIFTEN_API void replaceAll(std::string&, char c, const std::string& s); inline bool beginsWith(const std::string& s, char c) { @@ -28,7 +31,16 @@ namespace Swift { return s.size() > 0 && s[s.size()-1] == c; } - }; - class makeString { + std::string convertIntToHexString(int h); + int convertHexStringToInt(const std::string& s); + + } + +#ifdef SWIFTEN_PLATFORM_WINDOWS + SWIFTEN_API std::string convertWStringToString(const std::wstring& s); + SWIFTEN_API std::wstring convertStringToWString(const std::string& s); +#endif + + class SWIFTEN_API makeString { public: template <typename T> makeString& operator<<(T const& v) { diff --git a/Swiften/Base/URL.cpp b/Swiften/Base/URL.cpp new file mode 100644 index 0000000..866cd45 --- /dev/null +++ b/Swiften/Base/URL.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/URL.h> + +#include <iostream> + +namespace Swift { + +int URL::getPortOrDefaultPort(const URL& url) { + if (url.getPort()) { + return *url.getPort(); + } + else if (url.getScheme() == "http") { + return 80; + } + else if (url.getScheme() == "https") { + return 443; + } + else { + std::cerr << "Unknown scheme: " + url.getScheme() << std::endl; + return 80; + } +} + +URL URL::fromString(const std::string& urlString) { + size_t colonIndex = urlString.find(':'); + if (colonIndex == std::string::npos) { + return URL(); + } + std::string scheme = urlString.substr(0, colonIndex); + + // Authority + if (urlString.size() > colonIndex + 2 && urlString[colonIndex+1] == '/' && urlString[colonIndex+2] == '/') { + size_t authorityIndex = colonIndex + 3; + size_t slashIndex = urlString.find('/', authorityIndex); + std::string authority; + std::string path; + if (slashIndex == std::string::npos) { + authority = urlString.substr(authorityIndex); + path = ""; + } + else { + authority = urlString.substr(authorityIndex, slashIndex - authorityIndex); + path = unescape(urlString.substr(slashIndex)); + } + + size_t atIndex = authority.find('@'); + std::string userInfo; + std::string hostAndPort; + if (atIndex != std::string::npos) { + userInfo = authority.substr(0, atIndex); + hostAndPort = authority.substr(atIndex + 1); + } + else { + userInfo = ""; + hostAndPort = authority; + } + + std::string host; + boost::optional<int> port; + colonIndex = hostAndPort.find(':'); + if (colonIndex != std::string::npos) { + host = unescape(hostAndPort.substr(0, colonIndex)); + try { + port = boost::lexical_cast<int>(hostAndPort.substr(colonIndex + 1)); + } + catch (const boost::bad_lexical_cast&) { + return URL(); + } + } + else { + host = unescape(hostAndPort); + } + + if (port) { + return URL(scheme, host, *port, path); + } + else { + return URL(scheme, host, path); + } + } + else { + // We don't support URLs without authorities yet + return URL(); + } +} + +// FIXME: Escape non-ascii characters +std::string URL::toString() const { + if (empty) { + return ""; + } + std::string result = scheme + "://"; + if (!user.empty()) { + result += user; + if (!password.empty()) { + result += ":" + password; + } + result += "@"; + } + result += host; + if (port) { + result += ":"; + result += boost::lexical_cast<std::string>(*port); + } + result += path; + return result; +} + +// Disabling this code for now, since GCC4.5+boost1.42 (on ubuntu) seems to +// result in a bug. Replacing it with naive code. +#if 0 +// Should be in anonymous namespace, but older GCCs complain if we do that +struct PercentEncodedCharacterFinder { +template<typename Iterator> +boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { + boost::iterator_range<Iterator> r = boost::first_finder("%")(begin, end); + if (r.end() == end) { + return r; + } + else { + if (r.end() + 1 == end || r.end() + 2 == end) { + throw std::runtime_error("Incomplete escape character"); + } + else { + r.advance_end(2); + return r; + } + } +} +}; + +struct PercentUnencodeFormatter { +template<typename FindResult> +std::string operator()(const FindResult& match) const { + std::stringstream s; + s << std::hex << std::string(match.begin() + 1, match.end()); + unsigned int value; + s >> value; + if (s.fail() || s.bad()) { + throw std::runtime_error("Invalid escape character"); + } + unsigned char charValue = static_cast<unsigned char>(value); + return std::string(reinterpret_cast<const char*>(&charValue), 1); +} +}; + +std::string unescape(const std::string& s) { + try { + return boost::find_format_all_copy(s, PercentEncodedCharacterFinder(), PercentUnencodeFormatter()); + } + catch (const std::exception&) { + return ""; + } +} +#endif + +std::string URL::unescape(const std::string& str) { + std::string result; + for (size_t i = 0; i < str.size(); ++i) { + if (str[i] == '%') { + if (i + 3 < str.size()) { + std::stringstream s; + s << std::hex << str.substr(i+1, 2); + unsigned int value; + s >> value; + if (s.fail() || s.bad()) { + return ""; + } + unsigned char charValue = static_cast<unsigned char>(value); + result += std::string(reinterpret_cast<const char*>(&charValue), 1); + i += 2; + } + else { + return ""; + } + } + else { + result += str[i]; + } + } + return result; +} + +} diff --git a/Swiften/Base/URL.h b/Swiften/Base/URL.h index 7a5aa59..75cf1a6 100644 --- a/Swiften/Base/URL.h +++ b/Swiften/Base/URL.h @@ -8,15 +8,20 @@ #include <string> +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> namespace Swift { -class URL { +class SWIFTEN_API URL { public: - URL() : scheme(""), user(""), password(""), host(""), port(-1), path(""), isEmpty(true) { + URL() : scheme(""), user(""), password(""), host(""), path(""), empty(true) { } - URL(const std::string& scheme, const std::string& host, int port, const std::string& path) : scheme(scheme), user(), password(), host(host), port(port), path(path), isEmpty(false) { + URL(const std::string& scheme, const std::string& host, int port, const std::string& path) : scheme(scheme), user(), password(), host(host), port(port), path(path), empty(false) { + } + URL(const std::string& scheme, const std::string& host, const std::string& path) : scheme(scheme), user(), password(), host(host), path(path), empty(false) { } @@ -24,6 +29,6 @@ class URL { * Whether the URL is empty. */ - bool empty() const { - return isEmpty; + bool isEmpty() const { + return empty; } @@ -45,5 +50,5 @@ class URL { * Port number */ - int getPort() const { + boost::optional<int> getPort() const { return port; } @@ -56,4 +61,9 @@ class URL { } + std::string toString() const; + + static int getPortOrDefaultPort(const URL& url); + static URL fromString(const std::string&); + static std::string unescape(const std::string&); @@ -63,7 +73,7 @@ class URL { std::string password; std::string host; - int port; + boost::optional<int> port; std::string path; - bool isEmpty; + bool empty; }; } diff --git a/Swiften/Base/UnitTest/PathTest.cpp b/Swiften/Base/UnitTest/PathTest.cpp new file mode 100644 index 0000000..f5f99e7 --- /dev/null +++ b/Swiften/Base/UnitTest/PathTest.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 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/Base/Path.h> +#include <Swiften/Base/Platform.h> + +using namespace Swift; + +class PathTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(PathTest); + CPPUNIT_TEST(testStringToPath); + CPPUNIT_TEST(testPathToString); + CPPUNIT_TEST_SUITE_END(); + + public: + void testStringToPath() { +#ifdef SWIFTEN_PLATFORM_WINDOWS + CPPUNIT_ASSERT(std::wstring(L"tron\xe7on") == stringToPath("tron\xc3\xa7on").native()); +#else + CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), stringToPath("tron\xc3\xa7on").native()); +#endif + } + + void testPathToString() { + CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), pathToString(stringToPath("tron\xc3\xa7on"))); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PathTest); + diff --git a/Swiften/Base/UnitTest/StringTest.cpp b/Swiften/Base/UnitTest/StringTest.cpp index b29f331..ffca98a 100644 --- a/Swiften/Base/UnitTest/StringTest.cpp +++ b/Swiften/Base/UnitTest/StringTest.cpp @@ -10,4 +10,5 @@ #include <Swiften/Base/String.h> +#include <Swiften/Base/Platform.h> using namespace Swift; @@ -25,4 +26,8 @@ class StringTest : public CppUnit::TestFixture { CPPUNIT_TEST(testReplaceAll_MatchingReplace); CPPUNIT_TEST(testSplit); +#ifdef SWIFTEN_PLATFORM_WINDOWS + CPPUNIT_TEST(testConvertWStringToString); + CPPUNIT_TEST(testConvertStringToWString); +#endif CPPUNIT_TEST_SUITE_END(); @@ -110,4 +115,14 @@ class StringTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("ghi"), result[2]); } + +#ifdef SWIFTEN_PLATFORM_WINDOWS + void testConvertWStringToString() { + CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), convertWStringToString(std::wstring(L"tron\xe7on"))); + } + + void testConvertStringToWString() { + CPPUNIT_ASSERT(std::wstring(L"tron\xe7on") == convertStringToWString(std::string("tron\xc3\xa7on"))); + } +#endif }; diff --git a/Swiften/Base/UnitTest/URLTest.cpp b/Swiften/Base/UnitTest/URLTest.cpp new file mode 100644 index 0000000..e82321f --- /dev/null +++ b/Swiften/Base/UnitTest/URLTest.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2012 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/Base/URL.h> +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +class URLTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(URLTest); + CPPUNIT_TEST(testFromString); + CPPUNIT_TEST(testFromString_WithoutPath); + CPPUNIT_TEST(testFromString_WithRootPath); + CPPUNIT_TEST(testFromString_WithPort); + CPPUNIT_TEST(testFromString_WithPortOnePartPath); + CPPUNIT_TEST(testFromString_WithPortWithoutPath); + CPPUNIT_TEST(testFromString_WithUserInfo); + CPPUNIT_TEST(testFromString_NonASCIIHost); + CPPUNIT_TEST(testFromString_NonASCIIPath); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST(testToString_WithPort); + CPPUNIT_TEST_SUITE_END(); + + public: + void testFromString() { + URL url = URL::fromString("http://foo.bar/baz/bam"); + + CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); + CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); + CPPUNIT_ASSERT(!url.getPort()); + CPPUNIT_ASSERT_EQUAL(std::string("/baz/bam"), url.getPath()); + } + + void testFromString_WithoutPath() { + URL url = URL::fromString("http://foo.bar"); + + CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); + CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); + CPPUNIT_ASSERT(!url.getPort()); + CPPUNIT_ASSERT_EQUAL(std::string(""), url.getPath()); + } + + void testFromString_WithRootPath() { + URL url = URL::fromString("http://foo.bar/"); + + CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); + CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); + CPPUNIT_ASSERT(!url.getPort()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), url.getPath()); + } + + void testFromString_WithPort() { + URL url = URL::fromString("http://foo.bar:1234/baz/bam"); + + CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); + CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); + CPPUNIT_ASSERT_EQUAL(1234, *url.getPort()); + CPPUNIT_ASSERT_EQUAL(std::string("/baz/bam"), url.getPath()); + } + + void testFromString_WithPortOnePartPath() { + URL url = URL::fromString("http://foo.bar:11440/http-bind/"); + + CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); + CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); + CPPUNIT_ASSERT_EQUAL(11440, *url.getPort()); + CPPUNIT_ASSERT_EQUAL(std::string("/http-bind/"), url.getPath()); + } + + void testFromString_WithPortWithoutPath() { + URL url = URL::fromString("http://foo.bar:1234"); + + CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); + CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); + CPPUNIT_ASSERT_EQUAL(1234, *url.getPort()); + CPPUNIT_ASSERT_EQUAL(std::string(""), url.getPath()); + } + + void testFromString_WithUserInfo() { + URL url = URL::fromString("http://user:pass@foo.bar/baz/bam"); + + CPPUNIT_ASSERT_EQUAL(std::string("http"), url.getScheme()); + CPPUNIT_ASSERT_EQUAL(std::string("foo.bar"), url.getHost()); + CPPUNIT_ASSERT_EQUAL(std::string("/baz/bam"), url.getPath()); + } + + void testFromString_NonASCIIHost() { + URL url = URL::fromString("http://www.tron%C3%A7on.be/baz/bam"); + + CPPUNIT_ASSERT_EQUAL(std::string("www.tron\xc3\xa7on.be"), url.getHost()); + } + + void testFromString_NonASCIIPath() { + URL url = URL::fromString("http://foo.bar/baz/tron%C3%A7on/bam"); + + CPPUNIT_ASSERT_EQUAL(std::string("/baz/tron\xc3\xa7on/bam"), url.getPath()); + } + + void testToString() { + CPPUNIT_ASSERT_EQUAL(std::string("http://foo.bar/baz/bam"), URL("http", "foo.bar", "/baz/bam").toString()); + } + + void testToString_WithPort() { + CPPUNIT_ASSERT_EQUAL(std::string("http://foo.bar:1234/baz/bam"), URL("http", "foo.bar", 1234, "/baz/bam").toString()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(URLTest); diff --git a/Swiften/Base/foreach.h b/Swiften/Base/foreach.h index 87f6147..3ad506d 100644 --- a/Swiften/Base/foreach.h +++ b/Swiften/Base/foreach.h @@ -11,2 +11,3 @@ #undef foreach #define foreach BOOST_FOREACH +#define reverse_foreach BOOST_REVERSE_FOREACH diff --git a/Swiften/Base/sleep.cpp b/Swiften/Base/sleep.cpp index 7161217..0f1937b 100644 --- a/Swiften/Base/sleep.cpp +++ b/Swiften/Base/sleep.cpp @@ -8,4 +8,5 @@ #include <boost/thread.hpp> +#include <boost/version.hpp> namespace Swift { @@ -13,5 +14,9 @@ namespace Swift { void sleep(unsigned int msecs) { boost::xtime xt; +#if BOOST_VERSION >= 105000 + boost::xtime_get(&xt, boost::TIME_UTC_); +#else boost::xtime_get(&xt, boost::TIME_UTC); +#endif xt.nsec += msecs*1000000; boost::thread::sleep(xt); diff --git a/Swiften/Base/sleep.h b/Swiften/Base/sleep.h index a95e907..afcf6c7 100644 --- a/Swiften/Base/sleep.h +++ b/Swiften/Base/sleep.h @@ -7,5 +7,7 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { - void sleep(unsigned int msecs); + SWIFTEN_API void sleep(unsigned int msecs); } diff --git a/Swiften/Chat/ChatStateNotifier.h b/Swiften/Chat/ChatStateNotifier.h index c691092..5b99266 100644 --- a/Swiften/Chat/ChatStateNotifier.h +++ b/Swiften/Chat/ChatStateNotifier.h @@ -10,4 +10,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Message.h> #include <Swiften/Elements/ChatState.h> @@ -18,5 +19,5 @@ namespace Swift { class EntityCapsProvider; - class ChatStateNotifier { + class SWIFTEN_API ChatStateNotifier { public: ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager); diff --git a/Swiften/Chat/ChatStateTracker.h b/Swiften/Chat/ChatStateTracker.h index b356644..e401b0a 100644 --- a/Swiften/Chat/ChatStateTracker.h +++ b/Swiften/Chat/ChatStateTracker.h @@ -9,4 +9,5 @@ #include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Message.h> @@ -15,5 +16,5 @@ namespace Swift { - class ChatStateTracker { + class SWIFTEN_API ChatStateTracker { public: ChatStateTracker(); diff --git a/Swiften/Client/BlockList.cpp b/Swiften/Client/BlockList.cpp index 0b2fc12..3ee7864 100644 --- a/Swiften/Client/BlockList.cpp +++ b/Swiften/Client/BlockList.cpp @@ -7,4 +7,6 @@ #include <Swiften/Client/BlockList.h> +#include <algorithm> + using namespace Swift; @@ -12,2 +14,9 @@ BlockList::~BlockList() { } + +bool BlockList::isBlocked(const JID& jid) const { + const std::vector<JID>& items = getItems(); + return (std::find(items.begin(), items.end(), jid.toBare()) != items.end()) || + (std::find(items.begin(), items.end(), JID(jid.getDomain())) != items.end()) || + (std::find(items.begin(), items.end(), jid) != items.end()); +} diff --git a/Swiften/Client/BlockList.h b/Swiften/Client/BlockList.h index 39a211d..99c83c1 100644 --- a/Swiften/Client/BlockList.h +++ b/Swiften/Client/BlockList.h @@ -7,5 +7,5 @@ #pragma once -#include <set> +#include <vector> #include <Swiften/JID/JID.h> @@ -16,7 +16,8 @@ namespace Swift { public: enum State { + Init, Requesting, Available, - Error, + Error }; virtual ~BlockList(); @@ -24,5 +25,7 @@ namespace Swift { virtual State getState() const = 0; - virtual const std::set<JID>& getItems() const = 0; + virtual const std::vector<JID>& getItems() const = 0; + + bool isBlocked(const JID& jid) const; public: diff --git a/Swiften/Client/BlockListImpl.cpp b/Swiften/Client/BlockListImpl.cpp index dfaaaf1..5950233 100644 --- a/Swiften/Client/BlockListImpl.cpp +++ b/Swiften/Client/BlockListImpl.cpp @@ -9,16 +9,30 @@ #include <Swiften/Base/foreach.h> +#include <algorithm> + using namespace Swift; -BlockListImpl::BlockListImpl() { +BlockListImpl::BlockListImpl() : state(Init) { } void BlockListImpl::setItems(const std::vector<JID>& items) { - this->items = std::set<JID>(items.begin(), items.end()); + foreach (const JID& jid, this->items) { + if (std::find(items.begin(), items.end(), jid) != items.end()) { + onItemRemoved(jid); + } + } + + foreach (const JID& jid, items) { + if (std::find(this->items.begin(), this->items.end(), jid) != this->items.end()) { + onItemAdded(jid); + } + } + this->items = items; } void BlockListImpl::addItem(const JID& item) { - if (items.insert(item).second) { + if (std::find(items.begin(), items.end(), item) == items.end()) { + items.push_back(item); onItemAdded(item); } @@ -26,5 +40,7 @@ void BlockListImpl::addItem(const JID& item) { void BlockListImpl::removeItem(const JID& item) { - if (items.erase(item)) { + size_t oldSize = items.size(); + items.erase(std::remove(items.begin(), items.end(), item), items.end()); + if (items.size() != oldSize) { onItemRemoved(item); } @@ -33,4 +49,5 @@ void BlockListImpl::removeItem(const JID& item) { void BlockListImpl::setState(State state) { if (this->state != state) { + this->state = state; onStateChanged(); } @@ -44,5 +61,6 @@ void BlockListImpl::addItems(const std::vector<JID>& items) { void BlockListImpl::removeItems(const std::vector<JID>& items) { - foreach (const JID& item, items) { + std::vector<JID> itemsToRemove = items; + foreach (const JID& item, itemsToRemove) { removeItem(item); } @@ -50,7 +68,5 @@ void BlockListImpl::removeItems(const std::vector<JID>& items) { void BlockListImpl::removeAllItems() { - foreach (const JID& item, items) { - removeItem(item); - } + removeItems(items); } diff --git a/Swiften/Client/BlockListImpl.h b/Swiften/Client/BlockListImpl.h index ef08340..2a799ae 100644 --- a/Swiften/Client/BlockListImpl.h +++ b/Swiften/Client/BlockListImpl.h @@ -20,5 +20,5 @@ namespace Swift { void setState(State state); - virtual const std::set<JID>& getItems() const { + virtual const std::vector<JID>& getItems() const { return items; } @@ -33,5 +33,5 @@ namespace Swift { private: State state; - std::set<JID> items; + std::vector<JID> items; }; } diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 4d3ee04..f158370 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2012 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -15,4 +15,5 @@ #include <Swiften/MUC/MUCRegistry.h> #include <Swiften/MUC/MUCManager.h> +#include <Swiften/PubSub/PubSubManagerImpl.h> #include <Swiften/Client/MemoryStorages.h> #include <Swiften/VCards/VCardManager.h> @@ -30,4 +31,6 @@ #include <Swiften/Network/NetworkFactories.h> #include <Swiften/FileTransfer/FileTransferManagerImpl.h> +#include <Swiften/Whiteboard/WhiteboardSessionManager.h> +#include <Swiften/Client/ClientBlockListManager.h> #ifndef SWIFT_EXPERIMENTAL_FT #include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h> @@ -37,5 +40,5 @@ namespace Swift { Client::Client(const JID& jid, const SafeString& password, NetworkFactories* networkFactories, Storages* storages) : CoreClient(jid, password, networkFactories), storages(storages) { - memoryStorages = new MemoryStorages(); + memoryStorages = new MemoryStorages(networkFactories->getCryptoProvider()); softwareVersionResponder = new SoftwareVersionResponder(getIQRouter()); @@ -52,5 +55,5 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net stanzaChannelPresenceSender = new StanzaChannelPresenceSender(getStanzaChannel()); directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); - discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender); + discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender, networkFactories->getCryptoProvider()); mucRegistry = new MUCRegistry(); @@ -58,6 +61,6 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net vcardManager = new VCardManager(jid, getIQRouter(), getStorages()->getVCardStorage()); - avatarManager = new AvatarManagerImpl(vcardManager, getStanzaChannel(), getStorages()->getAvatarStorage(), mucRegistry); - capsManager = new CapsManager(getStorages()->getCapsStorage(), getStanzaChannel(), getIQRouter()); + avatarManager = new AvatarManagerImpl(vcardManager, getStanzaChannel(), getStorages()->getAvatarStorage(), networkFactories->getCryptoProvider(), mucRegistry); + capsManager = new CapsManager(getStorages()->getCapsStorage(), getStanzaChannel(), getIQRouter(), networkFactories->getCryptoProvider()); entityCapsManager = new EntityCapsManager(capsManager, getStanzaChannel()); @@ -68,8 +71,19 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net jingleSessionManager = new JingleSessionManager(getIQRouter()); + blockListManager = new ClientBlockListManager(getIQRouter()); fileTransferManager = NULL; + + whiteboardSessionManager = NULL; +#ifdef SWIFT_EXPERIMENTAL_WB + whiteboardSessionManager = new WhiteboardSessionManager(getIQRouter(), getStanzaChannel(), presenceOracle, getEntityCapsProvider()); +#endif + + pubsubManager = new PubSubManagerImpl(getStanzaChannel(), getIQRouter()); } Client::~Client() { + delete pubsubManager; + delete whiteboardSessionManager; + delete fileTransferManager; delete jingleSessionManager; @@ -113,5 +127,16 @@ void Client::setSoftwareVersion(const std::string& name, const std::string& vers void Client::handleConnected() { #ifdef SWIFT_EXPERIMENTAL_FT - fileTransferManager = new FileTransferManagerImpl(getJID(), jingleSessionManager, getIQRouter(), getEntityCapsProvider(), presenceOracle, getNetworkFactories()->getConnectionFactory(), getNetworkFactories()->getConnectionServerFactory(), getNetworkFactories()->getTimerFactory(), getNetworkFactories()->getNATTraverser()); + fileTransferManager = new FileTransferManagerImpl( + getJID(), + jingleSessionManager, + getIQRouter(), + getEntityCapsProvider(), + presenceOracle, + getNetworkFactories()->getConnectionFactory(), + getNetworkFactories()->getConnectionServerFactory(), + getNetworkFactories()->getTimerFactory(), + getNetworkFactories()->getNetworkEnvironment(), + getNetworkFactories()->getNATTraverser(), + getNetworkFactories()->getCryptoProvider()); #else fileTransferManager = new DummyFileTransferManager(); @@ -165,3 +190,7 @@ FileTransferManager* Client::getFileTransferManager() const { } +WhiteboardSessionManager* Client::getWhiteboardSessionManager() const { + return whiteboardSessionManager; +} + } diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index 940a526..9253074 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -7,6 +7,6 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Client/CoreClient.h> - #include <Swiften/Base/SafeString.h> @@ -37,4 +37,7 @@ namespace Swift { class JingleSessionManager; class FileTransferManager; + class WhiteboardSessionManager; + class ClientBlockListManager; + class PubSubManager; /** @@ -44,5 +47,5 @@ namespace Swift { * performing most tasks on the XMPP network. */ - class Client : public CoreClient { + class SWIFTEN_API Client : public CoreClient { public: /** @@ -136,4 +139,8 @@ namespace Swift { } + ClientBlockListManager* getClientBlockListManager() const { + return blockListManager; + } + /** * Returns a FileTransferManager for the client. This is only available after the onConnected @@ -152,4 +159,11 @@ namespace Swift { void setAlwaysTrustCertificates(); + WhiteboardSessionManager* getWhiteboardSessionManager() const; + + PubSubManager* getPubSubManager() const { + return pubsubManager; + } + + public: /** @@ -186,4 +200,7 @@ namespace Swift { FileTransferManager* fileTransferManager; BlindCertificateTrustChecker* blindCertificateTrustChecker; + WhiteboardSessionManager* whiteboardSessionManager; + ClientBlockListManager* blockListManager; + PubSubManager* pubsubManager; }; } diff --git a/Swiften/Client/ClientBlockListManager.cpp b/Swiften/Client/ClientBlockListManager.cpp index 7222cea..de43631 100644 --- a/Swiften/Client/ClientBlockListManager.cpp +++ b/Swiften/Client/ClientBlockListManager.cpp @@ -67,11 +67,11 @@ namespace { ClientBlockListManager::ClientBlockListManager(IQRouter* iqRouter) : iqRouter(iqRouter) { + } ClientBlockListManager::~ClientBlockListManager() { + if (blockList && blockList->getState() == BlockList::Available) { unblockResponder->stop(); blockResponder->stop(); - if (getRequest) { - getRequest->onResponse.disconnect(boost::bind(&ClientBlockListManager::handleBlockListReceived, this, _1, _2)); } } @@ -80,13 +80,43 @@ boost::shared_ptr<BlockList> ClientBlockListManager::getBlockList() { if (!blockList) { blockList = boost::make_shared<BlockListImpl>(); + blockList->setState(BlockList::Init); + } + return blockList; +} + +boost::shared_ptr<BlockList> ClientBlockListManager::requestBlockList() { + if (!blockList) { + blockList = boost::make_shared<BlockListImpl>(); + } blockList->setState(BlockList::Requesting); - assert(!getRequest); - getRequest = boost::make_shared< GenericRequest<BlockListPayload> >(IQ::Get, JID(), boost::make_shared<BlockListPayload>(), iqRouter); + boost::shared_ptr<GenericRequest<BlockListPayload> > getRequest = boost::make_shared< GenericRequest<BlockListPayload> >(IQ::Get, JID(), boost::make_shared<BlockListPayload>(), iqRouter); getRequest->onResponse.connect(boost::bind(&ClientBlockListManager::handleBlockListReceived, this, _1, _2)); getRequest->send(); - } return blockList; } +GenericRequest<BlockPayload>::ref ClientBlockListManager::createBlockJIDRequest(const JID& jid) { + return createBlockJIDsRequest(std::vector<JID>(1, jid)); +} + +GenericRequest<BlockPayload>::ref ClientBlockListManager::createBlockJIDsRequest(const std::vector<JID>& jids) { + boost::shared_ptr<BlockPayload> payload = boost::make_shared<BlockPayload>(jids); + return boost::make_shared< GenericRequest<BlockPayload> >(IQ::Set, JID(), payload, iqRouter); +} + +GenericRequest<UnblockPayload>::ref ClientBlockListManager::createUnblockJIDRequest(const JID& jid) { + return createUnblockJIDsRequest(std::vector<JID>(1, jid)); +} + +GenericRequest<UnblockPayload>::ref ClientBlockListManager::createUnblockJIDsRequest(const std::vector<JID>& jids) { + boost::shared_ptr<UnblockPayload> payload = boost::make_shared<UnblockPayload>(jids); + return boost::make_shared< GenericRequest<UnblockPayload> >(IQ::Set, JID(), payload, iqRouter); +} + +GenericRequest<UnblockPayload>::ref ClientBlockListManager::createUnblockAllRequest() { + return createUnblockJIDsRequest(std::vector<JID>()); +} + + void ClientBlockListManager::handleBlockListReceived(boost::shared_ptr<BlockListPayload> payload, ErrorPayload::ref error) { if (error || !payload) { @@ -94,11 +124,15 @@ void ClientBlockListManager::handleBlockListReceived(boost::shared_ptr<BlockList } else { - blockList->setState(BlockList::Available); blockList->setItems(payload->getItems()); + blockList->setState(BlockList::Available); + if (!blockResponder) { blockResponder = boost::make_shared<BlockResponder>(blockList, iqRouter); blockResponder->start(); + } + if (!unblockResponder) { unblockResponder = boost::make_shared<UnblockResponder>(blockList, iqRouter); unblockResponder->start(); } } +} diff --git a/Swiften/Client/ClientBlockListManager.h b/Swiften/Client/ClientBlockListManager.h index 21d35e3..e715737 100644 --- a/Swiften/Client/ClientBlockListManager.h +++ b/Swiften/Client/ClientBlockListManager.h @@ -13,4 +13,5 @@ #include <Swiften/Elements/BlockListPayload.h> #include <Swiften/Elements/UnblockPayload.h> +#include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Queries/SetResponder.h> #include <Swiften/Queries/GenericRequest.h> @@ -26,6 +27,4 @@ namespace Swift { ~ClientBlockListManager(); - bool isSupported() const; - /** * Returns the blocklist. @@ -33,4 +32,16 @@ namespace Swift { boost::shared_ptr<BlockList> getBlockList(); + /** + * Get the blocklist from the server. + */ + boost::shared_ptr<BlockList> requestBlockList(); + + GenericRequest<BlockPayload>::ref createBlockJIDRequest(const JID& jid); + GenericRequest<BlockPayload>::ref createBlockJIDsRequest(const std::vector<JID>& jids); + + GenericRequest<UnblockPayload>::ref createUnblockJIDRequest(const JID& jid); + GenericRequest<UnblockPayload>::ref createUnblockJIDsRequest(const std::vector<JID>& jids); + GenericRequest<UnblockPayload>::ref createUnblockAllRequest(); + private: void handleBlockListReceived(boost::shared_ptr<BlockListPayload> payload, ErrorPayload::ref); @@ -38,5 +49,4 @@ namespace Swift { private: IQRouter* iqRouter; - boost::shared_ptr<GenericRequest<BlockListPayload> > getRequest; boost::shared_ptr<SetResponder<BlockPayload> > blockResponder; boost::shared_ptr<SetResponder<UnblockPayload> > unblockResponder; diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h index fbec272..e5fcda9 100644 --- a/Swiften/Client/ClientOptions.h +++ b/Swiften/Client/ClientOptions.h @@ -18,5 +18,25 @@ namespace Swift { }; - ClientOptions() : useStreamCompression(true), useTLS(UseTLSWhenAvailable), allowPLAINWithoutTLS(false), useStreamResumption(false), forgetPassword(false), useAcks(true), boshHTTPConnectProxyAuthID(""), boshHTTPConnectProxyAuthPassword("") { + enum ProxyType { + NoProxy, + SystemConfiguredProxy, + SOCKS5Proxy, + HTTPConnectProxy + }; + + ClientOptions() : + useStreamCompression(true), + useTLS(UseTLSWhenAvailable), + allowPLAINWithoutTLS(false), + useStreamResumption(false), + forgetPassword(false), + useAcks(true), + manualHostname(""), + manualPort(-1), + proxyType(SystemConfiguredProxy), + manualProxyHostname(""), + manualProxyPort(-1), + boshHTTPConnectProxyAuthID(""), + boshHTTPConnectProxyAuthPassword("") { } @@ -67,4 +87,33 @@ namespace Swift { /** + * The hostname to connect to. + * Leave this empty for standard XMPP connection, based on the JID domain. + */ + std::string manualHostname; + + /** + * The port to connect to. + * Leave this to -1 to use the port discovered by SRV lookups, and 5222 as a + * fallback. + */ + int manualPort; + + /** + * The type of proxy to use for connecting to the XMPP + * server. + */ + ProxyType proxyType; + + /** + * Override the system-configured proxy hostname. + */ + std::string manualProxyHostname; + + /** + * Override the system-configured proxy port. + */ + int manualProxyPort; + + /** * If non-empty, use BOSH instead of direct TCP, with the given URL. * Default: empty (no BOSH) diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 70f0398..500299a 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -38,6 +38,8 @@ #include <Swiften/Elements/ResourceBind.h> #include <Swiften/SASL/PLAINClientAuthenticator.h> +#include <Swiften/SASL/EXTERNALClientAuthenticator.h> #include <Swiften/SASL/SCRAMSHA1ClientAuthenticator.h> #include <Swiften/SASL/DIGESTMD5ClientAuthenticator.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Session/SessionStream.h> #include <Swiften/TLS/CertificateTrustChecker.h> @@ -48,12 +50,19 @@ #endif +#define CHECK_STATE_OR_RETURN(a) \ + if (!checkState(a)) { return; } + namespace Swift { ClientSession::ClientSession( const JID& jid, - boost::shared_ptr<SessionStream> stream) : + boost::shared_ptr<SessionStream> stream, + IDNConverter* idnConverter, + CryptoProvider* crypto) : localJID(jid), state(Initial), stream(stream), + idnConverter(idnConverter), + crypto(crypto), allowPLAINOverNonTLS(false), useStreamCompression(true), @@ -101,9 +110,9 @@ void ClientSession::sendStanza(boost::shared_ptr<Stanza> stanza) { void ClientSession::handleStreamStart(const ProtocolHeader&) { - checkState(WaitingForStreamStart); + CHECK_STATE_OR_RETURN(WaitingForStreamStart); state = Negotiating; } -void ClientSession::handleElement(boost::shared_ptr<Element> element) { +void ClientSession::handleElement(boost::shared_ptr<ToplevelElement> element) { if (boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element)) { if (stanzaAckResponder_) { @@ -162,9 +171,9 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else { - std::cerr << "Warning: Got invalid ack from server" << std::endl; + SWIFT_LOG(warning) << "Got invalid ack from server"; } } else { - std::cerr << "Warning: Ignoring ack" << std::endl; + SWIFT_LOG(warning) << "Ignoring ack"; } } @@ -182,7 +191,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (StreamFeatures* streamFeatures = dynamic_cast<StreamFeatures*>(element.get())) { - if (!checkState(Negotiating)) { - return; - } + CHECK_STATE_OR_RETURN(Negotiating); if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption() && useTLS != NeverUseTLS) { @@ -200,4 +207,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { if (stream->hasTLSCertificate()) { if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { + authenticator = new EXTERNALClientAuthenticator(); state = Authenticating; stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); @@ -208,4 +216,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { + authenticator = new EXTERNALClientAuthenticator(); state = Authenticating; stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); @@ -214,12 +223,12 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { std::ostringstream s; ByteArray finishMessage; - bool plus = stream->isTLSEncrypted() && streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1-PLUS"); - if (plus) { + bool plus = streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1-PLUS"); + if (stream->isTLSEncrypted()) { finishMessage = stream->getTLSFinishMessage(); plus &= !finishMessage.empty(); } s << boost::uuids::random_generator()(); - SCRAMSHA1ClientAuthenticator* scramAuthenticator = new SCRAMSHA1ClientAuthenticator(s.str(), plus); - if (plus) { + SCRAMSHA1ClientAuthenticator* scramAuthenticator = new SCRAMSHA1ClientAuthenticator(s.str(), plus, idnConverter, crypto); + if (!finishMessage.empty()) { scramAuthenticator->setTLSChannelBindingData(finishMessage); } @@ -233,9 +242,9 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { onNeedCredentials(); } - else if (streamFeatures->hasAuthenticationMechanism("DIGEST-MD5") && DIGESTMD5ClientAuthenticator::canBeUsed()) { + else if (streamFeatures->hasAuthenticationMechanism("DIGEST-MD5") && crypto->isMD5AllowedForCrypto()) { std::ostringstream s; s << boost::uuids::random_generator()(); // FIXME: Host should probably be the actual host - authenticator = new DIGESTMD5ClientAuthenticator(localJID.getDomain(), s.str()); + authenticator = new DIGESTMD5ClientAuthenticator(localJID.getDomain(), s.str(), crypto); state = WaitingForCredentials; onNeedCredentials(); @@ -262,5 +271,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (boost::dynamic_pointer_cast<Compressed>(element)) { - checkState(Compressing); + CHECK_STATE_OR_RETURN(Compressing); state = WaitingForStreamStart; stream->addZLibCompression(); @@ -285,5 +294,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (AuthChallenge* challenge = dynamic_cast<AuthChallenge*>(element.get())) { - checkState(Authenticating); + CHECK_STATE_OR_RETURN(Authenticating); assert(authenticator); if (authenticator->setChallenge(challenge->getValue())) { @@ -295,8 +304,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (AuthSuccess* authSuccess = dynamic_cast<AuthSuccess*>(element.get())) { - checkState(Authenticating); - if (authenticator && !authenticator->setChallenge(authSuccess->getValue())) { - delete authenticator; - authenticator = NULL; + CHECK_STATE_OR_RETURN(Authenticating); + assert(authenticator); + if (!authenticator->setChallenge(authSuccess->getValue())) { finishSession(Error::ServerVerificationFailedError); } @@ -310,10 +318,8 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (dynamic_cast<AuthFailure*>(element.get())) { - delete authenticator; - authenticator = NULL; finishSession(Error::AuthenticationFailedError); } else if (dynamic_cast<TLSProceed*>(element.get())) { - checkState(WaitingForEncrypt); + CHECK_STATE_OR_RETURN(WaitingForEncrypt); state = Encrypting; stream->addTLSEncryption(); @@ -362,4 +368,5 @@ bool ClientSession::checkState(State state) { void ClientSession::sendCredentials(const SafeByteArray& password) { assert(WaitingForCredentials); + assert(authenticator); state = Authenticating; authenticator->setCredentials(localJID.getNode(), password); @@ -368,24 +375,24 @@ void ClientSession::sendCredentials(const SafeByteArray& password) { void ClientSession::handleTLSEncrypted() { - checkState(Encrypting); + CHECK_STATE_OR_RETURN(Encrypting); - Certificate::ref certificate = stream->getPeerCertificate(); + std::vector<Certificate::ref> certificateChain = stream->getPeerCertificateChain(); boost::shared_ptr<CertificateVerificationError> verificationError = stream->getPeerCertificateVerificationError(); if (verificationError) { - checkTrustOrFinish(certificate, verificationError); + checkTrustOrFinish(certificateChain, verificationError); } else { - ServerIdentityVerifier identityVerifier(localJID); - if (identityVerifier.certificateVerifies(certificate)) { + ServerIdentityVerifier identityVerifier(localJID, idnConverter); + if (!certificateChain.empty() && identityVerifier.certificateVerifies(certificateChain[0])) { continueAfterTLSEncrypted(); } else { - checkTrustOrFinish(certificate, boost::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidServerIdentity)); + checkTrustOrFinish(certificateChain, boost::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidServerIdentity)); } } } -void ClientSession::checkTrustOrFinish(Certificate::ref certificate, boost::shared_ptr<CertificateVerificationError> error) { - if (certificateTrustChecker && certificateTrustChecker->isCertificateTrusted(certificate)) { +void ClientSession::checkTrustOrFinish(const std::vector<Certificate::ref>& certificateChain, boost::shared_ptr<CertificateVerificationError> error) { + if (certificateTrustChecker && certificateTrustChecker->isCertificateTrusted(certificateChain)) { continueAfterTLSEncrypted(); } @@ -441,8 +448,15 @@ void ClientSession::finishSession(boost::shared_ptr<Swift::Error> error) { error_ = error; } + else { + SWIFT_LOG(warning) << "Session finished twice"; + } assert(stream->isOpen()); if (stanzaAckResponder_) { stanzaAckResponder_->handleAckRequestReceived(); } + if (authenticator) { + delete authenticator; + authenticator = NULL; + } stream->writeFooter(); stream->close(); diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index 2205c8d..8a3deb4 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,9 +11,10 @@ #include <boost/enable_shared_from_this.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/Error.h> #include <Swiften/Session/SessionStream.h> #include <string> #include <Swiften/JID/JID.h> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/StreamManagement/StanzaAckRequester.h> #include <Swiften/StreamManagement/StanzaAckResponder.h> @@ -22,6 +23,8 @@ namespace Swift { class ClientAuthenticator; class CertificateTrustChecker; + class IDNConverter; + class CryptoProvider; - class ClientSession : public boost::enable_shared_from_this<ClientSession> { + class SWIFTEN_API ClientSession : public boost::enable_shared_from_this<ClientSession> { public: enum State { @@ -53,5 +56,5 @@ namespace Swift { TLSClientCertificateError, TLSError, - StreamError, + StreamError } type; Error(Type type) : type(type) {} @@ -66,6 +69,6 @@ namespace Swift { ~ClientSession(); - static boost::shared_ptr<ClientSession> create(const JID& jid, boost::shared_ptr<SessionStream> stream) { - return boost::shared_ptr<ClientSession>(new ClientSession(jid, stream)); + static boost::shared_ptr<ClientSession> create(const JID& jid, boost::shared_ptr<SessionStream> stream, IDNConverter* idnConverter, CryptoProvider* crypto) { + return boost::shared_ptr<ClientSession>(new ClientSession(jid, stream, idnConverter, crypto)); } @@ -92,5 +95,7 @@ namespace Swift { bool getStreamManagementEnabled() const { - return stanzaAckRequester_; + // Explicitly convert to bool. In C++11, it would be cleaner to + // compare to nullptr. + return static_cast<bool>(stanzaAckRequester_); } @@ -99,4 +104,8 @@ namespace Swift { } + std::vector<Certificate::ref> getPeerCertificateChain() const { + return stream->getPeerCertificateChain(); + } + const JID& getLocalJID() const { return localJID; @@ -127,5 +136,7 @@ namespace Swift { ClientSession( const JID& jid, - boost::shared_ptr<SessionStream>); + boost::shared_ptr<SessionStream>, + IDNConverter* idnConverter, + CryptoProvider* crypto); void finishSession(Error::Type error); @@ -138,5 +149,5 @@ namespace Swift { void sendStreamHeader(); - void handleElement(boost::shared_ptr<Element>); + void handleElement(boost::shared_ptr<ToplevelElement>); void handleStreamStart(const ProtocolHeader&); void handleStreamClosed(boost::shared_ptr<Swift::Error>); @@ -151,5 +162,5 @@ namespace Swift { void ack(unsigned int handledStanzasCount); void continueAfterTLSEncrypted(); - void checkTrustOrFinish(Certificate::ref certificate, boost::shared_ptr<CertificateVerificationError> error); + void checkTrustOrFinish(const std::vector<Certificate::ref>& certificateChain, boost::shared_ptr<CertificateVerificationError> error); private: @@ -157,4 +168,6 @@ namespace Swift { State state; boost::shared_ptr<SessionStream> stream; + IDNConverter* idnConverter; + CryptoProvider* crypto; bool allowPLAINOverNonTLS; bool useStreamCompression; diff --git a/Swiften/Client/ClientSessionStanzaChannel.cpp b/Swiften/Client/ClientSessionStanzaChannel.cpp index 5dc0a42..8d85953 100644 --- a/Swiften/Client/ClientSessionStanzaChannel.cpp +++ b/Swiften/Client/ClientSessionStanzaChannel.cpp @@ -83,4 +83,11 @@ bool ClientSessionStanzaChannel::getStreamManagementEnabled() const { } +std::vector<Certificate::ref> ClientSessionStanzaChannel::getPeerCertificateChain() const { + if (session) { + return session->getPeerCertificateChain(); + } + return std::vector<Certificate::ref>(); +} + void ClientSessionStanzaChannel::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) { onStanzaAcked(stanza); diff --git a/Swiften/Client/ClientSessionStanzaChannel.h b/Swiften/Client/ClientSessionStanzaChannel.h index 47fb50e..2743a16 100644 --- a/Swiften/Client/ClientSessionStanzaChannel.h +++ b/Swiften/Client/ClientSessionStanzaChannel.h @@ -28,4 +28,5 @@ namespace Swift { void sendPresence(boost::shared_ptr<Presence> presence); bool getStreamManagementEnabled() const; + virtual std::vector<Certificate::ref> getPeerCertificateChain() const; bool isAvailable() const { diff --git a/Swiften/Client/ClientXMLTracer.cpp b/Swiften/Client/ClientXMLTracer.cpp index 405e3d1..9bfa047 100644 --- a/Swiften/Client/ClientXMLTracer.cpp +++ b/Swiften/Client/ClientXMLTracer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,10 +10,16 @@ #include <boost/bind.hpp> +#include <Swiften/Base/Platform.h> + namespace Swift { ClientXMLTracer::ClientXMLTracer(CoreClient* client, bool bosh) : bosh(bosh) { +#ifdef SWIFTEN_PLATFORM_WIN32 + beautifier = new XMLBeautifier(true, false); +#else beautifier = new XMLBeautifier(true, true); - client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, this, '<', _1)); - client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, this, '>', _1)); +#endif + onDataReadConnection = client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, this, '<', _1)); + onDataWrittenConnection = client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, this, '>', _1)); } @@ -26,12 +32,12 @@ void ClientXMLTracer::printData(char direction, const SafeByteArray& data) { if (bosh) { std::string line = byteArrayToString(ByteArray(data.begin(), data.end())); - size_t endOfHTTP = line.find("\r\n\r\n"); - if (false && endOfHTTP != std::string::npos) { - /* Disabled because it swallows bits of XML (namespaces, if I recall) */ - std::cerr << line.substr(0, endOfHTTP) << std::endl << beautifier->beautify(line.substr(endOfHTTP)) << std::endl; - } - else { +// Disabled because it swallows bits of XML (namespaces, if I recall) +// size_t endOfHTTP = line.find("\r\n\r\n"); +// if (false && endOfHTTP != std::string::npos) { +// std::cerr << line.substr(0, endOfHTTP) << std::endl << beautifier->beautify(line.substr(endOfHTTP)) << std::endl; +// } +// else { std::cerr << line << std::endl; - } +// } } else { diff --git a/Swiften/Client/ClientXMLTracer.h b/Swiften/Client/ClientXMLTracer.h index 67040c4..95e2f6f 100644 --- a/Swiften/Client/ClientXMLTracer.h +++ b/Swiften/Client/ClientXMLTracer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Client/CoreClient.h> #include <Swiften/Client/XMLBeautifier.h> @@ -12,8 +13,9 @@ namespace Swift { - class ClientXMLTracer { + class SWIFTEN_API ClientXMLTracer { public: ClientXMLTracer(CoreClient* client, bool bosh = false); ~ClientXMLTracer(); + private: void printData(char direction, const SafeByteArray& data); @@ -23,4 +25,6 @@ namespace Swift { XMLBeautifier *beautifier; bool bosh; + boost::bsignals::scoped_connection onDataReadConnection; + boost::bsignals::scoped_connection onDataWrittenConnection; }; } diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index 8a922ba..da755b1 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010-2011 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <boost/bind.hpp> +#include <boost/optional.hpp> #include <boost/smart_ptr/make_shared.hpp> @@ -54,28 +55,68 @@ CoreClient::~CoreClient() { void CoreClient::connect(const ClientOptions& o) { - SWIFT_LOG(debug) << "Connecting" << std::endl; - options = o; - connect(jid_.getDomain()); -} + SWIFT_LOG(debug) << "Connecting "; -void CoreClient::connect(const std::string& host) { forceReset(); - - SWIFT_LOG(debug) << "Connecting to host " << host << std::endl; disconnectRequested_ = false; - assert(!connector_); + + options = o; + + + // Determine connection types to use assert(proxyConnectionFactories.empty()); - if (networkFactories->getProxyProvider()->getSOCKS5Proxy().isValid()) { - proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getConnectionFactory(), networkFactories->getProxyProvider()->getSOCKS5Proxy())); + bool useDirectConnection = true; + HostAddressPort systemSOCKS5Proxy = networkFactories->getProxyProvider()->getSOCKS5Proxy(); + HostAddressPort systemHTTPConnectProxy = networkFactories->getProxyProvider()->getHTTPConnectProxy(); + switch (o.proxyType) { + case ClientOptions::NoProxy: + SWIFT_LOG(debug) << " without a proxy" << std::endl; + break; + case ClientOptions::SystemConfiguredProxy: + SWIFT_LOG(debug) << " with a system configured proxy" << std::endl; + if (systemSOCKS5Proxy.isValid()) { + SWIFT_LOG(debug) << "Found SOCK5 Proxy: " << systemSOCKS5Proxy.getAddress().toString() << ":" << systemSOCKS5Proxy.getPort() << std::endl; + proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), systemSOCKS5Proxy.getAddress().toString(), systemSOCKS5Proxy.getPort())); + } + if (systemHTTPConnectProxy.isValid()) { + SWIFT_LOG(debug) << "Found HTTPConnect Proxy: " << systemHTTPConnectProxy.getAddress().toString() << ":" << systemHTTPConnectProxy.getPort() << std::endl; + proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), systemHTTPConnectProxy.getAddress().toString(), systemHTTPConnectProxy.getPort())); + } + break; + case ClientOptions::SOCKS5Proxy: { + SWIFT_LOG(debug) << " with manual configured SOCKS5 proxy" << std::endl; + std::string proxyHostname = o.manualProxyHostname.empty() ? systemSOCKS5Proxy.getAddress().toString() : o.manualProxyHostname; + int proxyPort = o.manualProxyPort == -1 ? systemSOCKS5Proxy.getPort() : o.manualProxyPort; + SWIFT_LOG(debug) << "Proxy: " << proxyHostname << ":" << proxyPort << std::endl; + proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort)); + useDirectConnection = false; + break; + } + case ClientOptions::HTTPConnectProxy: { + SWIFT_LOG(debug) << " with manual configured HTTPConnect proxy" << std::endl; + std::string proxyHostname = o.manualProxyHostname.empty() ? systemHTTPConnectProxy.getAddress().toString() : o.manualProxyHostname; + int proxyPort = o.manualProxyPort == -1 ? systemHTTPConnectProxy.getPort() : o.manualProxyPort; + SWIFT_LOG(debug) << "Proxy: " << proxyHostname << ":" << proxyPort << std::endl; + proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), proxyHostname, proxyPort)); + useDirectConnection = false; + break; } - if(networkFactories->getProxyProvider()->getHTTPConnectProxy().isValid()) { - proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory(), networkFactories->getEventLoop(), networkFactories->getProxyProvider()->getHTTPConnectProxy().getAddress().toString(), networkFactories->getProxyProvider()->getHTTPConnectProxy().getPort())); } std::vector<ConnectionFactory*> connectionFactories(proxyConnectionFactories); - if (options.boshURL.empty()) { + if (useDirectConnection) { connectionFactories.push_back(networkFactories->getConnectionFactory()); - connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); + } + + // Create connector + std::string host = o.manualHostname.empty() ? jid_.getDomain() : o.manualHostname; + int port = o.manualPort; + boost::optional<std::string> serviceLookupPrefix; + if (o.manualHostname.empty()) { + serviceLookupPrefix = "_xmpp-client._tcp."; + } + assert(!connector_); + if (options.boshURL.isEmpty()) { + connector_ = boost::make_shared<ChainedConnector>(host, port, serviceLookupPrefix, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1, _2)); - connector_->setTimeoutMilliseconds(60*1000); + connector_->setTimeoutMilliseconds(2*60*1000); connector_->start(); } @@ -107,5 +148,5 @@ void CoreClient::connect(const std::string& host) { void CoreClient::bindSessionToStream() { - session_ = ClientSession::create(jid_, sessionStream_); + session_ = ClientSession::create(jid_, sessionStream_, networkFactories->getIDNConverter(), networkFactories->getCryptoProvider()); session_->setCertificateTrustChecker(certificateTrustChecker); session_->setUseStreamCompression(options.useStreamCompression); @@ -361,4 +402,8 @@ bool CoreClient::getStreamManagementEnabled() const { } +bool CoreClient::isStreamEncrypted() const { + return sessionStream_->isTLSEncrypted(); +} + StanzaChannel* CoreClient::getStanzaChannel() const { return stanzaChannel_; @@ -406,9 +451,9 @@ void CoreClient::resetSession() { void CoreClient::forceReset() { if (connector_) { - std::cerr << "Warning: Client not disconnected properly: Connector still active" << std::endl; + SWIFT_LOG(warning) << "Client not disconnected properly: Connector still active" << std::endl; resetConnector(); } if (sessionStream_ || connection_) { - std::cerr << "Warning: Client not disconnected properly: Session still active" << std::endl; + SWIFT_LOG(warning) << "Client not disconnected properly: Session still active" << std::endl; resetSession(); } diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index cafc634..eadfd9d 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -9,6 +9,7 @@ #include <string> #include <boost/shared_ptr.hpp> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Entity/Entity.h> #include <Swiften/JID/JID.h> @@ -46,9 +47,8 @@ namespace Swift { * for most needs. */ - class CoreClient : public Entity { + class SWIFTEN_API CoreClient : public Entity { public: /** * Constructs a client for the given JID with the given password. - * The given eventLoop will be used to post events to. */ CoreClient(const JID& jid, const SafeByteArray& password, NetworkFactories* networkFactories); @@ -75,6 +75,4 @@ namespace Swift { void disconnect(); - void connect(const std::string& host); - /** * Sends a message. @@ -128,4 +126,9 @@ namespace Swift { bool getStreamManagementEnabled() const; + /** + * Checks whether stream encryption (TLS) is currently active. + */ + bool isStreamEncrypted() const; + StanzaChannel* getStanzaChannel() const; @@ -201,5 +204,5 @@ namespace Swift { * Called before onConnected signal is emmitted. */ - virtual void handleConnected() {}; + virtual void handleConnected() {} private: diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index c2f3919..5cdedba 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -80,4 +80,8 @@ namespace Swift { } + std::vector<Certificate::ref> getPeerCertificateChain() const { + return std::vector<Certificate::ref>(); + } + std::vector<boost::shared_ptr<Stanza> > sentStanzas; bool available_; diff --git a/Swiften/Client/MemoryStorages.cpp b/Swiften/Client/MemoryStorages.cpp index fe171f7..850c1b2 100644 --- a/Swiften/Client/MemoryStorages.cpp +++ b/Swiften/Client/MemoryStorages.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,12 +10,18 @@ #include <Swiften/Disco/CapsMemoryStorage.h> #include <Swiften/Roster/RosterMemoryStorage.h> +#include <Swiften/History/SQLiteHistoryStorage.h> namespace Swift { -MemoryStorages::MemoryStorages() { - vcardStorage = new VCardMemoryStorage(); +MemoryStorages::MemoryStorages(CryptoProvider* crypto) { + vcardStorage = new VCardMemoryStorage(crypto); capsStorage = new CapsMemoryStorage(); avatarStorage = new AvatarMemoryStorage(); rosterStorage = new RosterMemoryStorage(); +#ifdef SWIFT_EXPERIMENTAL_HISTORY + historyStorage = new SQLiteHistoryStorage(":memory:"); +#else + historyStorage = NULL; +#endif } @@ -25,4 +31,5 @@ MemoryStorages::~MemoryStorages() { delete capsStorage; delete vcardStorage; + delete historyStorage; } @@ -43,4 +50,12 @@ RosterStorage* MemoryStorages::getRosterStorage() const { } +HistoryStorage* MemoryStorages::getHistoryStorage() const { +#ifdef SWIFT_EXPERIMENTAL_HISTORY + return historyStorage; +#else + return NULL; +#endif +} + } diff --git a/Swiften/Client/MemoryStorages.h b/Swiften/Client/MemoryStorages.h index ca01a7a..68ec285 100644 --- a/Swiften/Client/MemoryStorages.h +++ b/Swiften/Client/MemoryStorages.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,4 +11,5 @@ namespace Swift { class VCardMemoryStorage; + class CryptoProvider; /** @@ -18,5 +19,5 @@ namespace Swift { class MemoryStorages : public Storages { public: - MemoryStorages(); + MemoryStorages(CryptoProvider*); ~MemoryStorages(); @@ -25,4 +26,5 @@ namespace Swift { virtual CapsStorage* getCapsStorage() const; virtual RosterStorage* getRosterStorage() const; + virtual HistoryStorage* getHistoryStorage() const; private: @@ -31,4 +33,5 @@ namespace Swift { CapsStorage* capsStorage; RosterStorage* rosterStorage; + HistoryStorage* historyStorage; }; } diff --git a/Swiften/Client/NickManager.h b/Swiften/Client/NickManager.h index 288aa7b..c5a452e 100644 --- a/Swiften/Client/NickManager.h +++ b/Swiften/Client/NickManager.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <string> namespace Swift { - class NickManager { + class SWIFTEN_API NickManager { public: virtual ~NickManager(); diff --git a/Swiften/Client/NickResolver.h b/Swiften/Client/NickResolver.h index 584f2ce..306703e 100644 --- a/Swiften/Client/NickResolver.h +++ b/Swiften/Client/NickResolver.h @@ -7,7 +7,8 @@ #include <map> #include <boost/shared_ptr.hpp> +#include <string> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> -#include <string> #include <Swiften/JID/JID.h> #include <Swiften/Elements/VCard.h> @@ -17,5 +18,6 @@ namespace Swift { class MUCRegistry; class VCardManager; - class NickResolver { + + class SWIFTEN_API NickResolver { public: NickResolver(const JID& ownJID, XMPPRoster* xmppRoster, VCardManager* vcardManager, MUCRegistry* mucRegistry); diff --git a/Swiften/Client/StanzaChannel.h b/Swiften/Client/StanzaChannel.h index f1d76e0..5e85d3c 100644 --- a/Swiften/Client/StanzaChannel.h +++ b/Swiften/Client/StanzaChannel.h @@ -13,4 +13,5 @@ #include <Swiften/Elements/Message.h> #include <Swiften/Elements/Presence.h> +#include <Swiften/TLS/Certificate.h> namespace Swift { @@ -21,4 +22,5 @@ namespace Swift { virtual bool isAvailable() const = 0; virtual bool getStreamManagementEnabled() const = 0; + virtual std::vector<Certificate::ref> getPeerCertificateChain() const = 0; boost::signal<void (bool /* isAvailable */)> onAvailableChanged; diff --git a/Swiften/Client/Storages.h b/Swiften/Client/Storages.h index 1c5bbe9..76650a6 100644 --- a/Swiften/Client/Storages.h +++ b/Swiften/Client/Storages.h @@ -7,4 +7,6 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { class VCardStorage; @@ -12,4 +14,5 @@ namespace Swift { class CapsStorage; class RosterStorage; + class HistoryStorage; /** @@ -17,5 +20,5 @@ namespace Swift { * controllers. */ - class Storages { + class SWIFTEN_API Storages { public: virtual ~Storages(); @@ -25,4 +28,5 @@ namespace Swift { virtual CapsStorage* getCapsStorage() const = 0; virtual RosterStorage* getRosterStorage() const = 0; + virtual HistoryStorage* getHistoryStorage() const = 0; }; } diff --git a/Swiften/Client/UnitTest/ClientBlockListManagerTest.cpp b/Swiften/Client/UnitTest/ClientBlockListManagerTest.cpp new file mode 100644 index 0000000..dd6c95d --- /dev/null +++ b/Swiften/Client/UnitTest/ClientBlockListManagerTest.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <algorithm> + +#include <Swiften/Base/foreach.h> + +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Client/ClientBlockListManager.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/IQ.h> + +using namespace Swift; + +class ClientBlockListManagerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ClientBlockListManagerTest); + CPPUNIT_TEST(testFetchBlockList); + CPPUNIT_TEST(testBlockCommand); + CPPUNIT_TEST(testUnblockCommand); + CPPUNIT_TEST(testUnblockAllCommand); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + ownJID_ = JID("kev@wonderland.lit"); + stanzaChannel_ = new DummyStanzaChannel(); + iqRouter_ = new IQRouter(stanzaChannel_); + iqRouter_->setJID(ownJID_); + clientBlockListManager_ = new ClientBlockListManager(iqRouter_); + } + + void testFetchBlockList() { + std::vector<JID> blockJids; + blockJids.push_back(JID("romeo@montague.net")); + blockJids.push_back(JID("iago@shakespeare.lit")); + helperInitialBlockListFetch(blockJids); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), clientBlockListManager_->getBlockList()->getItems().size()); + } + + void testBlockCommand() { + // start with an already fetched block list + helperInitialBlockListFetch(std::vector<JID>(1, JID("iago@shakespeare.lit"))); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), clientBlockListManager_->getBlockList()->getItems().size()); + CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState()); + + GenericRequest<BlockPayload>::ref blockRequest = clientBlockListManager_->createBlockJIDRequest(JID("romeo@montague.net")); + blockRequest->send(); + IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(2); + CPPUNIT_ASSERT(request.get() != NULL); + boost::shared_ptr<BlockPayload> blockPayload = request->getPayload<BlockPayload>(); + CPPUNIT_ASSERT(blockPayload.get() != NULL); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), blockPayload->getItems().at(0)); + + IQ::ref blockRequestResponse = IQ::createResult(request->getFrom(), JID(), request->getID()); + stanzaChannel_->sendIQ(blockRequestResponse); + stanzaChannel_->onIQReceived(blockRequestResponse); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), clientBlockListManager_->getBlockList()->getItems().size()); + + // send block push + boost::shared_ptr<BlockPayload> pushPayload = boost::make_shared<BlockPayload>(); + pushPayload->addItem(JID("romeo@montague.net")); + IQ::ref blockPush = IQ::createRequest(IQ::Set, ownJID_, "push1", pushPayload); + stanzaChannel_->sendIQ(blockPush); + stanzaChannel_->onIQReceived(blockPush); + + std::vector<JID> blockedJIDs = clientBlockListManager_->getBlockList()->getItems(); + CPPUNIT_ASSERT(blockedJIDs.end() != std::find(blockedJIDs.begin(), blockedJIDs.end(), JID("romeo@montague.net"))); + } + + void testUnblockCommand() { + // start with an already fetched block list + std::vector<JID> initialBlockList = std::vector<JID>(1, JID("iago@shakespeare.lit")); + initialBlockList.push_back(JID("romeo@montague.net")); + helperInitialBlockListFetch(initialBlockList); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), clientBlockListManager_->getBlockList()->getItems().size()); + CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState()); + + GenericRequest<UnblockPayload>::ref unblockRequest = clientBlockListManager_->createUnblockJIDRequest(JID("romeo@montague.net")); + unblockRequest->send(); + IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(2); + CPPUNIT_ASSERT(request.get() != NULL); + boost::shared_ptr<UnblockPayload> unblockPayload = request->getPayload<UnblockPayload>(); + CPPUNIT_ASSERT(unblockPayload.get() != NULL); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), unblockPayload->getItems().at(0)); + + IQ::ref unblockRequestResponse = IQ::createResult(request->getFrom(), JID(), request->getID()); + stanzaChannel_->sendIQ(unblockRequestResponse); + stanzaChannel_->onIQReceived(unblockRequestResponse); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), clientBlockListManager_->getBlockList()->getItems().size()); + + // send block push + boost::shared_ptr<UnblockPayload> pushPayload = boost::make_shared<UnblockPayload>(); + pushPayload->addItem(JID("romeo@montague.net")); + IQ::ref unblockPush = IQ::createRequest(IQ::Set, ownJID_, "push1", pushPayload); + stanzaChannel_->sendIQ(unblockPush); + stanzaChannel_->onIQReceived(unblockPush); + + std::vector<JID> blockedJIDs = clientBlockListManager_->getBlockList()->getItems(); + CPPUNIT_ASSERT(blockedJIDs.end() == std::find(blockedJIDs.begin(), blockedJIDs.end(), JID("romeo@montague.net"))); + } + + void testUnblockAllCommand() { + // start with an already fetched block list + std::vector<JID> initialBlockList = std::vector<JID>(1, JID("iago@shakespeare.lit")); + initialBlockList.push_back(JID("romeo@montague.net")); + initialBlockList.push_back(JID("benvolio@montague.net")); + helperInitialBlockListFetch(initialBlockList); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), clientBlockListManager_->getBlockList()->getItems().size()); + CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState()); + + GenericRequest<UnblockPayload>::ref unblockRequest = clientBlockListManager_->createUnblockAllRequest(); + unblockRequest->send(); + IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(2); + CPPUNIT_ASSERT(request.get() != NULL); + boost::shared_ptr<UnblockPayload> unblockPayload = request->getPayload<UnblockPayload>(); + CPPUNIT_ASSERT(unblockPayload.get() != NULL); + CPPUNIT_ASSERT_EQUAL(true, unblockPayload->getItems().empty()); + + IQ::ref unblockRequestResponse = IQ::createResult(request->getFrom(), JID(), request->getID()); + stanzaChannel_->sendIQ(unblockRequestResponse); + stanzaChannel_->onIQReceived(unblockRequestResponse); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), clientBlockListManager_->getBlockList()->getItems().size()); + + // send block push + boost::shared_ptr<UnblockPayload> pushPayload = boost::make_shared<UnblockPayload>(); + IQ::ref unblockPush = IQ::createRequest(IQ::Set, ownJID_, "push1", pushPayload); + stanzaChannel_->sendIQ(unblockPush); + stanzaChannel_->onIQReceived(unblockPush); + + CPPUNIT_ASSERT_EQUAL(true, clientBlockListManager_->getBlockList()->getItems().empty()); + } + + void tearDown() { + delete clientBlockListManager_; + delete iqRouter_; + delete stanzaChannel_; + } + + private: + void helperInitialBlockListFetch(const std::vector<JID>& blockedJids) { + boost::shared_ptr<BlockList> blockList = clientBlockListManager_->requestBlockList(); + CPPUNIT_ASSERT(blockList); + + // check for IQ request + IQ::ref request = stanzaChannel_->getStanzaAtIndex<IQ>(0); + CPPUNIT_ASSERT(request.get() != NULL); + boost::shared_ptr<BlockListPayload> requestPayload = request->getPayload<BlockListPayload>(); + CPPUNIT_ASSERT(requestPayload.get() != NULL); + + CPPUNIT_ASSERT_EQUAL(BlockList::Requesting, blockList->getState()); + CPPUNIT_ASSERT_EQUAL(BlockList::Requesting, clientBlockListManager_->getBlockList()->getState()); + + // build IQ response + boost::shared_ptr<BlockListPayload> responsePayload = boost::make_shared<BlockListPayload>(); + foreach(const JID& jid, blockedJids) { + responsePayload->addItem(jid); + } + + IQ::ref response = IQ::createResult(ownJID_, JID(), request->getID(), responsePayload); + stanzaChannel_->sendIQ(response); + stanzaChannel_->onIQReceived(response); + + CPPUNIT_ASSERT_EQUAL(BlockList::Available, clientBlockListManager_->getBlockList()->getState()); + CPPUNIT_ASSERT(responsePayload->getItems() == clientBlockListManager_->getBlockList()->getItems()); + } + + + private: + JID ownJID_; + IQRouter* iqRouter_; + DummyStanzaChannel* stanzaChannel_; + ClientBlockListManager* clientBlockListManager_; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ClientBlockListManagerTest); + diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp index 6793643..4e1fc31 100644 --- a/Swiften/Client/UnitTest/ClientSessionTest.cpp +++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,7 +12,10 @@ #include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/IDN/PlatformIDNConverter.h> #include <Swiften/Session/SessionStream.h> #include <Swiften/Client/ClientSession.h> #include <Swiften/Elements/Message.h> +#include <Swiften/Elements/AuthChallenge.h> #include <Swiften/Elements/StartTLSRequest.h> #include <Swiften/Elements/StreamFeatures.h> @@ -31,4 +34,6 @@ #include <Swiften/TLS/SimpleCertificate.h> #include <Swiften/TLS/BlindCertificateTrustChecker.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -48,6 +53,8 @@ class ClientSessionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testAuthenticate_PLAINOverNonTLS); CPPUNIT_TEST(testAuthenticate_RequireTLS); + CPPUNIT_TEST(testAuthenticate_EXTERNAL); CPPUNIT_TEST(testStreamManagement); CPPUNIT_TEST(testStreamManagement_Failed); + CPPUNIT_TEST(testUnexpectedChallenge); CPPUNIT_TEST(testFinishAcksStanzas); /* @@ -67,4 +74,6 @@ class ClientSessionTest : public CppUnit::TestFixture { public: void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); server = boost::make_shared<MockSessionStream>(); sessionFinishedReceived = false; @@ -248,4 +257,32 @@ class ClientSessionTest : public CppUnit::TestFixture { } + void testAuthenticate_EXTERNAL() { + boost::shared_ptr<ClientSession> session(createSession()); + session->start(); + server->receiveStreamStart(); + server->sendStreamStart(); + server->sendStreamFeaturesWithEXTERNALAuthentication(); + server->receiveAuthRequest("EXTERNAL"); + server->sendAuthSuccess(); + server->receiveStreamStart(); + + session->finish(); + } + + void testUnexpectedChallenge() { + boost::shared_ptr<ClientSession> session(createSession()); + session->start(); + server->receiveStreamStart(); + server->sendStreamStart(); + server->sendStreamFeaturesWithEXTERNALAuthentication(); + server->receiveAuthRequest("EXTERNAL"); + server->sendChallenge(); + server->sendChallenge(); + + CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState()); + CPPUNIT_ASSERT(sessionFinishedReceived); + CPPUNIT_ASSERT(sessionFinishedError); + } + void testStreamManagement() { boost::shared_ptr<ClientSession> session(createSession()); @@ -309,5 +346,5 @@ class ClientSessionTest : public CppUnit::TestFixture { private: boost::shared_ptr<ClientSession> createSession() { - boost::shared_ptr<ClientSession> session = ClientSession::create(JID("me@foo.com"), server); + boost::shared_ptr<ClientSession> session = ClientSession::create(JID("me@foo.com"), server, idnConverter.get(), crypto.get()); session->onFinished.connect(boost::bind(&ClientSessionTest::handleSessionFinished, this, _1)); session->onNeedCredentials.connect(boost::bind(&ClientSessionTest::handleSessionNeedCredentials, this)); @@ -345,9 +382,9 @@ class ClientSessionTest : public CppUnit::TestFixture { public: struct Event { - Event(boost::shared_ptr<Element> element) : element(element), footer(false) {} + Event(boost::shared_ptr<ToplevelElement> element) : element(element), footer(false) {} Event(const ProtocolHeader& header) : header(header), footer(false) {} Event() : footer(true) {} - boost::shared_ptr<Element> element; + boost::shared_ptr<ToplevelElement> element; boost::optional<ProtocolHeader> header; bool footer; @@ -373,5 +410,5 @@ class ClientSessionTest : public CppUnit::TestFixture { } - virtual void writeElement(boost::shared_ptr<Element> element) { + virtual void writeElement(boost::shared_ptr<ToplevelElement> element) { receivedEvents.push_back(Event(element)); } @@ -400,4 +437,8 @@ class ClientSessionTest : public CppUnit::TestFixture { } + virtual std::vector<Certificate::ref> getPeerCertificateChain() const { + return std::vector<Certificate::ref>(); + } + virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const { return boost::shared_ptr<CertificateVerificationError>(); @@ -441,4 +482,8 @@ class ClientSessionTest : public CppUnit::TestFixture { } + void sendChallenge() { + onElementReceived(boost::make_shared<AuthChallenge>()); + } + void sendStreamError() { onElementReceived(boost::make_shared<StreamError>()); @@ -467,4 +512,10 @@ class ClientSessionTest : public CppUnit::TestFixture { } + void sendStreamFeaturesWithEXTERNALAuthentication() { + boost::shared_ptr<StreamFeatures> streamFeatures(new StreamFeatures()); + streamFeatures->addAuthenticationMechanism("EXTERNAL"); + onElementReceived(streamFeatures); + } + void sendStreamFeaturesWithUnknownAuthentication() { boost::shared_ptr<StreamFeatures> streamFeatures(new StreamFeatures()); @@ -572,4 +623,5 @@ class ClientSessionTest : public CppUnit::TestFixture { }; + boost::shared_ptr<IDNConverter> idnConverter; boost::shared_ptr<MockSessionStream> server; bool sessionFinishedReceived; @@ -577,4 +629,5 @@ class ClientSessionTest : public CppUnit::TestFixture { boost::shared_ptr<Error> sessionFinishedError; BlindCertificateTrustChecker* blindCertificateTrustChecker; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Client/UnitTest/NickResolverTest.cpp b/Swiften/Client/UnitTest/NickResolverTest.cpp index dfc90fe..a8b011c 100644 --- a/Swiften/Client/UnitTest/NickResolverTest.cpp +++ b/Swiften/Client/UnitTest/NickResolverTest.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -15,4 +21,6 @@ #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -35,9 +43,10 @@ class NickResolverTest : public CppUnit::TestFixture { public: void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); ownJID_ = JID("kev@wonderland.lit"); xmppRoster_ = new XMPPRosterImpl(); stanzaChannel_ = new DummyStanzaChannel(); iqRouter_ = new IQRouter(stanzaChannel_); - vCardStorage_ = new VCardMemoryStorage(); + vCardStorage_ = new VCardMemoryStorage(crypto.get()); vCardManager_ = new VCardManager(ownJID_, iqRouter_, vCardStorage_); registry_ = new MUCRegistry(); @@ -145,5 +154,5 @@ class NickResolverTest : public CppUnit::TestFixture { NickResolver* resolver_; JID ownJID_; - + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Client/XMLBeautifier.cpp b/Swiften/Client/XMLBeautifier.cpp index b70fc48..5d083ff 100644 --- a/Swiften/Client/XMLBeautifier.cpp +++ b/Swiften/Client/XMLBeautifier.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <sstream> #include <stack> @@ -39,11 +45,11 @@ void XMLBeautifier::indent() { // all bold but reset -const char colorBlue[] = "\x1b[01;34m"; -const char colorCyan[] = "\x1b[01;36m"; -const char colorGreen[] = "\x1b[01;32m"; -const char colorMagenta[] = "\x1b[01;35m"; -const char colorRed[] = "\x1b[01;31m"; -const char colorReset[] = "\x1b[0m"; -const char colorYellow[] = "\x1b[01;33m"; +// static const char colorBlue[] = "\x1b[01;34m"; +static const char colorCyan[] = "\x1b[01;36m"; +static const char colorGreen[] = "\x1b[01;32m"; +// static const char colorMagenta[] = "\x1b[01;35m"; +static const char colorRed[] = "\x1b[01;31m"; +static const char colorReset[] = "\x1b[0m"; +static const char colorYellow[] = "\x1b[01;33m"; diff --git a/Swiften/Client/XMLBeautifier.h b/Swiften/Client/XMLBeautifier.h index 44dfd20..25ecd18 100644 --- a/Swiften/Client/XMLBeautifier.h +++ b/Swiften/Client/XMLBeautifier.h @@ -5,6 +5,13 @@ */ +/* +* Copyright (c) 2014 Remko Tronçon and Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + #pragma once +#include <sstream> #include <string> #include <stack> diff --git a/Swiften/Component/Component.cpp b/Swiften/Component/Component.cpp index af378a7..a53f514 100644 --- a/Swiften/Component/Component.cpp +++ b/Swiften/Component/Component.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,5 +11,5 @@ namespace Swift { -Component::Component(EventLoop* eventLoop, NetworkFactories* networkFactories, const JID& jid, const std::string& secret) : CoreComponent(eventLoop, networkFactories, jid, secret) { +Component::Component(const JID& jid, const std::string& secret, NetworkFactories* networkFactories) : CoreComponent(jid, secret, networkFactories) { softwareVersionResponder = new SoftwareVersionResponder(getIQRouter()); softwareVersionResponder->start(); diff --git a/Swiften/Component/Component.h b/Swiften/Component/Component.h index 0b29ff7..3ead1a5 100644 --- a/Swiften/Component/Component.h +++ b/Swiften/Component/Component.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Component/CoreComponent.h> @@ -18,7 +19,7 @@ namespace Swift { * performing most component tasks on the XMPP network. */ - class Component : public CoreComponent { + class SWIFTEN_API Component : public CoreComponent { public: - Component(EventLoop* eventLoop, NetworkFactories* networkFactories, const JID& jid, const std::string& secret); + Component(const JID& jid, const std::string& secret, NetworkFactories* networkFactories); ~Component(); diff --git a/Swiften/Component/ComponentConnector.cpp b/Swiften/Component/ComponentConnector.cpp index b7bdd34..0dd8e82 100644 --- a/Swiften/Component/ComponentConnector.cpp +++ b/Swiften/Component/ComponentConnector.cpp @@ -105,3 +105,3 @@ void ComponentConnector::handleTimeout() { } -}; +} diff --git a/Swiften/Component/ComponentConnector.h b/Swiften/Component/ComponentConnector.h index b47f5da..0e35ab2 100644 --- a/Swiften/Component/ComponentConnector.h +++ b/Swiften/Component/ComponentConnector.h @@ -11,4 +11,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/Timer.h> @@ -23,5 +24,5 @@ namespace Swift { class TimerFactory; - class ComponentConnector : public boost::bsignals::trackable, public boost::enable_shared_from_this<ComponentConnector> { + class SWIFTEN_API ComponentConnector : public boost::bsignals::trackable, public boost::enable_shared_from_this<ComponentConnector> { public: typedef boost::shared_ptr<ComponentConnector> ref; @@ -62,3 +63,3 @@ namespace Swift { boost::shared_ptr<Connection> currentConnection; }; -}; +} diff --git a/Swiften/Component/ComponentError.h b/Swiften/Component/ComponentError.h index 928af2a..9c54b53 100644 --- a/Swiften/Component/ComponentError.h +++ b/Swiften/Component/ComponentError.h @@ -17,5 +17,5 @@ namespace Swift { XMLError, AuthenticationFailedError, - UnexpectedElementError, + UnexpectedElementError }; diff --git a/Swiften/Component/ComponentHandshakeGenerator.cpp b/Swiften/Component/ComponentHandshakeGenerator.cpp index 79ba9b3..495d530 100644 --- a/Swiften/Component/ComponentHandshakeGenerator.cpp +++ b/Swiften/Component/ComponentHandshakeGenerator.cpp @@ -7,10 +7,10 @@ #include <Swiften/Component/ComponentHandshakeGenerator.h> #include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/SHA1.h> #include <Swiften/Base/String.h> +#include <Swiften/Crypto/CryptoProvider.h> namespace Swift { -std::string ComponentHandshakeGenerator::getHandshake(const std::string& streamID, const std::string& secret) { +std::string ComponentHandshakeGenerator::getHandshake(const std::string& streamID, const std::string& secret, CryptoProvider* crypto) { std::string concatenatedString = streamID + secret; String::replaceAll(concatenatedString, '&', "&"); @@ -19,5 +19,5 @@ std::string ComponentHandshakeGenerator::getHandshake(const std::string& streamI String::replaceAll(concatenatedString, '\'', "'"); String::replaceAll(concatenatedString, '"', """); - return Hexify::hexify(SHA1::getHash(createByteArray(concatenatedString))); + return Hexify::hexify(crypto->getSHA1Hash(createByteArray(concatenatedString))); } diff --git a/Swiften/Component/ComponentHandshakeGenerator.h b/Swiften/Component/ComponentHandshakeGenerator.h index 4181d3c..e0e3ef8 100644 --- a/Swiften/Component/ComponentHandshakeGenerator.h +++ b/Swiften/Component/ComponentHandshakeGenerator.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,8 +9,12 @@ #include <string> +#include <Swiften/Base/API.h> + namespace Swift { - class ComponentHandshakeGenerator { + class CryptoProvider; + + class SWIFTEN_API ComponentHandshakeGenerator { public: - static std::string getHandshake(const std::string& streamID, const std::string& secret); + static std::string getHandshake(const std::string& streamID, const std::string& secret, CryptoProvider* crypto); }; diff --git a/Swiften/Component/ComponentSession.cpp b/Swiften/Component/ComponentSession.cpp index 51d9d15..826451d 100644 --- a/Swiften/Component/ComponentSession.cpp +++ b/Swiften/Component/ComponentSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,4 +11,5 @@ #include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Elements/StreamFeatures.h> #include <Swiften/Elements/ComponentHandshake.h> #include <Swiften/Session/SessionStream.h> @@ -17,5 +18,5 @@ namespace Swift { -ComponentSession::ComponentSession(const JID& jid, const std::string& secret, boost::shared_ptr<SessionStream> stream) : jid(jid), secret(secret), stream(stream), state(Initial) { +ComponentSession::ComponentSession(const JID& jid, const std::string& secret, boost::shared_ptr<SessionStream> stream, CryptoProvider* crypto) : jid(jid), secret(secret), stream(stream), crypto(crypto), state(Initial) { } @@ -46,8 +47,8 @@ void ComponentSession::handleStreamStart(const ProtocolHeader& header) { checkState(WaitingForStreamStart); state = Authenticating; - stream->writeElement(ComponentHandshake::ref(new ComponentHandshake(ComponentHandshakeGenerator::getHandshake(header.getID(), secret)))); + stream->writeElement(ComponentHandshake::ref(new ComponentHandshake(ComponentHandshakeGenerator::getHandshake(header.getID(), secret, crypto)))); } -void ComponentSession::handleElement(boost::shared_ptr<Element> element) { +void ComponentSession::handleElement(boost::shared_ptr<ToplevelElement> element) { if (boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element)) { if (getState() == Initialized) { @@ -67,7 +68,12 @@ void ComponentSession::handleElement(boost::shared_ptr<Element> element) { } else if (getState() == Authenticating) { + if (boost::dynamic_pointer_cast<StreamFeatures>(element)) { + // M-Link sends stream features, so swallow that. + } + else { // FIXME: We should actually check the element received finishSession(Error::AuthenticationFailedError); } + } else { finishSession(Error::UnexpectedElementError); diff --git a/Swiften/Component/ComponentSession.h b/Swiften/Component/ComponentSession.h index 647bad7..1fa7b5c 100644 --- a/Swiften/Component/ComponentSession.h +++ b/Swiften/Component/ComponentSession.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,9 +10,10 @@ #include <boost/enable_shared_from_this.hpp> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/Error.h> #include <string> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Elements/Stanza.h> #include <Swiften/Session/SessionStream.h> @@ -20,6 +21,7 @@ namespace Swift { class ComponentAuthenticator; + class CryptoProvider; - class ComponentSession : public boost::enable_shared_from_this<ComponentSession> { + class SWIFTEN_API ComponentSession : public boost::enable_shared_from_this<ComponentSession> { public: enum State { @@ -35,5 +37,5 @@ namespace Swift { enum Type { AuthenticationFailedError, - UnexpectedElementError, + UnexpectedElementError } type; Error(Type type) : type(type) {} @@ -42,6 +44,6 @@ namespace Swift { ~ComponentSession(); - static boost::shared_ptr<ComponentSession> create(const JID& jid, const std::string& secret, boost::shared_ptr<SessionStream> stream) { - return boost::shared_ptr<ComponentSession>(new ComponentSession(jid, secret, stream)); + static boost::shared_ptr<ComponentSession> create(const JID& jid, const std::string& secret, boost::shared_ptr<SessionStream> stream, CryptoProvider* crypto) { + return boost::shared_ptr<ComponentSession>(new ComponentSession(jid, secret, stream, crypto)); } @@ -61,5 +63,5 @@ namespace Swift { private: - ComponentSession(const JID& jid, const std::string& secret, boost::shared_ptr<SessionStream>); + ComponentSession(const JID& jid, const std::string& secret, boost::shared_ptr<SessionStream>, CryptoProvider*); void finishSession(Error::Type error); @@ -68,5 +70,5 @@ namespace Swift { void sendStreamHeader(); - void handleElement(boost::shared_ptr<Element>); + void handleElement(boost::shared_ptr<ToplevelElement>); void handleStreamStart(const ProtocolHeader&); void handleStreamClosed(boost::shared_ptr<Swift::Error>); @@ -78,4 +80,5 @@ namespace Swift { std::string secret; boost::shared_ptr<SessionStream> stream; + CryptoProvider* crypto; boost::shared_ptr<Swift::Error> error; State state; diff --git a/Swiften/Component/ComponentSessionStanzaChannel.h b/Swiften/Component/ComponentSessionStanzaChannel.h index 45f90b5..4e133b8 100644 --- a/Swiften/Component/ComponentSessionStanzaChannel.h +++ b/Swiften/Component/ComponentSessionStanzaChannel.h @@ -32,4 +32,9 @@ namespace Swift { } + std::vector<Certificate::ref> getPeerCertificateChain() const { + // TODO: actually implement this method + return std::vector<Certificate::ref>(); + } + bool isAvailable() const { return session && session->getState() == ComponentSession::Initialized; diff --git a/Swiften/Component/ComponentXMLTracer.h b/Swiften/Component/ComponentXMLTracer.h index c12ec07..57b9dcf 100644 --- a/Swiften/Component/ComponentXMLTracer.h +++ b/Swiften/Component/ComponentXMLTracer.h @@ -7,8 +7,9 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Component/Component.h> namespace Swift { - class ComponentXMLTracer { + class SWIFTEN_API ComponentXMLTracer { public: ComponentXMLTracer(CoreComponent* component); diff --git a/Swiften/Component/CoreComponent.cpp b/Swiften/Component/CoreComponent.cpp index e11d2b0..cc6be42 100644 --- a/Swiften/Component/CoreComponent.cpp +++ b/Swiften/Component/CoreComponent.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -21,5 +21,5 @@ namespace Swift { -CoreComponent::CoreComponent(EventLoop* eventLoop, NetworkFactories* networkFactories, const JID& jid, const std::string& secret) : eventLoop(eventLoop), networkFactories(networkFactories), resolver_(eventLoop), jid_(jid), secret_(secret), disconnectRequested_(false) { +CoreComponent::CoreComponent(const JID& jid, const std::string& secret, NetworkFactories* networkFactories) : networkFactories(networkFactories), jid_(jid), secret_(secret), disconnectRequested_(false) { stanzaChannel_ = new ComponentSessionStanzaChannel(); stanzaChannel_->onMessageReceived.connect(boost::ref(onMessageReceived)); @@ -45,5 +45,5 @@ CoreComponent::~CoreComponent() { void CoreComponent::connect(const std::string& host, int port) { assert(!connector_); - connector_ = ComponentConnector::create(host, port, &resolver_, networkFactories->getConnectionFactory(), networkFactories->getTimerFactory()); + connector_ = ComponentConnector::create(host, port, networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreComponent::handleConnectorFinished, this, _1)); connector_->setTimeoutMilliseconds(60*1000); @@ -68,5 +68,5 @@ void CoreComponent::handleConnectorFinished(boost::shared_ptr<Connection> connec sessionStream_->onDataWritten.connect(boost::bind(&CoreComponent::handleDataWritten, this, _1)); - session_ = ComponentSession::create(jid_, secret_, sessionStream_); + session_ = ComponentSession::create(jid_, secret_, sessionStream_, networkFactories->getCryptoProvider()); stanzaChannel_->setSession(session_); session_->onFinished.connect(boost::bind(&CoreComponent::handleSessionFinished, this, _1)); @@ -86,7 +86,7 @@ void CoreComponent::disconnect() { assert(!session_); } - assert(!session_); - assert(!sessionStream_); - assert(!connector_); + //assert(!session_); /* commenting out until we have time to refactor to be like CoreClient */ + //assert(!sessionStream_); + //assert(!connector_); disconnectRequested_ = false; } @@ -162,3 +162,7 @@ void CoreComponent::sendPresence(boost::shared_ptr<Presence> presence) { } +void CoreComponent::sendData(const std::string& data) { + sessionStream_->writeData(data); +} + } diff --git a/Swiften/Component/CoreComponent.h b/Swiften/Component/CoreComponent.h index e7945d1..e9fdd88 100644 --- a/Swiften/Component/CoreComponent.h +++ b/Swiften/Component/CoreComponent.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,7 +9,7 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/Error.h> -#include <Swiften/Network/PlatformDomainNameResolver.h> #include <Swiften/Component/ComponentConnector.h> #include <Swiften/Component/ComponentSession.h> @@ -26,4 +26,5 @@ namespace Swift { + class EventLoop; class IQRouter; class NetworkFactories; @@ -41,7 +42,7 @@ namespace Swift { * for most needs. */ - class CoreComponent : public Entity { + class SWIFTEN_API CoreComponent : public Entity { public: - CoreComponent(EventLoop* eventLoop, NetworkFactories* networkFactories, const JID& jid, const std::string& secret); + CoreComponent(const JID& jid, const std::string& secret, NetworkFactories* networkFactories); ~CoreComponent(); @@ -51,4 +52,5 @@ namespace Swift { void sendMessage(boost::shared_ptr<Message>); void sendPresence(boost::shared_ptr<Presence>); + void sendData(const std::string& data); IQRouter* getIQRouter() const { @@ -88,7 +90,5 @@ namespace Swift { private: - EventLoop* eventLoop; NetworkFactories* networkFactories; - PlatformDomainNameResolver resolver_; JID jid_; std::string secret_; diff --git a/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp b/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp index fd8f6fc..280e46e 100644 --- a/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp +++ b/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,4 +9,6 @@ #include <Swiften/Component/ComponentHandshakeGenerator.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -19,14 +21,20 @@ class ComponentHandshakeGeneratorTest : public CppUnit::TestFixture { public: + void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + } + void testGetHandshake() { - std::string result = ComponentHandshakeGenerator::getHandshake("myid", "mysecret"); + std::string result = ComponentHandshakeGenerator::getHandshake("myid", "mysecret", crypto.get()); CPPUNIT_ASSERT_EQUAL(std::string("4011cd31f9b99ac089a0cd7ce297da7323fa2525"), result); } void testGetHandshake_SpecialChars() { - std::string result = ComponentHandshakeGenerator::getHandshake("&<", ">'\""); + std::string result = ComponentHandshakeGenerator::getHandshake("&<", ">'\"", crypto.get()); CPPUNIT_ASSERT_EQUAL(std::string("33631b3e0aaeb2a11c4994c917919324028873fe"), result); } + private: + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Component/UnitTest/ComponentSessionTest.cpp b/Swiften/Component/UnitTest/ComponentSessionTest.cpp index da9ca7d..79d9ab3 100644 --- a/Swiften/Component/UnitTest/ComponentSessionTest.cpp +++ b/Swiften/Component/UnitTest/ComponentSessionTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -15,4 +15,6 @@ #include <Swiften/Elements/ComponentHandshake.h> #include <Swiften/Elements/AuthFailure.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -29,4 +31,5 @@ class ComponentSessionTest : public CppUnit::TestFixture { server = boost::make_shared<MockSessionStream>(); sessionFinishedReceived = false; + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); } @@ -71,5 +74,5 @@ class ComponentSessionTest : public CppUnit::TestFixture { private: boost::shared_ptr<ComponentSession> createSession() { - boost::shared_ptr<ComponentSession> session = ComponentSession::create(JID("service.foo.com"), "servicesecret", server); + boost::shared_ptr<ComponentSession> session = ComponentSession::create(JID("service.foo.com"), "servicesecret", server, crypto.get()); session->onFinished.connect(boost::bind(&ComponentSessionTest::handleSessionFinished, this, _1)); return session; @@ -84,9 +87,9 @@ class ComponentSessionTest : public CppUnit::TestFixture { public: struct Event { - Event(boost::shared_ptr<Element> element) : element(element), footer(false) {} + Event(boost::shared_ptr<ToplevelElement> element) : element(element), footer(false) {} Event(const ProtocolHeader& header) : header(header), footer(false) {} Event() : footer(true) {} - boost::shared_ptr<Element> element; + boost::shared_ptr<ToplevelElement> element; boost::optional<ProtocolHeader> header; bool footer; @@ -112,5 +115,5 @@ class ComponentSessionTest : public CppUnit::TestFixture { } - virtual void writeElement(boost::shared_ptr<Element> element) { + virtual void writeElement(boost::shared_ptr<ToplevelElement> element) { receivedEvents.push_back(Event(element)); } @@ -139,4 +142,8 @@ class ComponentSessionTest : public CppUnit::TestFixture { } + virtual std::vector<Certificate::ref> getPeerCertificateChain() const { + return std::vector<Certificate::ref>(); + } + virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const { return boost::shared_ptr<CertificateVerificationError>(); @@ -207,6 +214,6 @@ class ComponentSessionTest : public CppUnit::TestFixture { boost::shared_ptr<MockSessionStream> server; bool sessionFinishedReceived; - bool needCredentials; boost::shared_ptr<Error> sessionFinishedError; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Compress/ZLibCodecompressor.cpp b/Swiften/Compress/ZLibCodecompressor.cpp index 0869d6b..85d0174 100644 --- a/Swiften/Compress/ZLibCodecompressor.cpp +++ b/Swiften/Compress/ZLibCodecompressor.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,16 +9,20 @@ #include <cassert> #include <string.h> +#include <zlib.h> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Compress/ZLibException.h> +#include <Swiften/Compress/ZLibCodecompressor_Private.h> namespace Swift { -static const int CHUNK_SIZE = 1024; // If you change this, also change the unittest +static const size_t CHUNK_SIZE = 1024; // If you change this, also change the unittest -ZLibCodecompressor::ZLibCodecompressor() { - memset(&stream_, 0, sizeof(z_stream)); - stream_.zalloc = Z_NULL; - stream_.zfree = Z_NULL; - stream_.opaque = Z_NULL; + +ZLibCodecompressor::ZLibCodecompressor() : p(boost::make_shared<Private>()) { + memset(&p->stream, 0, sizeof(z_stream)); + p->stream.zalloc = Z_NULL; + p->stream.zfree = Z_NULL; + p->stream.opaque = Z_NULL; } @@ -28,22 +32,22 @@ ZLibCodecompressor::~ZLibCodecompressor() { SafeByteArray ZLibCodecompressor::process(const SafeByteArray& input) { SafeByteArray output; - stream_.avail_in = input.size(); - stream_.next_in = reinterpret_cast<Bytef*>(const_cast<unsigned char*>(vecptr(input))); - int outputPosition = 0; + p->stream.avail_in = static_cast<unsigned int>(input.size()); + p->stream.next_in = reinterpret_cast<Bytef*>(const_cast<unsigned char*>(vecptr(input))); + size_t outputPosition = 0; do { output.resize(outputPosition + CHUNK_SIZE); - stream_.avail_out = CHUNK_SIZE; - stream_.next_out = reinterpret_cast<Bytef*>(vecptr(output) + outputPosition); + p->stream.avail_out = CHUNK_SIZE; + p->stream.next_out = reinterpret_cast<Bytef*>(vecptr(output) + outputPosition); int result = processZStream(); if (result != Z_OK && result != Z_BUF_ERROR) { - throw ZLibException(/* stream_.msg */); + throw ZLibException(/* p->stream.msg */); } outputPosition += CHUNK_SIZE; } - while (stream_.avail_out == 0); - if (stream_.avail_in != 0) { + while (p->stream.avail_out == 0); + if (p->stream.avail_in != 0) { throw ZLibException(); } - output.resize(outputPosition - stream_.avail_out); + output.resize(outputPosition - p->stream.avail_out); return output; } diff --git a/Swiften/Compress/ZLibCodecompressor.h b/Swiften/Compress/ZLibCodecompressor.h index 93babf0..6ff64df 100644 --- a/Swiften/Compress/ZLibCodecompressor.h +++ b/Swiften/Compress/ZLibCodecompressor.h @@ -7,10 +7,9 @@ #pragma once -#include <zlib.h> - +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> namespace Swift { - class ZLibCodecompressor { + class SWIFTEN_API ZLibCodecompressor { public: ZLibCodecompressor(); @@ -21,5 +20,6 @@ namespace Swift { protected: - z_stream stream_; + struct Private; + boost::shared_ptr<Private> p; }; } diff --git a/Swiften/Compress/ZLibCodecompressor_Private.h b/Swiften/Compress/ZLibCodecompressor_Private.h new file mode 100644 index 0000000..1f24b83 --- /dev/null +++ b/Swiften/Compress/ZLibCodecompressor_Private.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Compress/ZLibCodecompressor.h> + +#include <zlib.h> + +namespace Swift { + struct ZLibCodecompressor::Private { + z_stream stream; + }; +} diff --git a/Swiften/Compress/ZLibCompressor.cpp b/Swiften/Compress/ZLibCompressor.cpp index 5d98e38..6af8d83 100644 --- a/Swiften/Compress/ZLibCompressor.cpp +++ b/Swiften/Compress/ZLibCompressor.cpp @@ -8,4 +8,7 @@ #include <cassert> +#include <zlib.h> + +#include <Swiften/Compress/ZLibCodecompressor_Private.h> #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -14,8 +17,16 @@ namespace Swift { ZLibCompressor::ZLibCompressor() { - int result = deflateInit(&stream_, COMPRESSION_LEVEL); + int result = deflateInit(&p->stream, COMPRESSION_LEVEL); assert(result == Z_OK); (void) result; } +ZLibCompressor::~ZLibCompressor() { + deflateEnd(&p->stream); +} + +int ZLibCompressor::processZStream() { + return deflate(&p->stream, Z_SYNC_FLUSH); +} + } diff --git a/Swiften/Compress/ZLibCompressor.h b/Swiften/Compress/ZLibCompressor.h index 1add725..3ba1955 100644 --- a/Swiften/Compress/ZLibCompressor.h +++ b/Swiften/Compress/ZLibCompressor.h @@ -7,19 +7,14 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Compress/ZLibCodecompressor.h> -#include <Swiften/Base/ByteArray.h> namespace Swift { - class ZLibCompressor : public ZLibCodecompressor { + class SWIFTEN_API ZLibCompressor : public ZLibCodecompressor { public: ZLibCompressor(); + ~ZLibCompressor(); - ~ZLibCompressor() { - deflateEnd(&stream_); - } - - virtual int processZStream() { - return deflate(&stream_, Z_SYNC_FLUSH); - } + virtual int processZStream(); private: diff --git a/Swiften/Compress/ZLibDecompressor.cpp b/Swiften/Compress/ZLibDecompressor.cpp index ab954f4..f5df9fe 100644 --- a/Swiften/Compress/ZLibDecompressor.cpp +++ b/Swiften/Compress/ZLibDecompressor.cpp @@ -7,6 +7,9 @@ #include <Swiften/Compress/ZLibDecompressor.h> +#include <zlib.h> #include <cassert> +#include <Swiften/Compress/ZLibCodecompressor_Private.h> + #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -14,8 +17,16 @@ namespace Swift { ZLibDecompressor::ZLibDecompressor() { - int result = inflateInit(&stream_); + int result = inflateInit(&p->stream); assert(result == Z_OK); (void) result; } +ZLibDecompressor::~ZLibDecompressor() { + inflateEnd(&p->stream); +} + +int ZLibDecompressor::processZStream() { + return inflate(&p->stream, Z_SYNC_FLUSH); +} + } diff --git a/Swiften/Compress/ZLibDecompressor.h b/Swiften/Compress/ZLibDecompressor.h index 67994d1..e3122f1 100644 --- a/Swiften/Compress/ZLibDecompressor.h +++ b/Swiften/Compress/ZLibDecompressor.h @@ -8,18 +8,13 @@ #include <Swiften/Compress/ZLibCodecompressor.h> -#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/API.h> namespace Swift { - class ZLibDecompressor : public ZLibCodecompressor { + class SWIFTEN_API ZLibDecompressor : public ZLibCodecompressor { public: ZLibDecompressor(); + ~ZLibDecompressor(); - ~ZLibDecompressor() { - inflateEnd(&stream_); - } - - virtual int processZStream() { - return inflate(&stream_, Z_SYNC_FLUSH); - } + virtual int processZStream(); }; } diff --git a/Swiften/Config/.gitignore b/Swiften/Config/.gitignore index 2ae0953..e7b484e 100644 --- a/Swiften/Config/.gitignore +++ b/Swiften/Config/.gitignore @@ -2,2 +2,4 @@ swiften-config swiften-config.h Paths.cpp +Path.cpp +String.cpp diff --git a/Swiften/Config/SConscript b/Swiften/Config/SConscript index 357a5e6..837884b 100644 --- a/Swiften/Config/SConscript +++ b/Swiften/Config/SConscript @@ -7,5 +7,5 @@ def replaceSwiftenPath(input) : def cStringVariable(env, cVar, sconsVar) : - result = "const char* " + cVar + "[] = {\n" + result = "static const char* " + cVar + "[] = {\n" # FIXME: Probably not very robust for var in sconsVar.split(" ") : @@ -18,21 +18,36 @@ config_flags = "" swiften_env = env.Clone() -swiften_env.MergeFlags(swiften_env["SWIFTEN_FLAGS"]) -swiften_env.MergeFlags(swiften_env["SWIFTEN_DEP_FLAGS"]) +swiften_env.UseFlags(swiften_env["SWIFTEN_FLAGS"]) +swiften_env.UseFlags(swiften_env["SWIFTEN_DEP_FLAGS"]) -cppflags = replaceSwiftenPath(" ".join([swiften_env.subst("$_CPPDEFFLAGS"), swiften_env.subst("$_CPPINCFLAGS")])) +cppflags = replaceSwiftenPath(" ".join([ + swiften_env.subst("$CPPFLAGS").replace("-isystem ","-I"), + swiften_env.subst("$_CPPDEFFLAGS"), + swiften_env.subst("$_CPPINCFLAGS")])) config_flags += cStringVariable(swiften_env, "CPPFLAGS", cppflags) -libflags = replaceSwiftenPath(" ".join([swiften_env.subst("$_LIBDIRFLAGS"), swiften_env.subst("$_LIBFLAGS")])) +libflags = replaceSwiftenPath(" ".join([ + swiften_env.subst("$_LIBDIRFLAGS"), + swiften_env.subst("$_LIBFLAGS"), + swiften_env.subst("$_FRAMEWORKPATH"), + swiften_env.subst("$_FRAMEWORKS"), + swiften_env.subst("$_FRAMEWORKSFLAGS") + ])) config_flags += cStringVariable(swiften_env, "LIBFLAGS", libflags) config_env = env.Clone() # Create a local copy of Paths.cpp to avoid a Swiften dependency -config_env.Install(".", "#/Swiften/Base/Paths.cpp") -config_env.MergeFlags(config_env["BOOST_FLAGS"]) -config_env.MergeFlags(config_env["PLATFORM_FLAGS"]) +config_env.Install(".", [ + "#/Swiften/Base/Paths.cpp", + "#/Swiften/Base/Path.cpp", + "#/Swiften/Base/String.cpp", +]) +config_env.UseFlags(config_env["BOOST_FLAGS"]) +config_env.UseFlags(config_env["PLATFORM_FLAGS"]) config_env.WriteVal("swiften-config.h", config_env.Value(config_flags)) swiften_config = config_env.Program("swiften-config", [ "Paths.cpp", + "Path.cpp", + "String.cpp", "swiften-config.cpp" ]) diff --git a/Swiften/Config/swiften-config.cpp b/Swiften/Config/swiften-config.cpp index 81a8357..778134d 100644 --- a/Swiften/Config/swiften-config.cpp +++ b/Swiften/Config/swiften-config.cpp @@ -17,4 +17,5 @@ #include <Swiften/Base/Platform.h> #include <Swiften/Base/Paths.h> +#include <Swiften/Base/Path.h> #include <Swiften/Version.h> @@ -23,5 +24,5 @@ using namespace Swift; -void printFlags(const std::vector<std::string>& flags) { +static void printFlags(const std::vector<std::string>& flags) { for (size_t i = 0; i < flags.size(); ++i) { if (i > 0) { @@ -91,10 +92,10 @@ int main(int argc, char* argv[]) { if (inPlace) { std::string lib = libs[i]; - boost::replace_all(lib, "#", topSourcePath.string()); + boost::replace_all(lib, "#", pathToString(topSourcePath)); libs[i] = lib; } else { std::string lib = libs[i]; - boost::replace_all(lib, "#", (topInstallPath / "lib").string()); + boost::replace_all(lib, "#", pathToString(topInstallPath / "lib")); boost::erase_all(lib, "/Swiften"); libs[i] = lib; @@ -104,10 +105,10 @@ int main(int argc, char* argv[]) { if (inPlace) { std::string cflag = cflags[i]; - boost::replace_all(cflag, "#", topSourcePath.string()); + boost::replace_all(cflag, "#", pathToString(topSourcePath)); cflags[i] = cflag; } else { std::string cflag = cflags[i]; - boost::replace_all(cflag, "#", (topInstallPath / "include").string()); + boost::replace_all(cflag, "#", pathToString(topInstallPath / "include")); cflags[i] = cflag; } @@ -119,5 +120,5 @@ int main(int argc, char* argv[]) { printFlags(libs); } - else if (vm.count("cflags") > 0) { + if (vm.count("cflags") > 0) { printFlags(cflags); } diff --git a/Swiften/Crypto/CommonCryptoCryptoProvider.cpp b/Swiften/Crypto/CommonCryptoCryptoProvider.cpp new file mode 100644 index 0000000..14f9284 --- /dev/null +++ b/Swiften/Crypto/CommonCryptoCryptoProvider.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Crypto/CommonCryptoCryptoProvider.h> + +#include <CommonCrypto/CommonDigest.h> +#include <CommonCrypto/CommonHMAC.h> +#include <cassert> + +#include <Swiften/Crypto/Hash.h> +#include <Swiften/Base/ByteArray.h> +#include <boost/numeric/conversion/cast.hpp> + +using namespace Swift; + +namespace { + class SHA1Hash : public Hash { + public: + SHA1Hash() : finalized(false) { + if (!CC_SHA1_Init(&context)) { + assert(false); + } + } + + ~SHA1Hash() { + } + + virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual std::vector<unsigned char> getHash() { + assert(!finalized); + std::vector<unsigned char> result(CC_SHA1_DIGEST_LENGTH); + CC_SHA1_Final(vecptr(result), &context); + return result; + } + + private: + template<typename ContainerType> + Hash& updateInternal(const ContainerType& data) { + assert(!finalized); + if (!CC_SHA1_Update(&context, vecptr(data), boost::numeric_cast<CC_LONG>(data.size()))) { + assert(false); + } + return *this; + } + + private: + CC_SHA1_CTX context; + bool finalized; + }; + + class MD5Hash : public Hash { + public: + MD5Hash() : finalized(false) { + if (!CC_MD5_Init(&context)) { + assert(false); + } + } + + ~MD5Hash() { + } + + virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual std::vector<unsigned char> getHash() { + assert(!finalized); + std::vector<unsigned char> result(CC_MD5_DIGEST_LENGTH); + CC_MD5_Final(vecptr(result), &context); + return result; + } + + private: + template<typename ContainerType> + Hash& updateInternal(const ContainerType& data) { + assert(!finalized); + if (!CC_MD5_Update(&context, vecptr(data), boost::numeric_cast<CC_LONG>(data.size()))) { + assert(false); + } + return *this; + } + + private: + CC_MD5_CTX context; + bool finalized; + }; + + template<typename T> + ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data) { + std::vector<unsigned char> result(CC_SHA1_DIGEST_LENGTH); + CCHmac(kCCHmacAlgSHA1, vecptr(key), key.size(), vecptr(data), boost::numeric_cast<CC_LONG>(data.size()), vecptr(result)); + return result; + } +} + +CommonCryptoCryptoProvider::CommonCryptoCryptoProvider() { +} + +CommonCryptoCryptoProvider::~CommonCryptoCryptoProvider() { +} + +Hash* CommonCryptoCryptoProvider::createSHA1() { + return new SHA1Hash(); +} + +Hash* CommonCryptoCryptoProvider::createMD5() { + return new MD5Hash(); +} + +ByteArray CommonCryptoCryptoProvider::getHMACSHA1(const SafeByteArray& key, const ByteArray& data) { + return getHMACSHA1Internal(key, data); +} + +ByteArray CommonCryptoCryptoProvider::getHMACSHA1(const ByteArray& key, const ByteArray& data) { + return getHMACSHA1Internal(key, data); +} + +bool CommonCryptoCryptoProvider::isMD5AllowedForCrypto() const { + return true; +} + diff --git a/Swiften/Crypto/CommonCryptoCryptoProvider.h b/Swiften/Crypto/CommonCryptoCryptoProvider.h new file mode 100644 index 0000000..f921e17 --- /dev/null +++ b/Swiften/Crypto/CommonCryptoCryptoProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Base/Override.h> + +namespace Swift { + class CommonCryptoCryptoProvider : public CryptoProvider { + public: + CommonCryptoCryptoProvider(); + ~CommonCryptoCryptoProvider(); + + virtual Hash* createSHA1() SWIFTEN_OVERRIDE; + virtual Hash* createMD5() SWIFTEN_OVERRIDE; + virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE; + virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE; + virtual bool isMD5AllowedForCrypto() const SWIFTEN_OVERRIDE; + }; +} diff --git a/Swiften/Crypto/CryptoProvider.cpp b/Swiften/Crypto/CryptoProvider.cpp new file mode 100644 index 0000000..0189de4 --- /dev/null +++ b/Swiften/Crypto/CryptoProvider.cpp @@ -0,0 +1,14 @@ +/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Crypto/CryptoProvider.h>
+
+#include <boost/shared_ptr.hpp>
+
+using namespace Swift;
+
+CryptoProvider::~CryptoProvider() {
+}
diff --git a/Swiften/Crypto/CryptoProvider.h b/Swiften/Crypto/CryptoProvider.h new file mode 100644 index 0000000..c1e1eb9 --- /dev/null +++ b/Swiften/Crypto/CryptoProvider.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Crypto/Hash.h> + +namespace Swift { + class Hash; + + class SWIFTEN_API CryptoProvider { + public: + virtual ~CryptoProvider(); + + virtual Hash* createSHA1() = 0; + virtual Hash* createMD5() = 0; + virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) = 0; + virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) = 0; + virtual bool isMD5AllowedForCrypto() const = 0; + + // Convenience + template<typename T> ByteArray getSHA1Hash(const T& data) { + return boost::shared_ptr<Hash>(createSHA1())->update(data).getHash(); + } + + template<typename T> ByteArray getMD5Hash(const T& data) { + return boost::shared_ptr<Hash>(createMD5())->update(data).getHash(); + } + }; +} diff --git a/Swiften/Crypto/Hash.cpp b/Swiften/Crypto/Hash.cpp new file mode 100644 index 0000000..35c7e70 --- /dev/null +++ b/Swiften/Crypto/Hash.cpp @@ -0,0 +1,12 @@ +/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Crypto/Hash.h>
+
+using namespace Swift;
+
+Hash::~Hash() {
+}
diff --git a/Swiften/Crypto/Hash.h b/Swiften/Crypto/Hash.h new file mode 100644 index 0000000..37c6ec8 --- /dev/null +++ b/Swiften/Crypto/Hash.h @@ -0,0 +1,24 @@ +/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/Base/SafeByteArray.h>
+
+namespace Swift {
+ class Hash {
+ public:
+ virtual ~Hash();
+
+ virtual Hash& update(const ByteArray& data) = 0;
+ virtual Hash& update(const SafeByteArray& data) = 0;
+
+ virtual std::vector<unsigned char> getHash() = 0;
+ };
+}
diff --git a/Swiften/Crypto/OpenSSLCryptoProvider.cpp b/Swiften/Crypto/OpenSSLCryptoProvider.cpp new file mode 100644 index 0000000..9b1d544 --- /dev/null +++ b/Swiften/Crypto/OpenSSLCryptoProvider.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Crypto/OpenSSLCryptoProvider.h> + +#include <openssl/sha.h> +#include <openssl/md5.h> +#include <openssl/hmac.h> +#include <cassert> +#include <boost/numeric/conversion/cast.hpp> + +#include <Swiften/Crypto/Hash.h> +#include <Swiften/Base/ByteArray.h> + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +using namespace Swift; + +namespace { + class SHA1Hash : public Hash { + public: + SHA1Hash() : finalized(false) { + if (!SHA1_Init(&context)) { + assert(false); + } + } + + ~SHA1Hash() { + } + + virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual std::vector<unsigned char> getHash() { + assert(!finalized); + std::vector<unsigned char> result(SHA_DIGEST_LENGTH); + SHA1_Final(vecptr(result), &context); + return result; + } + + private: + template<typename ContainerType> + Hash& updateInternal(const ContainerType& data) { + assert(!finalized); + if (!SHA1_Update(&context, vecptr(data), data.size())) { + assert(false); + } + return *this; + } + + private: + SHA_CTX context; + bool finalized; + }; + + class MD5Hash : public Hash { + public: + MD5Hash() : finalized(false) { + if (!MD5_Init(&context)) { + assert(false); + } + } + + ~MD5Hash() { + } + + virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual std::vector<unsigned char> getHash() { + assert(!finalized); + std::vector<unsigned char> result(MD5_DIGEST_LENGTH); + MD5_Final(vecptr(result), &context); + return result; + } + + private: + template<typename ContainerType> + Hash& updateInternal(const ContainerType& data) { + assert(!finalized); + if (!MD5_Update(&context, vecptr(data), data.size())) { + assert(false); + } + return *this; + } + + private: + MD5_CTX context; + bool finalized; + }; + + + template<typename T> + ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data) { + unsigned int len = SHA_DIGEST_LENGTH; + std::vector<unsigned char> result(len); + HMAC(EVP_sha1(), vecptr(key), boost::numeric_cast<int>(key.size()), vecptr(data), data.size(), vecptr(result), &len); + return result; + } +} + +OpenSSLCryptoProvider::OpenSSLCryptoProvider() { +} + +OpenSSLCryptoProvider::~OpenSSLCryptoProvider() { +} + +Hash* OpenSSLCryptoProvider::createSHA1() { + return new SHA1Hash(); +} + +Hash* OpenSSLCryptoProvider::createMD5() { + return new MD5Hash(); +} + +ByteArray OpenSSLCryptoProvider::getHMACSHA1(const SafeByteArray& key, const ByteArray& data) { + return getHMACSHA1Internal(key, data); +} + +ByteArray OpenSSLCryptoProvider::getHMACSHA1(const ByteArray& key, const ByteArray& data) { + return getHMACSHA1Internal(key, data); +} + +bool OpenSSLCryptoProvider::isMD5AllowedForCrypto() const { + return true; +} + diff --git a/Swiften/Crypto/OpenSSLCryptoProvider.h b/Swiften/Crypto/OpenSSLCryptoProvider.h new file mode 100644 index 0000000..9440aee --- /dev/null +++ b/Swiften/Crypto/OpenSSLCryptoProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Base/Override.h> + +namespace Swift { + class OpenSSLCryptoProvider : public CryptoProvider { + public: + OpenSSLCryptoProvider(); + ~OpenSSLCryptoProvider(); + + virtual Hash* createSHA1() SWIFTEN_OVERRIDE; + virtual Hash* createMD5() SWIFTEN_OVERRIDE; + virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE; + virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE; + virtual bool isMD5AllowedForCrypto() const SWIFTEN_OVERRIDE; + }; +} diff --git a/Swiften/Crypto/PlatformCryptoProvider.cpp b/Swiften/Crypto/PlatformCryptoProvider.cpp new file mode 100644 index 0000000..ab0fa7b --- /dev/null +++ b/Swiften/Crypto/PlatformCryptoProvider.cpp @@ -0,0 +1,32 @@ +/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Crypto/PlatformCryptoProvider.h>
+
+#include <cassert>
+
+#include <Swiften/Base/Platform.h>
+#if defined(SWIFTEN_PLATFORM_WIN32)
+#include <Swiften/Crypto/WindowsCryptoProvider.h>
+#elif defined(HAVE_COMMONCRYPTO_CRYPTO_PROVIDER)
+#include <Swiften/Crypto/CommonCryptoCryptoProvider.h>
+#elif defined(HAVE_OPENSSL_CRYPTO_PROVIDER)
+#include <Swiften/Crypto/OpenSSLCryptoProvider.h>
+#endif
+
+using namespace Swift;
+
+CryptoProvider* PlatformCryptoProvider::create() {
+#if defined(SWIFTEN_PLATFORM_WIN32)
+ return new WindowsCryptoProvider();
+#elif defined(HAVE_COMMONCRYPTO_CRYPTO_PROVIDER)
+ return new CommonCryptoCryptoProvider();
+#elif defined(HAVE_OPENSSL_CRYPTO_PROVIDER)
+ return new OpenSSLCryptoProvider();
+#endif
+ assert(false);
+ return NULL;
+}
diff --git a/Swiften/Crypto/PlatformCryptoProvider.h b/Swiften/Crypto/PlatformCryptoProvider.h new file mode 100644 index 0000000..0721887 --- /dev/null +++ b/Swiften/Crypto/PlatformCryptoProvider.h @@ -0,0 +1,17 @@ +/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+
+namespace Swift {
+ class CryptoProvider;
+
+ namespace PlatformCryptoProvider {
+ SWIFTEN_API CryptoProvider* create();
+ }
+}
diff --git a/Swiften/Crypto/SConscript b/Swiften/Crypto/SConscript new file mode 100644 index 0000000..ce4bdae --- /dev/null +++ b/Swiften/Crypto/SConscript @@ -0,0 +1,28 @@ +Import("swiften_env", "env")
+
+
+objects = swiften_env.SwiftenObject([
+ "CryptoProvider.cpp",
+ "Hash.cpp"
+])
+
+myenv = swiften_env.Clone()
+if myenv["PLATFORM"] == "win32" :
+ objects += myenv.SwiftenObject(["WindowsCryptoProvider.cpp"])
+if myenv.get("HAVE_OPENSSL", False) :
+ myenv.Append(CPPDEFINES = ["HAVE_OPENSSL_CRYPTO_PROVIDER"])
+ objects += myenv.SwiftenObject(["OpenSSLCryptoProvider.cpp"])
+if myenv["PLATFORM"] == "darwin" and myenv["target"] == "native" :
+ myenv.Append(CPPDEFINES = ["HAVE_COMMONCRYPTO_CRYPTO_PROVIDER"])
+ objects += myenv.SwiftenObject(["CommonCryptoCryptoProvider.cpp"])
+
+objects += myenv.SwiftenObject(["PlatformCryptoProvider.cpp"])
+
+swiften_env.Append(SWIFTEN_OBJECTS = [objects])
+
+if env["TEST"] :
+ test_env = myenv.Clone()
+ test_env.UseFlags(swiften_env["CPPUNIT_FLAGS"])
+ env.Append(UNITTEST_OBJECTS = test_env.SwiftenObject([
+ File("UnitTest/CryptoProviderTest.cpp"),
+ ]))
diff --git a/Swiften/Crypto/UnitTest/CryptoProviderTest.cpp b/Swiften/Crypto/UnitTest/CryptoProviderTest.cpp new file mode 100644 index 0000000..1e2275a --- /dev/null +++ b/Swiften/Crypto/UnitTest/CryptoProviderTest.cpp @@ -0,0 +1,156 @@ +/*
+ * Copyright (c) 2010-2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/Base/Platform.h>
+#include <QA/Checker/IO.h>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#ifdef SWIFTEN_PLATFORM_WIN32
+#include <Swiften/Crypto/WindowsCryptoProvider.h>
+#endif
+#ifdef HAVE_OPENSSL_CRYPTO_PROVIDER
+#include <Swiften/Crypto/OpenSSLCryptoProvider.h>
+#endif
+#ifdef HAVE_OPENSSL_CRYPTO_PROVIDER
+#include <Swiften/Crypto/CommonCryptoCryptoProvider.h>
+#endif
+#include <Swiften/Crypto/Hash.h>
+
+using namespace Swift;
+
+template <typename CryptoProviderType>
+class CryptoProviderTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(CryptoProviderTest);
+
+ CPPUNIT_TEST(testGetSHA1Hash);
+ CPPUNIT_TEST(testGetSHA1Hash_TwoUpdates);
+ CPPUNIT_TEST(testGetSHA1Hash_NoData);
+ CPPUNIT_TEST(testGetSHA1HashStatic);
+ CPPUNIT_TEST(testGetSHA1HashStatic_Twice);
+ CPPUNIT_TEST(testGetSHA1HashStatic_NoData);
+
+ CPPUNIT_TEST(testGetMD5Hash_Empty);
+ CPPUNIT_TEST(testGetMD5Hash_Alphabet);
+ CPPUNIT_TEST(testMD5Incremental);
+
+ CPPUNIT_TEST(testGetHMACSHA1);
+ CPPUNIT_TEST(testGetHMACSHA1_KeyLongerThanBlockSize);
+
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ provider = new CryptoProviderType();
+ }
+
+ void tearDown() {
+ delete provider;
+ }
+
+ ////////////////////////////////////////////////////////////
+ // SHA-1
+ ////////////////////////////////////////////////////////////
+
+ void testGetSHA1Hash() {
+ boost::shared_ptr<Hash> sha = boost::shared_ptr<Hash>(provider->createSHA1());
+ sha->update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<"));
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha->getHash());
+ }
+
+ void testGetSHA1Hash_TwoUpdates() {
+ boost::shared_ptr<Hash> sha = boost::shared_ptr<Hash>(provider->createSHA1());
+ sha->update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<"));
+ sha->update(createByteArray("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<"));
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha->getHash());
+ }
+
+ void testGetSHA1Hash_NoData() {
+ boost::shared_ptr<Hash> sha = boost::shared_ptr<Hash>(provider->createSHA1());
+ sha->update(std::vector<unsigned char>());
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), sha->getHash());
+ }
+
+ void testGetSHA1HashStatic() {
+ ByteArray result(provider->getSHA1Hash(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")));
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result);
+ }
+
+
+ void testGetSHA1HashStatic_Twice() {
+ ByteArray input(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<"));
+ provider->getSHA1Hash(input);
+ ByteArray result(provider->getSHA1Hash(input));
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result);
+ }
+
+ void testGetSHA1HashStatic_NoData() {
+ ByteArray result(provider->getSHA1Hash(ByteArray()));
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), result);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+ // MD5
+ ////////////////////////////////////////////////////////////
+
+ void testGetMD5Hash_Empty() {
+ ByteArray result(provider->getMD5Hash(createByteArray("")));
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e", 16), result);
+ }
+
+ void testGetMD5Hash_Alphabet() {
+ ByteArray result(provider->getMD5Hash(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")));
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", 16), result);
+ }
+
+ void testMD5Incremental() {
+ boost::shared_ptr<Hash> testling = boost::shared_ptr<Hash>(provider->createMD5());
+ testling->update(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+ testling->update(createByteArray("abcdefghijklmnopqrstuvwxyz0123456789"));
+
+ ByteArray result = testling->getHash();
+
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", 16), result);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+ // HMAC-SHA1
+ ////////////////////////////////////////////////////////////
+
+ void testGetHMACSHA1() {
+ ByteArray result(provider->getHMACSHA1(createSafeByteArray("foo"), createByteArray("foobar")));
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\xa4\xee\xba\x8e\x63\x3d\x77\x88\x69\xf5\x68\xd0\x5a\x1b\x3d\xc7\x2b\xfd\x4\xdd"), result);
+ }
+
+ void testGetHMACSHA1_KeyLongerThanBlockSize() {
+ ByteArray result(provider->getHMACSHA1(createSafeByteArray("---------|---------|---------|---------|---------|----------|---------|"), createByteArray("foobar")));
+ CPPUNIT_ASSERT_EQUAL(createByteArray("\xd6""n""\x8f""P|1""\xd3"",""\x6"" ""\xb9\xe3""gg""\x8e\xcf"" ]+""\xa"), result);
+ }
+
+ private:
+ CryptoProviderType* provider;
+};
+
+#ifdef SWIFTEN_PLATFORM_WIN32
+CPPUNIT_TEST_SUITE_REGISTRATION(CryptoProviderTest<WindowsCryptoProvider>);
+#endif
+#ifdef HAVE_OPENSSL_CRYPTO_PROVIDER
+CPPUNIT_TEST_SUITE_REGISTRATION(CryptoProviderTest<OpenSSLCryptoProvider>);
+#endif
+#ifdef HAVE_COMMONCRYPTO_CRYPTO_PROVIDER
+CPPUNIT_TEST_SUITE_REGISTRATION(CryptoProviderTest<CommonCryptoCryptoProvider>);
+#endif
diff --git a/Swiften/Crypto/WindowsCryptoProvider.cpp b/Swiften/Crypto/WindowsCryptoProvider.cpp new file mode 100644 index 0000000..9ca4c14 --- /dev/null +++ b/Swiften/Crypto/WindowsCryptoProvider.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Crypto/WindowsCryptoProvider.h> + +#include <Windows.h> +#define SECURITY_WIN32 +#include <security.h> +#include <Wincrypt.h> +#include <cassert> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Crypto/Hash.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/WindowsRegistry.h> + +using namespace Swift; + +struct WindowsCryptoProvider::Private { + HCRYPTPROV context; +}; + +namespace { + class WindowsHash : public Hash { + public: + WindowsHash(HCRYPTPROV context, ALG_ID algorithm) : hash(NULL) { + if (!CryptCreateHash(context, algorithm, 0, 0, &hash)) { + assert(false); + } + } + + ~WindowsHash() { + CryptDestroyHash(hash); + } + + virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual std::vector<unsigned char> getHash() { + std::vector<unsigned char> result; + DWORD hashLength = sizeof(DWORD); + DWORD hashSize; + CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &hashLength, 0); + result.resize(static_cast<size_t>(hashSize)); + if (!CryptGetHashParam(hash, HP_HASHVAL, vecptr(result), &hashSize, 0)) { + assert(false); + } + result.resize(static_cast<size_t>(hashSize)); + return result; + } + + private: + template<typename ContainerType> + Hash& updateInternal(const ContainerType& data) { + if (!CryptHashData(hash, const_cast<BYTE*>(vecptr(data)), data.size(), 0)) { + assert(false); + } + return *this; + } + + private: + HCRYPTHASH hash; + }; + +#if 0 // NOT YET DONE + // Haven't tested the code below properly yet, but figured out after writing + // it that PLAINTEXTKEYBLOB doesn't work on XP or 2k, and the workaround is a + // bit too ugly to try this now. So, using our own algorithm for now. See + // http://support.microsoft.com/kb/228786/en-us + + // MSDN describes this as PLAINTEXTKEYBLOB, but this struct doesn't exist, + // and seems to even conflict with the PLAINTEXTKEYBLOB constant. Redefining + // here. + struct PlainTextKeyBlob { + BLOBHEADER hdr; + DWORD dwKeySize; + }; + + class HMACHash : public Hash { + public: + template<typename T> + HMACHash(HCRYPTPROV context, const T& rawKey) : hash(NULL) { + // Import raw key + T blobData(sizeof(PlainTextKeyBlob) + rawKey.size()); + PlainTextKeyBlob* blob = reinterpret_cast<PlainTextKeyBlob*>(vecptr(blobData)); + blob->hdr.bType = PLAINTEXTKEYBLOB; + blob->hdr.bVersion = CUR_BLOB_VERSION; + blob->hdr.reserved = 0; + blob->hdr.aiKeyAlg = CALG_RC2; + blob->dwKeySize = rawKey.size(); + std::copy(rawKey.begin(), rawKey.end(), blobData.begin() + sizeof(PlainTextKeyBlob)); + HCRYPTKEY key; + if (!CryptImportKey(context, vecptr(blobData), blobData.size(), 0, CRYPT_IPSEC_HMAC_KEY, &key)) { + assert(false); + return; + } + + // Create hash + if (!CryptCreateHash(context, CALG_HMAC, key, 0, &hash)) { + assert(false); + return; + } + ZeroMemory(&info, sizeof(info)); + info.HashAlgid = CALG_SHA1; + } + + ~HMACHash() { + CryptDestroyHash(hash); + } + + virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE { + return updateInternal(data); + } + + virtual std::vector<unsigned char> getHash() { + std::vector<unsigned char> result; + DWORD hashLength = sizeof(DWORD); + DWORD hashSize; + CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &hashLength, 0); + result.resize(static_cast<size_t>(hashSize)); + if (!CryptGetHashParam(hash, HP_HASHVAL, vecptr(result), &hashSize, 0)) { + assert(false); + } + result.resize(static_cast<size_t>(hashSize)); + return result; + } + + private: + template<typename ContainerType> + Hash& updateInternal(const ContainerType& data) { + if (!CryptHashData(hash, const_cast<BYTE*>(vecptr(data)), data.size(), 0)) { + assert(false); + } + return *this; + } + + private: + HCRYPTHASH hash; + HMAC_INFO info; + }; +#endif + + // Simple implementation. + template<typename T> + ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data, CryptoProvider* crypto) { + static const int BLOCK_SIZE = 64; + + T paddedKey; + if (key.size() <= BLOCK_SIZE) { + paddedKey = key; + } + else { + assign(paddedKey, crypto->getSHA1Hash(key)); + } + paddedKey.resize(BLOCK_SIZE, 0x0); + + // Create the first value + T x(paddedKey); + for (unsigned int i = 0; i < x.size(); ++i) { + x[i] ^= 0x36; + } + append(x, data); + + // Create the second value + T y(paddedKey); + for (unsigned int i = 0; i < y.size(); ++i) { + y[i] ^= 0x5c; + } + append(y, crypto->getSHA1Hash(x)); + return crypto->getSHA1Hash(y); + } +} + +WindowsCryptoProvider::WindowsCryptoProvider() { + p = boost::make_shared<Private>(); + if (!CryptAcquireContext(&p->context, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + assert(false); + } +} + +WindowsCryptoProvider::~WindowsCryptoProvider() { + CryptReleaseContext(p->context, 0); +} + +Hash* WindowsCryptoProvider::createSHA1() { + return new WindowsHash(p->context, CALG_SHA1); +} + +Hash* WindowsCryptoProvider::createMD5() { + return new WindowsHash(p->context, CALG_MD5); +} + +bool WindowsCryptoProvider::isMD5AllowedForCrypto() const { + return !WindowsRegistry::isFIPSEnabled(); +} + +ByteArray WindowsCryptoProvider::getHMACSHA1(const SafeByteArray& key, const ByteArray& data) { + return getHMACSHA1Internal(key, data, this); +} + +ByteArray WindowsCryptoProvider::getHMACSHA1(const ByteArray& key, const ByteArray& data) { + return getHMACSHA1Internal(key, data, this); +} diff --git a/Swiften/Crypto/WindowsCryptoProvider.h b/Swiften/Crypto/WindowsCryptoProvider.h new file mode 100644 index 0000000..9418fc0 --- /dev/null +++ b/Swiften/Crypto/WindowsCryptoProvider.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Base/Override.h> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class WindowsCryptoProvider : public CryptoProvider, public boost::noncopyable { + public: + WindowsCryptoProvider(); + ~WindowsCryptoProvider(); + + virtual Hash* createSHA1() SWIFTEN_OVERRIDE; + virtual Hash* createMD5() SWIFTEN_OVERRIDE; + virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE; + virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE; + virtual bool isMD5AllowedForCrypto() const SWIFTEN_OVERRIDE; + + private: + struct Private; + boost::shared_ptr<Private> p; + }; +} diff --git a/Swiften/Disco/CapsInfoGenerator.cpp b/Swiften/Disco/CapsInfoGenerator.cpp index 6d84984..4332f76 100644 --- a/Swiften/Disco/CapsInfoGenerator.cpp +++ b/Swiften/Disco/CapsInfoGenerator.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,5 +12,5 @@ #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Elements/FormField.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/StringCodecs/Base64.h> @@ -23,5 +23,5 @@ namespace { namespace Swift { -CapsInfoGenerator::CapsInfoGenerator(const std::string& node) : node_(node) { +CapsInfoGenerator::CapsInfoGenerator(const std::string& node, CryptoProvider* crypto) : node_(node), crypto_(crypto) { } @@ -50,5 +50,5 @@ CapsInfo CapsInfoGenerator::generateCapsInfo(const DiscoInfo& discoInfo) const { } serializedCaps += field->getName() + "<"; - std::vector<std::string> values(field->getRawValues()); + std::vector<std::string> values(field->getValues()); std::sort(values.begin(), values.end()); foreach(const std::string& value, values) { @@ -58,5 +58,5 @@ CapsInfo CapsInfoGenerator::generateCapsInfo(const DiscoInfo& discoInfo) const { } - std::string version(Base64::encode(SHA1::getHash(createByteArray(serializedCaps)))); + std::string version(Base64::encode(crypto_->getSHA1Hash(createByteArray(serializedCaps)))); return CapsInfo(node_, version, "sha-1"); } diff --git a/Swiften/Disco/CapsInfoGenerator.h b/Swiften/Disco/CapsInfoGenerator.h index d1b2663..17a01dd 100644 --- a/Swiften/Disco/CapsInfoGenerator.h +++ b/Swiften/Disco/CapsInfoGenerator.h @@ -8,12 +8,14 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Elements/CapsInfo.h> namespace Swift { class DiscoInfo; + class CryptoProvider; - class CapsInfoGenerator { + class SWIFTEN_API CapsInfoGenerator { public: - CapsInfoGenerator(const std::string& node); + CapsInfoGenerator(const std::string& node, CryptoProvider* crypto); CapsInfo generateCapsInfo(const DiscoInfo& discoInfo) const; @@ -21,4 +23,5 @@ namespace Swift { private: std::string node_; + CryptoProvider* crypto_; }; } diff --git a/Swiften/Disco/CapsManager.cpp b/Swiften/Disco/CapsManager.cpp index 66eb47e..18f8745 100644 --- a/Swiften/Disco/CapsManager.cpp +++ b/Swiften/Disco/CapsManager.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,5 +18,5 @@ namespace Swift { -CapsManager::CapsManager(CapsStorage* capsStorage, StanzaChannel* stanzaChannel, IQRouter* iqRouter) : iqRouter(iqRouter), capsStorage(capsStorage), warnOnInvalidHash(true) { +CapsManager::CapsManager(CapsStorage* capsStorage, StanzaChannel* stanzaChannel, IQRouter* iqRouter, CryptoProvider* crypto) : iqRouter(iqRouter), crypto(crypto), capsStorage(capsStorage), warnOnInvalidHash(true) { stanzaChannel->onPresenceReceived.connect(boost::bind(&CapsManager::handlePresenceReceived, this, _1)); stanzaChannel->onAvailableChanged.connect(boost::bind(&CapsManager::handleStanzaChannelAvailableChanged, this, _1)); @@ -52,5 +52,5 @@ void CapsManager::handleStanzaChannelAvailableChanged(bool available) { void CapsManager::handleDiscoInfoReceived(const JID& from, const std::string& hash, DiscoInfo::ref discoInfo, ErrorPayload::ref error) { requestedDiscoInfos.erase(hash); - if (error || !discoInfo || CapsInfoGenerator("").generateCapsInfo(*discoInfo.get()).getVersion() != hash) { + if (error || !discoInfo || CapsInfoGenerator("", crypto).generateCapsInfo(*discoInfo.get()).getVersion() != hash) { if (warnOnInvalidHash && !error && discoInfo) { std::cerr << "Warning: Caps from " << from.toString() << " do not verify" << std::endl; diff --git a/Swiften/Disco/CapsManager.h b/Swiften/Disco/CapsManager.h index ddc7997..3529812 100644 --- a/Swiften/Disco/CapsManager.h +++ b/Swiften/Disco/CapsManager.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Elements/Presence.h> @@ -22,8 +23,9 @@ namespace Swift { class JID; class CapsStorage; + class CryptoProvider; - class CapsManager : public CapsProvider, public boost::bsignals::trackable { + class SWIFTEN_API CapsManager : public CapsProvider, public boost::bsignals::trackable { public: - CapsManager(CapsStorage*, StanzaChannel*, IQRouter*); + CapsManager(CapsStorage*, StanzaChannel*, IQRouter*, CryptoProvider*); DiscoInfo::ref getCaps(const std::string&) const; @@ -42,4 +44,5 @@ namespace Swift { private: IQRouter* iqRouter; + CryptoProvider* crypto; CapsStorage* capsStorage; bool warnOnInvalidHash; diff --git a/Swiften/Disco/CapsStorage.h b/Swiften/Disco/CapsStorage.h index fb6e442..7420c28 100644 --- a/Swiften/Disco/CapsStorage.h +++ b/Swiften/Disco/CapsStorage.h @@ -10,9 +10,8 @@ #include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Base/API.h> namespace Swift { - - - class CapsStorage { + class SWIFTEN_API CapsStorage { public: virtual ~CapsStorage(); diff --git a/Swiften/Disco/ClientDiscoManager.cpp b/Swiften/Disco/ClientDiscoManager.cpp index cca0144..f6683a8 100644 --- a/Swiften/Disco/ClientDiscoManager.cpp +++ b/Swiften/Disco/ClientDiscoManager.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,5 +13,5 @@ namespace Swift { -ClientDiscoManager::ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender) { +ClientDiscoManager::ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender, CryptoProvider* crypto) : crypto(crypto) { discoInfoResponder = new DiscoInfoResponder(iqRouter); discoInfoResponder->start(); @@ -30,5 +30,5 @@ void ClientDiscoManager::setCapsNode(const std::string& node) { void ClientDiscoManager::setDiscoInfo(const DiscoInfo& discoInfo) { - capsInfo = CapsInfo::ref(new CapsInfo(CapsInfoGenerator(capsNode).generateCapsInfo(discoInfo))); + capsInfo = CapsInfo::ref(new CapsInfo(CapsInfoGenerator(capsNode, crypto).generateCapsInfo(discoInfo))); discoInfoResponder->clearDiscoInfo(); discoInfoResponder->setDiscoInfo(discoInfo); diff --git a/Swiften/Disco/ClientDiscoManager.h b/Swiften/Disco/ClientDiscoManager.h index 6f126eb..a9ed10a 100644 --- a/Swiften/Disco/ClientDiscoManager.h +++ b/Swiften/Disco/ClientDiscoManager.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Elements/CapsInfo.h> #include <Swiften/Elements/DiscoInfo.h> @@ -16,4 +17,5 @@ namespace Swift { class PayloadAddingPresenceSender; class PresenceSender; + class CryptoProvider; /** @@ -27,5 +29,5 @@ namespace Swift { * called whenever the capabilities change. */ - class ClientDiscoManager { + class SWIFTEN_API ClientDiscoManager { public: /** @@ -36,5 +38,5 @@ namespace Swift { * (with caps information) will be sent. */ - ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender); + ClientDiscoManager(IQRouter* iqRouter, PresenceSender* presenceSender, CryptoProvider* crypto); ~ClientDiscoManager(); @@ -68,4 +70,5 @@ namespace Swift { private: PayloadAddingPresenceSender* presenceSender; + CryptoProvider* crypto; DiscoInfoResponder* discoInfoResponder; std::string capsNode; diff --git a/Swiften/Disco/DiscoInfoResponder.h b/Swiften/Disco/DiscoInfoResponder.h index af9f48f..cfe4d06 100644 --- a/Swiften/Disco/DiscoInfoResponder.h +++ b/Swiften/Disco/DiscoInfoResponder.h @@ -9,4 +9,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Queries/GetResponder.h> #include <Swiften/Elements/DiscoInfo.h> @@ -15,5 +16,5 @@ namespace Swift { class IQRouter; - class DiscoInfoResponder : public GetResponder<DiscoInfo> { + class SWIFTEN_API DiscoInfoResponder : public GetResponder<DiscoInfo> { public: DiscoInfoResponder(IQRouter* router); diff --git a/Swiften/Disco/DiscoServiceWalker.cpp b/Swiften/Disco/DiscoServiceWalker.cpp index c8c3e1b..0f27111 100644 --- a/Swiften/Disco/DiscoServiceWalker.cpp +++ b/Swiften/Disco/DiscoServiceWalker.cpp @@ -36,4 +36,5 @@ void DiscoServiceWalker::endWalk() { } active_ = false; + onWalkAborted(); } } diff --git a/Swiften/Disco/DiscoServiceWalker.h b/Swiften/Disco/DiscoServiceWalker.h index fd749fc..ea55a78 100644 --- a/Swiften/Disco/DiscoServiceWalker.h +++ b/Swiften/Disco/DiscoServiceWalker.h @@ -10,4 +10,5 @@ #include <set> +#include <Swiften/Base/API.h> #include <boost/shared_ptr.hpp> #include <Swiften/Base/boost_bsignals.h> @@ -26,5 +27,5 @@ namespace Swift { * This stops on any disco item that's not reporting itself as a server. */ - class DiscoServiceWalker { + class SWIFTEN_API DiscoServiceWalker { public: DiscoServiceWalker(const JID& service, IQRouter* iqRouter, size_t maxSteps = 200); @@ -49,4 +50,7 @@ namespace Swift { boost::signal<void(const JID&, boost::shared_ptr<DiscoInfo>)> onServiceFound; + /** Emitted when walking is aborted. */ + boost::signal<void()> onWalkAborted; + /** Emitted when walking is complete.*/ boost::signal<void()> onWalkComplete; diff --git a/Swiften/Disco/DummyEntityCapsProvider.h b/Swiften/Disco/DummyEntityCapsProvider.h index a1e3db6..713e21a 100644 --- a/Swiften/Disco/DummyEntityCapsProvider.h +++ b/Swiften/Disco/DummyEntityCapsProvider.h @@ -9,8 +9,9 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Disco/EntityCapsProvider.h> namespace Swift { - class DummyEntityCapsProvider : public EntityCapsProvider { + class SWIFTEN_API DummyEntityCapsProvider : public EntityCapsProvider { public: DummyEntityCapsProvider() { diff --git a/Swiften/Disco/EntityCapsManager.h b/Swiften/Disco/EntityCapsManager.h index e41c15f..4472ba5 100644 --- a/Swiften/Disco/EntityCapsManager.h +++ b/Swiften/Disco/EntityCapsManager.h @@ -9,4 +9,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Elements/Presence.h> @@ -25,5 +26,5 @@ namespace Swift { * information. */ - class EntityCapsManager : public EntityCapsProvider, public boost::bsignals::trackable { + class SWIFTEN_API EntityCapsManager : public EntityCapsProvider, public boost::bsignals::trackable { public: EntityCapsManager(CapsProvider*, StanzaChannel*); diff --git a/Swiften/Disco/EntityCapsProvider.h b/Swiften/Disco/EntityCapsProvider.h index b38992c..54b090b 100644 --- a/Swiften/Disco/EntityCapsProvider.h +++ b/Swiften/Disco/EntityCapsProvider.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/JID/JID.h> @@ -17,5 +18,5 @@ namespace Swift { * information. */ - class EntityCapsProvider { + class SWIFTEN_API EntityCapsProvider { public: virtual ~EntityCapsProvider(); diff --git a/Swiften/Disco/JIDDiscoInfoResponder.h b/Swiften/Disco/JIDDiscoInfoResponder.h index ebc1452..df529c6 100644 --- a/Swiften/Disco/JIDDiscoInfoResponder.h +++ b/Swiften/Disco/JIDDiscoInfoResponder.h @@ -9,4 +9,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Queries/GetResponder.h> #include <Swiften/Elements/DiscoInfo.h> @@ -16,5 +17,5 @@ namespace Swift { class IQRouter; - class JIDDiscoInfoResponder : public GetResponder<DiscoInfo> { + class SWIFTEN_API JIDDiscoInfoResponder : public GetResponder<DiscoInfo> { public: JIDDiscoInfoResponder(IQRouter* router); diff --git a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp index 52fdbaa..67d27c0 100644 --- a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp +++ b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,6 @@ #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Disco/CapsInfoGenerator.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -20,4 +22,8 @@ class CapsInfoGeneratorTest : public CppUnit::TestFixture { public: + void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + } + void testGenerate_XEP0115SimpleExample() { DiscoInfo discoInfo; @@ -28,5 +34,5 @@ class CapsInfoGeneratorTest : public CppUnit::TestFixture { discoInfo.addFeature("http://jabber.org/protocol/muc"); - CapsInfoGenerator testling("http://code.google.com/p/exodus"); + CapsInfoGenerator testling("http://code.google.com/p/exodus", crypto.get()); CapsInfo result = testling.generateCapsInfo(discoInfo); @@ -46,38 +52,34 @@ class CapsInfoGeneratorTest : public CppUnit::TestFixture { Form::ref extension(new Form(Form::ResultType)); - FormField::ref field = HiddenFormField::create("urn:xmpp:dataforms:softwareinfo"); + FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "urn:xmpp:dataforms:softwareinfo"); field->setName("FORM_TYPE"); extension->addField(field); - std::vector<std::string> ipVersions; - ipVersions.push_back("ipv6"); - ipVersions.push_back("ipv4"); - field = ListMultiFormField::create(ipVersions); - field->addRawValue("ipv6"); - field->addRawValue("ipv4"); + field = boost::make_shared<FormField>(FormField::ListMultiType); + field->addValue("ipv6"); + field->addValue("ipv4"); field->setName("ip_version"); extension->addField(field); - field = TextSingleFormField::create("Psi"); - field->addRawValue("Psi"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Psi"); field->setName("software"); extension->addField(field); - field = TextSingleFormField::create("0.11"); - field->addRawValue("0.11"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "0.11"); field->setName("software_version"); extension->addField(field); - field = TextSingleFormField::create("Mac"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Mac"); field->setName("os"); - field->addRawValue("Mac"); extension->addField(field); - field = TextSingleFormField::create("10.5.1"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "10.5.1"); field->setName("os_version"); - field->addRawValue("10.5.1"); extension->addField(field); discoInfo.addExtension(extension); - CapsInfoGenerator testling("http://psi-im.org"); + CapsInfoGenerator testling("http://psi-im.org", crypto.get()); CapsInfo result = testling.generateCapsInfo(discoInfo); CPPUNIT_ASSERT_EQUAL(std::string("q07IKJEyjvHSyhy//CH0CxmKi8w="), result.getVersion()); } + + private: + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Disco/UnitTest/CapsManagerTest.cpp b/Swiften/Disco/UnitTest/CapsManagerTest.cpp index ca55c48..303fd78 100644 --- a/Swiften/Disco/UnitTest/CapsManagerTest.cpp +++ b/Swiften/Disco/UnitTest/CapsManagerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,4 +17,6 @@ #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -42,4 +44,5 @@ class CapsManagerTest : public CppUnit::TestFixture { public: void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); stanzaChannel = new DummyStanzaChannel(); iqRouter = new IQRouter(stanzaChannel); @@ -48,10 +51,10 @@ class CapsManagerTest : public CppUnit::TestFixture { discoInfo1 = boost::make_shared<DiscoInfo>(); discoInfo1->addFeature("http://swift.im/feature1"); - capsInfo1 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im").generateCapsInfo(*discoInfo1.get())); - capsInfo1alt = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im").generateCapsInfo(*discoInfo1.get())); + capsInfo1 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im", crypto.get()).generateCapsInfo(*discoInfo1.get())); + capsInfo1alt = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo1.get())); user2 = JID("user2@foo.com/baz"); discoInfo2 = boost::make_shared<DiscoInfo>(); discoInfo2->addFeature("http://swift.im/feature2"); - capsInfo2 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im").generateCapsInfo(*discoInfo2.get())); + capsInfo2 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo2.get())); user3 = JID("user3@foo.com/baz"); legacyCapsInfo = boost::make_shared<CapsInfo>("http://swift.im", "ver1", ""); @@ -247,5 +250,5 @@ class CapsManagerTest : public CppUnit::TestFixture { private: boost::shared_ptr<CapsManager> createManager() { - boost::shared_ptr<CapsManager> manager(new CapsManager(storage, stanzaChannel, iqRouter)); + boost::shared_ptr<CapsManager> manager(new CapsManager(storage, stanzaChannel, iqRouter, crypto.get())); manager->setWarnOnInvalidHash(false); //manager->onCapsChanged.connect(boost::bind(&CapsManagerTest::handleCapsChanged, this, _1)); @@ -282,4 +285,5 @@ class CapsManagerTest : public CppUnit::TestFixture { boost::shared_ptr<CapsInfo> legacyCapsInfo; JID user3; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp b/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp index 0fd966d..940f043 100644 --- a/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp +++ b/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -15,4 +15,6 @@ #include <Swiften/Client/DummyStanzaChannel.h> #include <Swiften/Disco/CapsInfoGenerator.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -31,4 +33,6 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { public: void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + stanzaChannel = new DummyStanzaChannel(); capsProvider = new DummyCapsProvider(); @@ -37,10 +41,10 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { discoInfo1 = boost::make_shared<DiscoInfo>(); discoInfo1->addFeature("http://swift.im/feature1"); - capsInfo1 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im").generateCapsInfo(*discoInfo1.get())); - capsInfo1alt = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im").generateCapsInfo(*discoInfo1.get())); + capsInfo1 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im", crypto.get()).generateCapsInfo(*discoInfo1.get())); + capsInfo1alt = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo1.get())); user2 = JID("user2@foo.com/baz"); discoInfo2 = boost::make_shared<DiscoInfo>(); discoInfo2->addFeature("http://swift.im/feature2"); - capsInfo2 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im").generateCapsInfo(*discoInfo2.get())); + capsInfo2 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo2.get())); user3 = JID("user3@foo.com/baz"); legacyCapsInfo = boost::make_shared<CapsInfo>("http://swift.im", "ver1", ""); @@ -184,4 +188,5 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { JID user3; std::vector<JID> changes; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/Elements/AuthChallenge.h b/Swiften/Elements/AuthChallenge.h index f7f2796..6332d69 100644 --- a/Swiften/Elements/AuthChallenge.h +++ b/Swiften/Elements/AuthChallenge.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,8 +10,8 @@ #include <vector> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class AuthChallenge : public Element { + class AuthChallenge : public ToplevelElement { public: AuthChallenge() { diff --git a/Swiften/Elements/AuthFailure.h b/Swiften/Elements/AuthFailure.h index ac40956..5088dcf 100644 --- a/Swiften/Elements/AuthFailure.h +++ b/Swiften/Elements/AuthFailure.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class AuthFailure : public Element { + class AuthFailure : public ToplevelElement { public: typedef boost::shared_ptr<AuthFailure> ref; diff --git a/Swiften/Elements/AuthRequest.h b/Swiften/Elements/AuthRequest.h index bfc86c2..bc88b9b 100644 --- a/Swiften/Elements/AuthRequest.h +++ b/Swiften/Elements/AuthRequest.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,9 +11,9 @@ #include <boost/optional.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Base/SafeByteArray.h> namespace Swift { - class AuthRequest : public Element { + class AuthRequest : public ToplevelElement { public: AuthRequest(const std::string& mechanism = "") : mechanism_(mechanism) { diff --git a/Swiften/Elements/AuthResponse.h b/Swiften/Elements/AuthResponse.h index db2dcea..f8a075c 100644 --- a/Swiften/Elements/AuthResponse.h +++ b/Swiften/Elements/AuthResponse.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,9 +10,9 @@ #include <boost/optional.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Base/SafeByteArray.h> namespace Swift { - class AuthResponse : public Element { + class AuthResponse : public ToplevelElement { public: AuthResponse() { diff --git a/Swiften/Elements/AuthSuccess.h b/Swiften/Elements/AuthSuccess.h index 3c0f329..8e4591c 100644 --- a/Swiften/Elements/AuthSuccess.h +++ b/Swiften/Elements/AuthSuccess.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,8 +10,8 @@ #include <boost/optional.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class AuthSuccess : public Element { + class AuthSuccess : public ToplevelElement { public: AuthSuccess() {} diff --git a/Swiften/Elements/BlockListPayload.h b/Swiften/Elements/BlockListPayload.h index 25cb602..49df75f 100644 --- a/Swiften/Elements/BlockListPayload.h +++ b/Swiften/Elements/BlockListPayload.h @@ -15,5 +15,5 @@ namespace Swift { class BlockListPayload : public Payload { public: - BlockListPayload() { + BlockListPayload(const std::vector<JID>& items = std::vector<JID>()) : items(items) { } diff --git a/Swiften/Elements/BlockPayload.h b/Swiften/Elements/BlockPayload.h index 6dd5170..49a0463 100644 --- a/Swiften/Elements/BlockPayload.h +++ b/Swiften/Elements/BlockPayload.h @@ -15,5 +15,5 @@ namespace Swift { class BlockPayload : public Payload { public: - BlockPayload() { + BlockPayload(const std::vector<JID>& jids = std::vector<JID>()) : items(jids) { } diff --git a/Swiften/Elements/Command.h b/Swiften/Elements/Command.h index 91ae5a3..5454d8d 100644 --- a/Swiften/Elements/Command.h +++ b/Swiften/Elements/Command.h @@ -27,5 +27,5 @@ namespace Swift { enum Type {Info, Warn, Error}; - Note(std::string note, Type type) : note(note), type(type) {}; + Note(std::string note, Type type) : note(note), type(type) {} std::string note; diff --git a/Swiften/Elements/ComponentHandshake.h b/Swiften/Elements/ComponentHandshake.h index 5992b8c..b2f9b21 100644 --- a/Swiften/Elements/ComponentHandshake.h +++ b/Swiften/Elements/ComponentHandshake.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,8 +10,8 @@ #include <string> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class ComponentHandshake : public Element { + class ComponentHandshake : public ToplevelElement { public: typedef boost::shared_ptr<ComponentHandshake> ref; diff --git a/Swiften/Elements/CompressFailure.h b/Swiften/Elements/CompressFailure.h index 7dd8867..75e1d1d 100644 --- a/Swiften/Elements/CompressFailure.h +++ b/Swiften/Elements/CompressFailure.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,8 +8,8 @@ -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class CompressFailure : public Element { + class CompressFailure : public ToplevelElement { public: CompressFailure() {} diff --git a/Swiften/Elements/CompressRequest.h b/Swiften/Elements/CompressRequest.h index b6fcc64..9e2e267 100644 --- a/Swiften/Elements/CompressRequest.h +++ b/Swiften/Elements/CompressRequest.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,8 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class CompressRequest : public Element + class CompressRequest : public ToplevelElement { public: diff --git a/Swiften/Elements/Compressed.h b/Swiften/Elements/Compressed.h index 2affec5..f593412 100644 --- a/Swiften/Elements/Compressed.h +++ b/Swiften/Elements/Compressed.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,8 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class Compressed : public Element { + class Compressed : public ToplevelElement { public: Compressed() {} diff --git a/Swiften/Elements/ContainerPayload.h b/Swiften/Elements/ContainerPayload.h new file mode 100644 index 0000000..e2a4682 --- /dev/null +++ b/Swiften/Elements/ContainerPayload.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace Swift { + template<typename T> + class SWIFTEN_API ContainerPayload : public Payload { + public: + ContainerPayload() {} + ContainerPayload(boost::shared_ptr<T> payload) : payload(payload) {} + + void setPayload(boost::shared_ptr<T> payload) { + this->payload = payload; + } + + boost::shared_ptr<T> getPayload() const { + return payload; + } + + private: + boost::shared_ptr<T> payload; + }; +} diff --git a/Swiften/Elements/Delay.h b/Swiften/Elements/Delay.h index f7c4570..f4376dc 100644 --- a/Swiften/Elements/Delay.h +++ b/Swiften/Elements/Delay.h @@ -16,12 +16,12 @@ namespace Swift { class Delay : public Payload { public: - Delay() {}; - Delay(const boost::posix_time::ptime& time, const JID& from = JID()) : time_(time), from_(from) {}; + Delay() {} + Delay(const boost::posix_time::ptime& time, const JID& from = JID()) : time_(time), from_(from) {} - const boost::posix_time::ptime& getStamp() const {return time_;}; - void setStamp(const boost::posix_time::ptime& time) {time_ = time;}; + const boost::posix_time::ptime& getStamp() const {return time_;} + void setStamp(const boost::posix_time::ptime& time) {time_ = time;} - const boost::optional<JID>& getFrom() const {return from_;}; - void setFrom(const JID& from) {from_ = from;}; + const boost::optional<JID>& getFrom() const {return from_;} + void setFrom(const JID& from) {from_ = from;} private: diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp index a4ce079..f353c42 100644 --- a/Swiften/Elements/DiscoInfo.cpp +++ b/Swiften/Elements/DiscoInfo.cpp @@ -23,4 +23,6 @@ const std::string DiscoInfo::JingleTransportsS5BFeature = std::string("urn:xmpp: const std::string DiscoInfo::Bytestream = std::string("http://jabber.org/protocol/bytestreams"); const std::string DiscoInfo::MessageDeliveryReceiptsFeature = std::string("urn:xmpp:receipts"); +const std::string DiscoInfo::WhiteboardFeature = std::string("http://swift.im/whiteboard"); +const std::string DiscoInfo::BlockingCommandFeature = std::string("urn:xmpp:blocking"); bool DiscoInfo::Identity::operator<(const Identity& other) const { diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h index fec60d6..3701096 100644 --- a/Swiften/Elements/DiscoInfo.h +++ b/Swiften/Elements/DiscoInfo.h @@ -10,4 +10,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Payload.h> #include <Swiften/Elements/Form.h> @@ -17,5 +18,5 @@ namespace Swift { * disco#info from XEP-0030 */ - class DiscoInfo : public Payload { + class SWIFTEN_API DiscoInfo : public Payload { public: typedef boost::shared_ptr<DiscoInfo> ref; @@ -33,4 +34,6 @@ namespace Swift { static const std::string Bytestream; static const std::string MessageDeliveryReceiptsFeature; + static const std::string WhiteboardFeature; + static const std::string BlockingCommandFeature; class Identity { diff --git a/Swiften/Elements/Element.cpp b/Swiften/Elements/Element.cpp index 94829ba..6014ea2 100644 --- a/Swiften/Elements/Element.cpp +++ b/Swiften/Elements/Element.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. diff --git a/Swiften/Elements/Element.h b/Swiften/Elements/Element.h index 1e6a9d0..6bcf93e 100644 --- a/Swiften/Elements/Element.h +++ b/Swiften/Elements/Element.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,14 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { - class Element { + class SWIFTEN_API Element { public: + Element() {} + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(Element) virtual ~Element(); + + SWIFTEN_DEFAULT_COPY_ASSIGMNENT_OPERATOR(Element) }; } diff --git a/Swiften/Elements/EnableStreamManagement.h b/Swiften/Elements/EnableStreamManagement.h index 15a091e..732b225 100644 --- a/Swiften/Elements/EnableStreamManagement.h +++ b/Swiften/Elements/EnableStreamManagement.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,9 +7,9 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class EnableStreamManagement : public Element { + class EnableStreamManagement : public ToplevelElement { public: EnableStreamManagement() {} diff --git a/Swiften/Elements/Form.cpp b/Swiften/Elements/Form.cpp index cf9ecf6..4915e2a 100644 --- a/Swiften/Elements/Form.cpp +++ b/Swiften/Elements/Form.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,6 +12,8 @@ namespace Swift { std::string Form::getFormType() const { FormField::ref field = getField("FORM_TYPE"); - boost::shared_ptr<HiddenFormField> f = boost::dynamic_pointer_cast<HiddenFormField>(field); - return (f ? f->getValue() : ""); + if (field && field->getType() == FormField::HiddenType) { + return field->getValues().empty() ? "" : field->getValues()[0]; + } + return ""; } @@ -41,3 +43,23 @@ const std::vector<Form::FormItem>& Form::getItems() const { } +void Form::clearEmptyTextFields() { + std::vector<FormField::ref> populatedFields; + foreach (FormField::ref field, fields_) { + if (field->getType() == FormField::TextSingleType) { + if (!field->getTextSingleValue().empty()) { + populatedFields.push_back(field); + } + } + else if (field->getType() == FormField::TextMultiType) { + if (!field->getTextMultiValue().empty()) { + populatedFields.push_back(field); + } + } + else { + populatedFields.push_back(field); + } + } + fields_ = populatedFields; +} + } diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h index 2c6f963..16cef98 100644 --- a/Swiften/Elements/Form.h +++ b/Swiften/Elements/Form.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Payload.h> #include <Swiften/Elements/FormField.h> @@ -20,5 +21,5 @@ namespace Swift { * the strange multi-value instead of newline thing by transforming them. */ - class Form : public Payload { + class SWIFTEN_API Form : public Payload { public: typedef boost::shared_ptr<Form> ref; @@ -35,4 +36,5 @@ namespace Swift { void addField(boost::shared_ptr<FormField> field) {assert(field); fields_.push_back(field); } const std::vector<boost::shared_ptr<FormField> >& getFields() const { return fields_; } + void clearFields() { fields_.clear(); } void setTitle(const std::string& title) { title_ = title; } const std::string& getTitle() const { return title_; } @@ -50,7 +52,12 @@ namespace Swift { void addReportedField(FormField::ref field); const std::vector<FormField::ref>& getReportedFields() const; + void clearReportedFields() { reportedFields_.clear(); } void addItem(const FormItem& item); const std::vector<FormItem>& getItems() const; + void clearItems() { items_.clear(); } + + void clearEmptyTextFields(); + private: std::vector<boost::shared_ptr<FormField> > fields_; diff --git a/Swiften/Elements/FormField.cpp b/Swiften/Elements/FormField.cpp new file mode 100644 index 0000000..e9e4f77 --- /dev/null +++ b/Swiften/Elements/FormField.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/FormField.h> + +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/join.hpp> +#include <boost/algorithm/string/classification.hpp> + +using namespace Swift; + +FormField::~FormField() { +} + +std::string FormField::getTextMultiValue() const { + assert(type == TextMultiType || type == UnknownType); + return boost::algorithm::join(values, "\n"); +} + +void FormField::setTextMultiValue(const std::string& value) { + assert(type == TextMultiType || type == UnknownType); + values.clear(); + boost::split(values, value, boost::is_any_of("\n")); +} + +void FormField::setBoolValue(bool b) { + values.clear(); + values.push_back(b ? "1" : "0"); +} diff --git a/Swiften/Elements/FormField.h b/Swiften/Elements/FormField.h index e8fe3a0..f0bebd9 100644 --- a/Swiften/Elements/FormField.h +++ b/Swiften/Elements/FormField.h @@ -1,11 +1,8 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * 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 @@ -21,5 +18,23 @@ namespace Swift { typedef boost::shared_ptr<FormField> ref; - virtual ~FormField() {} + enum Type { + UnknownType, + BooleanType, + FixedType, + HiddenType, + ListSingleType, + TextMultiType, + TextPrivateType, + TextSingleType, + JIDSingleType, + JIDMultiType, + ListMultiType + }; + + FormField(Type type = UnknownType) : type(type), required(false) {} + FormField(Type type, const std::string& value) : type(type), required(false) { + addValue(value); + } + virtual ~FormField(); struct Option { @@ -49,66 +64,75 @@ namespace Swift { } - const std::vector<std::string>& getRawValues() const { - return rawValues; + void clearOptions() { + options.clear(); } - void addRawValue(const std::string& value) { - rawValues.push_back(value); + const std::vector<std::string>& getValues() const { + return values; } - protected: - FormField() : required(false) {} + void addValue(const std::string& value) { + values.push_back(value); + } - private: - std::string name; - std::string label; - std::string description; - bool required; - std::vector<Option> options; - std::vector<std::string> rawValues; - }; + Type getType() const { + return type; + } - template<typename T> class GenericFormField : public FormField { - public: - const T& getValue() const { - return value; + void setType(Type type) { + this->type = type; + } + + // Type specific + + bool getBoolValue() const { + assert(type == BooleanType || type == UnknownType); + if (values.empty()) { + return false; + } + return values[0] == "true" || values[0] == "1"; + } + + void setBoolValue(bool b); + + JID getJIDSingleValue() const { + assert(type == JIDSingleType || type == UnknownType); + return values.empty() ? JID() : JID(values[0]); + } + + JID getJIDMultiValue(size_t index) const { + assert(type == JIDMultiType || type == UnknownType); + return values.empty() ? JID() : JID(values[index]); + } + + std::string getTextPrivateValue() const { + assert(type == TextPrivateType || type == UnknownType); + return values.empty() ? "" : values[0]; + } + + std::string getFixedValue() const { + assert(type == FixedType || type == UnknownType); + return values.empty() ? "" : values[0]; } - void setValue(const T& value) { - this->value = value; + std::string getTextSingleValue() const { + assert(type == TextSingleType || type == UnknownType); + return values.empty() ? "" : values[0]; } + std::string getTextMultiValue() const; + void setTextMultiValue(const std::string& value); + protected: - GenericFormField() : value() {} - GenericFormField(const T& value) : value(value) {} private: - T value; - }; - -#define SWIFTEN_DECLARE_FORM_FIELD(name, valueType) \ - class name##FormField : public GenericFormField< valueType > { \ - public: \ - typedef boost::shared_ptr<name##FormField> ref; \ - static ref create(const valueType& value) { \ - return ref(new name##FormField(value)); \ - } \ - static ref create() { \ - return ref(new name##FormField()); \ - } \ - private: \ - name##FormField(valueType value) : GenericFormField< valueType >(value) {} \ - name##FormField() : GenericFormField< valueType >() {} \ + Type type; + std::string name; + std::string label; + std::string description; + bool required; + std::vector<Option> options; + std::vector<std::string> values; }; - SWIFTEN_DECLARE_FORM_FIELD(Boolean, bool); - SWIFTEN_DECLARE_FORM_FIELD(Fixed, std::string); - SWIFTEN_DECLARE_FORM_FIELD(Hidden, std::string); - SWIFTEN_DECLARE_FORM_FIELD(ListSingle, std::string); - SWIFTEN_DECLARE_FORM_FIELD(TextMulti, std::string); - SWIFTEN_DECLARE_FORM_FIELD(TextPrivate, std::string); - SWIFTEN_DECLARE_FORM_FIELD(TextSingle, std::string); - SWIFTEN_DECLARE_FORM_FIELD(JIDSingle, JID); - SWIFTEN_DECLARE_FORM_FIELD(JIDMulti, std::vector<JID>); - SWIFTEN_DECLARE_FORM_FIELD(ListMulti, std::vector<std::string>); } diff --git a/Swiften/Elements/Forwarded.cpp b/Swiften/Elements/Forwarded.cpp new file mode 100644 index 0000000..590c1ca --- /dev/null +++ b/Swiften/Elements/Forwarded.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/Forwarded.h> + +using namespace Swift; + +Forwarded::~Forwarded() { +} diff --git a/Swiften/Elements/Forwarded.h b/Swiften/Elements/Forwarded.h new file mode 100644 index 0000000..f1a718c --- /dev/null +++ b/Swiften/Elements/Forwarded.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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 <boost/date_time/posix_time/posix_time.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class Delay; + class Stanza; + + class SWIFTEN_API Forwarded : public Payload { + public: + virtual ~Forwarded(); + + void setDelay(boost::shared_ptr<Delay> delay) { delay_ = delay; } + const boost::shared_ptr<Delay>& getDelay() const { return delay_; } + + void setStanza(boost::shared_ptr<Stanza> stanza) { stanza_ = stanza; } + const boost::shared_ptr<Stanza>& getStanza() const { return stanza_; } + + private: + boost::shared_ptr<Delay> delay_; + boost::shared_ptr<Stanza> stanza_; + }; +} diff --git a/Swiften/Elements/IBB.h b/Swiften/Elements/IBB.h index 64c9f14..fb33eaf 100644 --- a/Swiften/Elements/IBB.h +++ b/Swiften/Elements/IBB.h @@ -22,9 +22,9 @@ namespace Swift { Open, Close, - Data, + Data }; enum StanzaType { IQStanza, - MessageStanza, + MessageStanza }; diff --git a/Swiften/Elements/IQ.cpp b/Swiften/Elements/IQ.cpp index 8e6d7cc..8c0f692 100644 --- a/Swiften/Elements/IQ.cpp +++ b/Swiften/Elements/IQ.cpp @@ -45,18 +45,22 @@ boost::shared_ptr<IQ> IQ::createResult(const JID& to, const JID& from, const std } -boost::shared_ptr<IQ> IQ::createError(const JID& to, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type) { +boost::shared_ptr<IQ> IQ::createError(const JID& to, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type, boost::shared_ptr<Payload> payload) { boost::shared_ptr<IQ> iq = boost::make_shared<IQ>(IQ::Error); iq->setTo(to); iq->setID(id); - iq->addPayload(boost::make_shared<Swift::ErrorPayload>(condition, type)); + boost::shared_ptr<ErrorPayload> errorPayload = boost::make_shared<Swift::ErrorPayload>(condition, type); + errorPayload->setPayload(payload); + iq->addPayload(errorPayload); return iq; } -boost::shared_ptr<IQ> IQ::createError(const JID& to, const JID& from, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type) { +boost::shared_ptr<IQ> IQ::createError(const JID& to, const JID& from, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type, boost::shared_ptr<Payload> payload) { boost::shared_ptr<IQ> iq = boost::make_shared<IQ>(IQ::Error); iq->setTo(to); iq->setFrom(from); iq->setID(id); - iq->addPayload(boost::make_shared<Swift::ErrorPayload>(condition, type)); + boost::shared_ptr<ErrorPayload> errorPayload = boost::make_shared<Swift::ErrorPayload>(condition, type); + errorPayload->setPayload(payload); + iq->addPayload(errorPayload); return iq; } diff --git a/Swiften/Elements/IQ.h b/Swiften/Elements/IQ.h index 05cd96a..ff978b3 100644 --- a/Swiften/Elements/IQ.h +++ b/Swiften/Elements/IQ.h @@ -9,9 +9,10 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Stanza.h> #include <Swiften/Elements/ErrorPayload.h> namespace Swift { - class IQ : public Stanza { + class SWIFTEN_API IQ : public Stanza { public: typedef boost::shared_ptr<IQ> ref; @@ -42,5 +43,6 @@ namespace Swift { const std::string& id, ErrorPayload::Condition condition = ErrorPayload::BadRequest, - ErrorPayload::Type type = ErrorPayload::Cancel); + ErrorPayload::Type type = ErrorPayload::Cancel, + boost::shared_ptr<Payload> payload = boost::shared_ptr<Payload>()); static boost::shared_ptr<IQ> createError( const JID& to, @@ -48,5 +50,6 @@ namespace Swift { const std::string& id, ErrorPayload::Condition condition = ErrorPayload::BadRequest, - ErrorPayload::Type type = ErrorPayload::Cancel); + ErrorPayload::Type type = ErrorPayload::Cancel, + boost::shared_ptr<Payload> payload = boost::shared_ptr<Payload>()); private: diff --git a/Swiften/Elements/Idle.h b/Swiften/Elements/Idle.h new file mode 100644 index 0000000..572eba2 --- /dev/null +++ b/Swiften/Elements/Idle.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> + +#include <Swiften/Elements/Payload.h> + +namespace Swift { + + class Idle : public Payload { + public: + typedef boost::shared_ptr<Idle> ref; + + public: + Idle() {} + Idle(boost::posix_time::ptime since) : since_(since) { + } + + void setSince(boost::posix_time::ptime since) { + since_ = since; + } + + boost::posix_time::ptime getSince() const { + return since_; + } + + private: + boost::posix_time::ptime since_; + }; + +} diff --git a/Swiften/Elements/IsodeIQDelegation.cpp b/Swiften/Elements/IsodeIQDelegation.cpp new file mode 100644 index 0000000..ce13e2a --- /dev/null +++ b/Swiften/Elements/IsodeIQDelegation.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2014 Remko Tronçon and Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/IsodeIQDelegation.h> + +using namespace Swift; + +IsodeIQDelegation::IsodeIQDelegation() { +} + +IsodeIQDelegation::~IsodeIQDelegation() { +} diff --git a/Swiften/Elements/IsodeIQDelegation.h b/Swiften/Elements/IsodeIQDelegation.h new file mode 100644 index 0000000..7935a4f --- /dev/null +++ b/Swiften/Elements/IsodeIQDelegation.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Remko Tronçon and Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/Forwarded.h> + +namespace Swift { + class SWIFTEN_API IsodeIQDelegation : public Payload { + public: + + IsodeIQDelegation(); + + virtual ~IsodeIQDelegation(); + + boost::shared_ptr<Forwarded> getForward() const { + return forward; + } + + void setForward(boost::shared_ptr<Forwarded> value) { + this->forward = value ; + } + + + private: + boost::shared_ptr<Forwarded> forward; + }; +} diff --git a/Swiften/Elements/JingleContentPayload.h b/Swiften/Elements/JingleContentPayload.h index 183b8eb..ac62866 100644 --- a/Swiften/Elements/JingleContentPayload.h +++ b/Swiften/Elements/JingleContentPayload.h @@ -24,7 +24,10 @@ namespace Swift { UnknownCreator, InitiatorCreator, - ResponderCreator, + ResponderCreator }; + JingleContentPayload() : creator(UnknownCreator) { + } + /*enum Senders { NoSenders, diff --git a/Swiften/Elements/JingleIBBTransportPayload.h b/Swiften/Elements/JingleIBBTransportPayload.h index 8c174f0..5704c00 100644 --- a/Swiften/Elements/JingleIBBTransportPayload.h +++ b/Swiften/Elements/JingleIBBTransportPayload.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> #include <string> @@ -19,7 +20,10 @@ namespace Swift { enum StanzaType { IQStanza, - MessageStanza, + MessageStanza }; + JingleIBBTransportPayload() : stanzaType(IQStanza) { + } + void setStanzaType(StanzaType stanzaType) { this->stanzaType = stanzaType; @@ -30,14 +34,14 @@ namespace Swift { } - int getBlockSize() const { + boost::optional<unsigned int> getBlockSize() const { return blockSize; } - void setBlockSize(int blockSize) { + void setBlockSize(unsigned int blockSize) { this->blockSize = blockSize; } private: - int blockSize; + boost::optional<unsigned int> blockSize; StanzaType stanzaType; }; diff --git a/Swiften/Elements/JinglePayload.h b/Swiften/Elements/JinglePayload.h index 31d4448..7d7160b 100644 --- a/Swiften/Elements/JinglePayload.h +++ b/Swiften/Elements/JinglePayload.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,10 +12,9 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <Swiften/Elements/Payload.h> #include <Swiften/Elements/JingleContentPayload.h> -#include <Swiften/Base/Log.h> - namespace Swift { class JinglePayload : public Payload { @@ -45,5 +44,4 @@ namespace Swift { Reason() : type(UnknownType), text("") {} Reason(Type type, const std::string& text = "") : type(type), text(text) {} - ~Reason() {} Type type; std::string text; diff --git a/Swiften/Elements/JingleS5BTransportPayload.h b/Swiften/Elements/JingleS5BTransportPayload.h index 995933c..41bf809 100644 --- a/Swiften/Elements/JingleS5BTransportPayload.h +++ b/Swiften/Elements/JingleS5BTransportPayload.h @@ -21,5 +21,5 @@ namespace Swift { enum Mode { TCPMode, // default case - UDPMode, + UDPMode }; @@ -29,5 +29,5 @@ namespace Swift { AssistedType, TunnelType, - ProxyType, + ProxyType }; diff --git a/Swiften/Elements/Last.h b/Swiften/Elements/Last.h index fe0323a..cb7e0c6 100644 --- a/Swiften/Elements/Last.h +++ b/Swiften/Elements/Last.h @@ -12,5 +12,5 @@ namespace Swift { class Last : public Payload { public: - Last(int seconds = 0) : seconds_(seconds) {}; + Last(int seconds = 0) : seconds_(seconds) {} int getSeconds() const {return seconds_;} diff --git a/Swiften/Elements/MAMArchived.cpp b/Swiften/Elements/MAMArchived.cpp new file mode 100644 index 0000000..4ec5750 --- /dev/null +++ b/Swiften/Elements/MAMArchived.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/MAMArchived.h> + +using namespace Swift; + +MAMArchived::~MAMArchived() { +} diff --git a/Swiften/Elements/MAMArchived.h b/Swiften/Elements/MAMArchived.h new file mode 100644 index 0000000..df83427 --- /dev/null +++ b/Swiften/Elements/MAMArchived.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API MAMArchived : public Payload { + public: + virtual ~MAMArchived(); + + void setBy(const JID& by) { by_ = by; } + const JID& getBy() const { return by_; } + + void setID(const std::string& id) { id_ = id; } + const std::string& getID() const { return id_; } + + private: + JID by_; + std::string id_; + }; +} diff --git a/Swiften/Elements/MAMQuery.cpp b/Swiften/Elements/MAMQuery.cpp new file mode 100644 index 0000000..ff71bcc --- /dev/null +++ b/Swiften/Elements/MAMQuery.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/MAMQuery.h> + +using namespace Swift; + +MAMQuery::~MAMQuery() { +} diff --git a/Swiften/Elements/MAMQuery.h b/Swiften/Elements/MAMQuery.h new file mode 100644 index 0000000..3f3724e --- /dev/null +++ b/Swiften/Elements/MAMQuery.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/API.h> +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/ResultSet.h> + +namespace Swift { + class SWIFTEN_API MAMQuery : public Payload { + public: + virtual ~MAMQuery(); + + void setQueryID(const boost::optional<std::string>& queryID) { queryID_ = queryID; } + const boost::optional<std::string>& getQueryID() const { return queryID_; } + + void setForm(boost::shared_ptr<Form> form) { form_ = form; } + const boost::shared_ptr<Form>& getForm() const { return form_; } + + void setResultSet(boost::shared_ptr<ResultSet> resultSet) { resultSet_ = resultSet; } + const boost::shared_ptr<ResultSet>& getResultSet() const { return resultSet_; } + + private: + boost::optional<std::string> queryID_; + boost::shared_ptr<Form> form_; + boost::shared_ptr<ResultSet> resultSet_; + }; +} diff --git a/Swiften/Elements/MAMResult.cpp b/Swiften/Elements/MAMResult.cpp new file mode 100644 index 0000000..79913d3 --- /dev/null +++ b/Swiften/Elements/MAMResult.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/MAMResult.h> + +using namespace Swift; + +MAMResult::~MAMResult() { +} diff --git a/Swiften/Elements/MAMResult.h b/Swiften/Elements/MAMResult.h new file mode 100644 index 0000000..7d43902 --- /dev/null +++ b/Swiften/Elements/MAMResult.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/API.h> +#include <Swiften/Elements/ContainerPayload.h> +#include <Swiften/Elements/Forwarded.h> + +namespace Swift { + class SWIFTEN_API MAMResult : public ContainerPayload<Forwarded> { + public: + virtual ~MAMResult(); + + void setID(const std::string& id) { id_ = id; } + const std::string& getID() const { return id_; } + + void setQueryID(const boost::optional<std::string>& queryID) { queryID_ = queryID; } + const boost::optional<std::string>& getQueryID() const { return queryID_; } + + private: + std::string id_; + boost::optional<std::string> queryID_; + }; +} diff --git a/Swiften/Elements/MUCInvitationPayload.h b/Swiften/Elements/MUCInvitationPayload.h index ebae61a..290c585 100644 --- a/Swiften/Elements/MUCInvitationPayload.h +++ b/Swiften/Elements/MUCInvitationPayload.h @@ -16,5 +16,5 @@ namespace Swift { public: typedef boost::shared_ptr<MUCInvitationPayload> ref; - MUCInvitationPayload() : continuation_(false) { + MUCInvitationPayload() : continuation_(false), impromptu_(false) { } @@ -27,4 +27,12 @@ namespace Swift { } + void setIsImpromptu(bool b) { + impromptu_ = b; + } + + bool getIsImpromptu() const { + return impromptu_; + } + void setJID(const JID& jid) { jid_ = jid; @@ -61,4 +69,5 @@ namespace Swift { private: bool continuation_; + bool impromptu_; JID jid_; std::string password_; diff --git a/Swiften/Elements/MUCOccupant.h b/Swiften/Elements/MUCOccupant.h index 931f544..023643c 100644 --- a/Swiften/Elements/MUCOccupant.h +++ b/Swiften/Elements/MUCOccupant.h @@ -8,6 +8,7 @@ #include <boost/optional.hpp> - #include <string> + +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> @@ -15,5 +16,5 @@ namespace Swift { class Client; - class MUCOccupant { + class SWIFTEN_API MUCOccupant { public: enum Role {Moderator, Participant, Visitor, NoRole}; diff --git a/Swiften/Elements/Message.h b/Swiften/Elements/Message.h index 3b9145c..ea99814 100644 --- a/Swiften/Elements/Message.h +++ b/Swiften/Elements/Message.h @@ -39,6 +39,8 @@ namespace Swift { } + // Explicitly convert to bool. In C++11, it would be cleaner to + // compare to nullptr. bool hasSubject() { - return getPayload<Subject>(); + return static_cast<bool>(getPayload<Subject>()); } diff --git a/Swiften/Elements/Payload.h b/Swiften/Elements/Payload.h index f994ebc..7cc00da 100644 --- a/Swiften/Elements/Payload.h +++ b/Swiften/Elements/Payload.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,10 +9,17 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Element.h> + namespace Swift { - class Payload { + class SWIFTEN_API Payload : public Element { public: typedef boost::shared_ptr<Payload> ref; public: + Payload() {} + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(Payload) virtual ~Payload(); + + SWIFTEN_DEFAULT_COPY_ASSIGMNENT_OPERATOR(Payload) }; } diff --git a/Swiften/Elements/Presence.h b/Swiften/Elements/Presence.h index 28a9ee5..d16be2a 100644 --- a/Swiften/Elements/Presence.h +++ b/Swiften/Elements/Presence.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,9 +9,11 @@ #include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Stanza.h> #include <Swiften/Elements/StatusShow.h> + namespace Swift { - class Presence : public Stanza { + class SWIFTEN_API Presence : public Stanza { public: typedef boost::shared_ptr<Presence> ref; @@ -21,4 +23,5 @@ namespace Swift { Presence(); Presence(const std::string& status); + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(Presence) virtual ~Presence(); diff --git a/Swiften/Elements/PubSub.cpp b/Swiften/Elements/PubSub.cpp new file mode 100644 index 0000000..30a6376 --- /dev/null +++ b/Swiften/Elements/PubSub.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/PubSub.h> + +using namespace Swift; + +PubSub::PubSub() { +} + +PubSub::~PubSub() { +} diff --git a/Swiften/Elements/PubSub.h b/Swiften/Elements/PubSub.h new file mode 100644 index 0000000..cd8bf43 --- /dev/null +++ b/Swiften/Elements/PubSub.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ContainerPayload.h> + +#include <Swiften/Elements/PubSubPayload.h> + +namespace Swift { + class SWIFTEN_API PubSub : public ContainerPayload<PubSubPayload> { + public: + PubSub(); + virtual ~PubSub(); + }; +} diff --git a/Swiften/Elements/PubSubAffiliation.cpp b/Swiften/Elements/PubSubAffiliation.cpp new file mode 100644 index 0000000..aa8ab77 --- /dev/null +++ b/Swiften/Elements/PubSubAffiliation.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubAffiliation.h> + +using namespace Swift; + +PubSubAffiliation::PubSubAffiliation() : type(None) { +} + +PubSubAffiliation::~PubSubAffiliation() { +} diff --git a/Swiften/Elements/PubSubAffiliation.h b/Swiften/Elements/PubSubAffiliation.h new file mode 100644 index 0000000..6b9bc09 --- /dev/null +++ b/Swiften/Elements/PubSubAffiliation.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + + + +namespace Swift { + class SWIFTEN_API PubSubAffiliation : public Payload { + public: + enum Type { + None, + Member, + Outcast, + Owner, + Publisher, + PublishOnly + }; + + PubSubAffiliation(); + PubSubAffiliation(const std::string& node) : node(node), type(None) {} + virtual ~PubSubAffiliation(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + Type getType() const { + return type; + } + + void setType(Type value) { + this->type = value ; + } + + + private: + std::string node; + Type type; + }; +} diff --git a/Swiften/Elements/PubSubAffiliations.cpp b/Swiften/Elements/PubSubAffiliations.cpp new file mode 100644 index 0000000..d112f35 --- /dev/null +++ b/Swiften/Elements/PubSubAffiliations.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubAffiliations.h> + +using namespace Swift; + +PubSubAffiliations::PubSubAffiliations() { +} + +PubSubAffiliations::~PubSubAffiliations() { +} diff --git a/Swiften/Elements/PubSubAffiliations.h b/Swiften/Elements/PubSubAffiliations.h new file mode 100644 index 0000000..4a6d0f7 --- /dev/null +++ b/Swiften/Elements/PubSubAffiliations.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubAffiliation.h> +#include <Swiften/Elements/PubSubPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubAffiliations : public PubSubPayload { + public: + + PubSubAffiliations(); + + virtual ~PubSubAffiliations(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubAffiliation> >& getAffiliations() const { + return affiliations; + } + + void setAffiliations(const std::vector< boost::shared_ptr<PubSubAffiliation> >& value) { + this->affiliations = value ; + } + + void addAffiliation(boost::shared_ptr<PubSubAffiliation> value) { + this->affiliations.push_back(value); + } + + + private: + boost::optional< std::string > node; + std::vector< boost::shared_ptr<PubSubAffiliation> > affiliations; + }; +} diff --git a/Swiften/Elements/PubSubConfigure.cpp b/Swiften/Elements/PubSubConfigure.cpp new file mode 100644 index 0000000..0098ca6 --- /dev/null +++ b/Swiften/Elements/PubSubConfigure.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubConfigure.h> + +using namespace Swift; + +PubSubConfigure::PubSubConfigure() { +} + +PubSubConfigure::~PubSubConfigure() { +} diff --git a/Swiften/Elements/PubSubConfigure.h b/Swiften/Elements/PubSubConfigure.h new file mode 100644 index 0000000..84f5b82 --- /dev/null +++ b/Swiften/Elements/PubSubConfigure.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/Form.h> + +namespace Swift { + class SWIFTEN_API PubSubConfigure : public Payload { + public: + + PubSubConfigure(); + + virtual ~PubSubConfigure(); + + boost::shared_ptr<Form> getData() const { + return data; + } + + void setData(boost::shared_ptr<Form> value) { + this->data = value ; + } + + + private: + boost::shared_ptr<Form> data; + }; +} diff --git a/Swiften/Elements/PubSubCreate.cpp b/Swiften/Elements/PubSubCreate.cpp new file mode 100644 index 0000000..0ec3c38 --- /dev/null +++ b/Swiften/Elements/PubSubCreate.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubCreate.h> + +using namespace Swift; + +PubSubCreate::PubSubCreate() { +} + +PubSubCreate::~PubSubCreate() { +} diff --git a/Swiften/Elements/PubSubCreate.h b/Swiften/Elements/PubSubCreate.h new file mode 100644 index 0000000..f53fb9e --- /dev/null +++ b/Swiften/Elements/PubSubCreate.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/PubSubConfigure.h> +#include <Swiften/Elements/PubSubPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubCreate : public PubSubPayload { + public: + + PubSubCreate(); + PubSubCreate(const std::string& node) : node(node) {} + virtual ~PubSubCreate(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + boost::shared_ptr<PubSubConfigure> getConfigure() const { + return configure; + } + + void setConfigure(boost::shared_ptr<PubSubConfigure> value) { + this->configure = value ; + } + + + private: + std::string node; + boost::shared_ptr<PubSubConfigure> configure; + }; +} diff --git a/Swiften/Elements/PubSubDefault.cpp b/Swiften/Elements/PubSubDefault.cpp new file mode 100644 index 0000000..1ea5d2e3 --- /dev/null +++ b/Swiften/Elements/PubSubDefault.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubDefault.h> + +using namespace Swift; + +PubSubDefault::PubSubDefault() : type(None) { +} + +PubSubDefault::~PubSubDefault() { +} diff --git a/Swiften/Elements/PubSubDefault.h b/Swiften/Elements/PubSubDefault.h new file mode 100644 index 0000000..ef3117c --- /dev/null +++ b/Swiften/Elements/PubSubDefault.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <string> + +#include <Swiften/Elements/PubSubPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubDefault : public PubSubPayload { + public: + enum Type { + None, + Collection, + Leaf + }; + + PubSubDefault(); + + virtual ~PubSubDefault(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + Type getType() const { + return type; + } + + void setType(Type value) { + this->type = value ; + } + + + private: + boost::optional< std::string > node; + Type type; + }; +} diff --git a/Swiften/Elements/PubSubError.cpp b/Swiften/Elements/PubSubError.cpp new file mode 100644 index 0000000..db07972 --- /dev/null +++ b/Swiften/Elements/PubSubError.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/PubSubError.h> + +using namespace Swift; + +PubSubError::~PubSubError() { +} diff --git a/Swiften/Elements/PubSubError.h b/Swiften/Elements/PubSubError.h new file mode 100644 index 0000000..3748e44 --- /dev/null +++ b/Swiften/Elements/PubSubError.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API PubSubError : public Payload { + public: + enum Type { + UnknownType = 0, + ClosedNode, + ConfigurationRequired, + InvalidJID, + InvalidOptions, + InvalidPayload, + InvalidSubscriptionID, + ItemForbidden, + ItemRequired, + JIDRequired, + MaximumItemsExceeded, + MaximumNodesExceeded, + NodeIDRequired, + NotInRosterGroup, + NotSubscribed, + PayloadTooBig, + PayloadRequired, + PendingSubscription, + PresenceSubscriptionRequired, + SubscriptionIDRequired, + TooManySubscriptions, + Unsupported, + UnsupportedAccessModel + }; + + enum UnsupportedFeatureType { + UnknownUnsupportedFeatureType = 0, + AccessAuthorize, + AccessOpen, + AccessPresence, + AccessRoster, + AccessWhitelist, + AutoCreate, + AutoSubscribe, + Collections, + ConfigNode, + CreateAndConfigure, + CreateNodes, + DeleteItems, + DeleteNodes, + FilteredNotifications, + GetPending, + InstantNodes, + ItemIDs, + LastPublished, + LeasedSubscription, + ManageSubscriptions, + MemberAffiliation, + MetaData, + ModifyAffiliations, + MultiCollection, + MultiSubscribe, + OutcastAffiliation, + PersistentItems, + PresenceNotifications, + PresenceSubscribe, + Publish, + PublishOptions, + PublishOnlyAffiliation, + PublisherAffiliation, + PurgeNodes, + RetractItems, + RetrieveAffiliations, + RetrieveDefault, + RetrieveItems, + RetrieveSubscriptions, + Subscribe, + SubscriptionOptions, + SubscriptionNotifications + }; + + PubSubError(Type type = UnknownType) : type(type), unsupportedType(UnknownUnsupportedFeatureType) { + } + + virtual ~PubSubError(); + + Type getType() const { + return type; + } + + void setType(Type type) { + this->type = type; + } + + UnsupportedFeatureType getUnsupportedFeatureType() const { + return unsupportedType; + } + + void setUnsupportedFeatureType(UnsupportedFeatureType unsupportedType) { + this->unsupportedType = unsupportedType; + } + + private: + Type type; + UnsupportedFeatureType unsupportedType; + }; +} diff --git a/Swiften/Elements/PubSubEvent.cpp b/Swiften/Elements/PubSubEvent.cpp new file mode 100644 index 0000000..1b63134 --- /dev/null +++ b/Swiften/Elements/PubSubEvent.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/PubSubEvent.h> + +using namespace Swift; + +PubSubEvent::PubSubEvent() { +} + +PubSubEvent::~PubSubEvent() { +} diff --git a/Swiften/Elements/PubSubEvent.h b/Swiften/Elements/PubSubEvent.h new file mode 100644 index 0000000..9ef6d89 --- /dev/null +++ b/Swiften/Elements/PubSubEvent.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/ContainerPayload.h> +#include <Swiften/Elements/PubSubEventPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubEvent : public ContainerPayload<PubSubEventPayload> { + public: + PubSubEvent(); + virtual ~PubSubEvent(); + }; +} diff --git a/Swiften/Elements/PubSubEventAssociate.cpp b/Swiften/Elements/PubSubEventAssociate.cpp new file mode 100644 index 0000000..be1c35b --- /dev/null +++ b/Swiften/Elements/PubSubEventAssociate.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventAssociate.h> + +using namespace Swift; + +PubSubEventAssociate::PubSubEventAssociate() { +} + +PubSubEventAssociate::~PubSubEventAssociate() { +} diff --git a/Swiften/Elements/PubSubEventAssociate.h b/Swiften/Elements/PubSubEventAssociate.h new file mode 100644 index 0000000..be4f8f4 --- /dev/null +++ b/Swiften/Elements/PubSubEventAssociate.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + + + +namespace Swift { + class SWIFTEN_API PubSubEventAssociate : public Payload { + public: + + PubSubEventAssociate(); + + virtual ~PubSubEventAssociate(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + + private: + std::string node; + }; +} diff --git a/Swiften/Elements/PubSubEventCollection.cpp b/Swiften/Elements/PubSubEventCollection.cpp new file mode 100644 index 0000000..ca98be2 --- /dev/null +++ b/Swiften/Elements/PubSubEventCollection.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventCollection.h> + +using namespace Swift; + +PubSubEventCollection::PubSubEventCollection() { +} + +PubSubEventCollection::~PubSubEventCollection() { +} diff --git a/Swiften/Elements/PubSubEventCollection.h b/Swiften/Elements/PubSubEventCollection.h new file mode 100644 index 0000000..9c1d7cc --- /dev/null +++ b/Swiften/Elements/PubSubEventCollection.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/PubSubEventAssociate.h> +#include <Swiften/Elements/PubSubEventDisassociate.h> +#include <Swiften/Elements/PubSubEventPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubEventCollection : public PubSubEventPayload { + public: + + PubSubEventCollection(); + + virtual ~PubSubEventCollection(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + boost::shared_ptr<PubSubEventDisassociate> getDisassociate() const { + return disassociate; + } + + void setDisassociate(boost::shared_ptr<PubSubEventDisassociate> value) { + this->disassociate = value ; + } + + boost::shared_ptr<PubSubEventAssociate> getAssociate() const { + return associate; + } + + void setAssociate(boost::shared_ptr<PubSubEventAssociate> value) { + this->associate = value ; + } + + + private: + boost::optional< std::string > node; + boost::shared_ptr<PubSubEventDisassociate> disassociate; + boost::shared_ptr<PubSubEventAssociate> associate; + }; +} diff --git a/Swiften/Elements/PubSubEventConfiguration.cpp b/Swiften/Elements/PubSubEventConfiguration.cpp new file mode 100644 index 0000000..98c43ad --- /dev/null +++ b/Swiften/Elements/PubSubEventConfiguration.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventConfiguration.h> + +using namespace Swift; + +PubSubEventConfiguration::PubSubEventConfiguration() { +} + +PubSubEventConfiguration::~PubSubEventConfiguration() { +} diff --git a/Swiften/Elements/PubSubEventConfiguration.h b/Swiften/Elements/PubSubEventConfiguration.h new file mode 100644 index 0000000..4a2197e --- /dev/null +++ b/Swiften/Elements/PubSubEventConfiguration.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/PubSubEventPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubEventConfiguration : public PubSubEventPayload { + public: + + PubSubEventConfiguration(); + + virtual ~PubSubEventConfiguration(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + boost::shared_ptr<Form> getData() const { + return data; + } + + void setData(boost::shared_ptr<Form> value) { + this->data = value ; + } + + + private: + std::string node; + boost::shared_ptr<Form> data; + }; +} diff --git a/Swiften/Elements/PubSubEventDelete.cpp b/Swiften/Elements/PubSubEventDelete.cpp new file mode 100644 index 0000000..35c4569 --- /dev/null +++ b/Swiften/Elements/PubSubEventDelete.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventDelete.h> + +using namespace Swift; + +PubSubEventDelete::PubSubEventDelete() { +} + +PubSubEventDelete::~PubSubEventDelete() { +} diff --git a/Swiften/Elements/PubSubEventDelete.h b/Swiften/Elements/PubSubEventDelete.h new file mode 100644 index 0000000..3c27c82 --- /dev/null +++ b/Swiften/Elements/PubSubEventDelete.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/PubSubEventPayload.h> +#include <Swiften/Elements/PubSubEventRedirect.h> + +namespace Swift { + class SWIFTEN_API PubSubEventDelete : public PubSubEventPayload { + public: + + PubSubEventDelete(); + + virtual ~PubSubEventDelete(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + boost::shared_ptr<PubSubEventRedirect> getRedirects() const { + return redirects; + } + + void setRedirects(boost::shared_ptr<PubSubEventRedirect> value) { + this->redirects = value ; + } + + + private: + std::string node; + boost::shared_ptr<PubSubEventRedirect> redirects; + }; +} diff --git a/Swiften/Elements/PubSubEventDisassociate.cpp b/Swiften/Elements/PubSubEventDisassociate.cpp new file mode 100644 index 0000000..7060345 --- /dev/null +++ b/Swiften/Elements/PubSubEventDisassociate.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventDisassociate.h> + +using namespace Swift; + +PubSubEventDisassociate::PubSubEventDisassociate() { +} + +PubSubEventDisassociate::~PubSubEventDisassociate() { +} diff --git a/Swiften/Elements/PubSubEventDisassociate.h b/Swiften/Elements/PubSubEventDisassociate.h new file mode 100644 index 0000000..22a971f --- /dev/null +++ b/Swiften/Elements/PubSubEventDisassociate.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + + + +namespace Swift { + class SWIFTEN_API PubSubEventDisassociate : public Payload { + public: + + PubSubEventDisassociate(); + + virtual ~PubSubEventDisassociate(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + + private: + std::string node; + }; +} diff --git a/Swiften/Elements/PubSubEventItem.cpp b/Swiften/Elements/PubSubEventItem.cpp new file mode 100644 index 0000000..0922f60 --- /dev/null +++ b/Swiften/Elements/PubSubEventItem.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventItem.h> + +using namespace Swift; + +PubSubEventItem::PubSubEventItem() { +} + +PubSubEventItem::~PubSubEventItem() { +} diff --git a/Swiften/Elements/PubSubEventItem.h b/Swiften/Elements/PubSubEventItem.h new file mode 100644 index 0000000..b25a79f --- /dev/null +++ b/Swiften/Elements/PubSubEventItem.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API PubSubEventItem : public Payload { + public: + + PubSubEventItem(); + + virtual ~PubSubEventItem(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + const boost::optional< std::string >& getPublisher() const { + return publisher; + } + + void setPublisher(const boost::optional< std::string >& value) { + this->publisher = value ; + } + + const std::vector< boost::shared_ptr<Payload> >& getData() const { + return data; + } + + void setData(const std::vector< boost::shared_ptr<Payload> >& value) { + this->data = value ; + } + + void addData(boost::shared_ptr<Payload> value) { + this->data.push_back(value); + } + + const boost::optional< std::string >& getID() const { + return id; + } + + void setID(const boost::optional< std::string >& value) { + this->id = value ; + } + + + private: + boost::optional< std::string > node; + boost::optional< std::string > publisher; + std::vector< boost::shared_ptr<Payload> > data; + boost::optional< std::string > id; + }; +} diff --git a/Swiften/Elements/PubSubEventItems.cpp b/Swiften/Elements/PubSubEventItems.cpp new file mode 100644 index 0000000..624c844 --- /dev/null +++ b/Swiften/Elements/PubSubEventItems.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventItems.h> + +using namespace Swift; + +PubSubEventItems::PubSubEventItems() { +} + +PubSubEventItems::~PubSubEventItems() { +} diff --git a/Swiften/Elements/PubSubEventItems.h b/Swiften/Elements/PubSubEventItems.h new file mode 100644 index 0000000..78b2ef0 --- /dev/null +++ b/Swiften/Elements/PubSubEventItems.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubEventItem.h> +#include <Swiften/Elements/PubSubEventPayload.h> +#include <Swiften/Elements/PubSubEventRetract.h> + +namespace Swift { + class SWIFTEN_API PubSubEventItems : public PubSubEventPayload { + public: + + PubSubEventItems(); + + virtual ~PubSubEventItems(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubEventItem> >& getItems() const { + return items; + } + + void setItems(const std::vector< boost::shared_ptr<PubSubEventItem> >& value) { + this->items = value ; + } + + void addItem(boost::shared_ptr<PubSubEventItem> value) { + this->items.push_back(value); + } + + const std::vector< boost::shared_ptr<PubSubEventRetract> >& getRetracts() const { + return retracts; + } + + void setRetracts(const std::vector< boost::shared_ptr<PubSubEventRetract> >& value) { + this->retracts = value ; + } + + void addRetract(boost::shared_ptr<PubSubEventRetract> value) { + this->retracts.push_back(value); + } + + + private: + std::string node; + std::vector< boost::shared_ptr<PubSubEventItem> > items; + std::vector< boost::shared_ptr<PubSubEventRetract> > retracts; + }; +} diff --git a/Swiften/Elements/PubSubEventPayload.cpp b/Swiften/Elements/PubSubEventPayload.cpp new file mode 100644 index 0000000..0019942 --- /dev/null +++ b/Swiften/Elements/PubSubEventPayload.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/PubSubEventPayload.h> + +using namespace Swift; + +PubSubEventPayload::~PubSubEventPayload() { +} diff --git a/Swiften/Elements/PubSubEventPayload.h b/Swiften/Elements/PubSubEventPayload.h new file mode 100644 index 0000000..81fb9a8 --- /dev/null +++ b/Swiften/Elements/PubSubEventPayload.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API PubSubEventPayload : public Payload { + public: + virtual ~PubSubEventPayload(); + }; +} diff --git a/Swiften/Elements/PubSubEventPurge.cpp b/Swiften/Elements/PubSubEventPurge.cpp new file mode 100644 index 0000000..3a62486 --- /dev/null +++ b/Swiften/Elements/PubSubEventPurge.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventPurge.h> + +using namespace Swift; + +PubSubEventPurge::PubSubEventPurge() { +} + +PubSubEventPurge::~PubSubEventPurge() { +} diff --git a/Swiften/Elements/PubSubEventPurge.h b/Swiften/Elements/PubSubEventPurge.h new file mode 100644 index 0000000..bd1eaf8 --- /dev/null +++ b/Swiften/Elements/PubSubEventPurge.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + +#include <Swiften/Elements/PubSubEventPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubEventPurge : public PubSubEventPayload { + public: + + PubSubEventPurge(); + + virtual ~PubSubEventPurge(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + + private: + std::string node; + }; +} diff --git a/Swiften/Elements/PubSubEventRedirect.cpp b/Swiften/Elements/PubSubEventRedirect.cpp new file mode 100644 index 0000000..6c54371 --- /dev/null +++ b/Swiften/Elements/PubSubEventRedirect.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventRedirect.h> + +using namespace Swift; + +PubSubEventRedirect::PubSubEventRedirect() { +} + +PubSubEventRedirect::~PubSubEventRedirect() { +} diff --git a/Swiften/Elements/PubSubEventRedirect.h b/Swiften/Elements/PubSubEventRedirect.h new file mode 100644 index 0000000..22d30b8 --- /dev/null +++ b/Swiften/Elements/PubSubEventRedirect.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + + + +namespace Swift { + class SWIFTEN_API PubSubEventRedirect : public Payload { + public: + + PubSubEventRedirect(); + + virtual ~PubSubEventRedirect(); + + const std::string& getURI() const { + return uri; + } + + void setURI(const std::string& value) { + this->uri = value ; + } + + + private: + std::string uri; + }; +} diff --git a/Swiften/Elements/PubSubEventRetract.cpp b/Swiften/Elements/PubSubEventRetract.cpp new file mode 100644 index 0000000..be28264 --- /dev/null +++ b/Swiften/Elements/PubSubEventRetract.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventRetract.h> + +using namespace Swift; + +PubSubEventRetract::PubSubEventRetract() { +} + +PubSubEventRetract::~PubSubEventRetract() { +} diff --git a/Swiften/Elements/PubSubEventRetract.h b/Swiften/Elements/PubSubEventRetract.h new file mode 100644 index 0000000..075b48c --- /dev/null +++ b/Swiften/Elements/PubSubEventRetract.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + + + +namespace Swift { + class SWIFTEN_API PubSubEventRetract : public Payload { + public: + + PubSubEventRetract(); + + virtual ~PubSubEventRetract(); + + const std::string& getID() const { + return id; + } + + void setID(const std::string& value) { + this->id = value ; + } + + + private: + std::string id; + }; +} diff --git a/Swiften/Elements/PubSubEventSubscription.cpp b/Swiften/Elements/PubSubEventSubscription.cpp new file mode 100644 index 0000000..5943c32 --- /dev/null +++ b/Swiften/Elements/PubSubEventSubscription.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubEventSubscription.h> + +using namespace Swift; + +PubSubEventSubscription::PubSubEventSubscription() : subscription(None) { +} + +PubSubEventSubscription::~PubSubEventSubscription() { +} diff --git a/Swiften/Elements/PubSubEventSubscription.h b/Swiften/Elements/PubSubEventSubscription.h new file mode 100644 index 0000000..8d681b7 --- /dev/null +++ b/Swiften/Elements/PubSubEventSubscription.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <boost/optional.hpp> +#include <string> + +#include <Swiften/Elements/PubSubEventPayload.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API PubSubEventSubscription : public PubSubEventPayload { + public: + enum SubscriptionType { + None, + Pending, + Subscribed, + Unconfigured + }; + + PubSubEventSubscription(); + + virtual ~PubSubEventSubscription(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& value) { + this->jid = value ; + } + + SubscriptionType getSubscription() const { + return subscription; + } + + void setSubscription(SubscriptionType value) { + this->subscription = value ; + } + + const boost::optional< std::string >& getSubscriptionID() const { + return subscriptionID; + } + + void setSubscriptionID(const boost::optional< std::string >& value) { + this->subscriptionID = value ; + } + + const boost::posix_time::ptime& getExpiry() const { + return expiry; + } + + void setExpiry(const boost::posix_time::ptime& value) { + this->expiry = value ; + } + + + private: + std::string node; + JID jid; + SubscriptionType subscription; + boost::optional< std::string > subscriptionID; + boost::posix_time::ptime expiry; + }; +} diff --git a/Swiften/Elements/PubSubItem.cpp b/Swiften/Elements/PubSubItem.cpp new file mode 100644 index 0000000..c6cae54 --- /dev/null +++ b/Swiften/Elements/PubSubItem.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubItem.h> + +using namespace Swift; + +PubSubItem::PubSubItem() { +} + +PubSubItem::~PubSubItem() { +} diff --git a/Swiften/Elements/PubSubItem.h b/Swiften/Elements/PubSubItem.h new file mode 100644 index 0000000..7d65904 --- /dev/null +++ b/Swiften/Elements/PubSubItem.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API PubSubItem : public Payload { + public: + + PubSubItem(); + + virtual ~PubSubItem(); + + const std::vector< boost::shared_ptr<Payload> >& getData() const { + return data; + } + + void setData(const std::vector< boost::shared_ptr<Payload> >& value) { + this->data = value ; + } + + void addData(boost::shared_ptr<Payload> value) { + this->data.push_back(value); + } + + const std::string& getID() const { + return id; + } + + void setID(const std::string& value) { + this->id = value ; + } + + + private: + std::vector< boost::shared_ptr<Payload> > data; + std::string id; + }; +} diff --git a/Swiften/Elements/PubSubItems.cpp b/Swiften/Elements/PubSubItems.cpp new file mode 100644 index 0000000..966b8d6 --- /dev/null +++ b/Swiften/Elements/PubSubItems.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubItems.h> + +using namespace Swift; + +PubSubItems::PubSubItems() { +} + +PubSubItems::~PubSubItems() { +} diff --git a/Swiften/Elements/PubSubItems.h b/Swiften/Elements/PubSubItems.h new file mode 100644 index 0000000..f2147ef --- /dev/null +++ b/Swiften/Elements/PubSubItems.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubItem.h> +#include <Swiften/Elements/PubSubPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubItems : public PubSubPayload { + public: + + PubSubItems(); + PubSubItems(const std::string& node) : node(node) {} + virtual ~PubSubItems(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubItem> >& getItems() const { + return items; + } + + void setItems(const std::vector< boost::shared_ptr<PubSubItem> >& value) { + this->items = value ; + } + + void addItem(boost::shared_ptr<PubSubItem> value) { + this->items.push_back(value); + } + + const boost::optional< unsigned int >& getMaximumItems() const { + return maximumItems; + } + + void setMaximumItems(const boost::optional< unsigned int >& value) { + this->maximumItems = value ; + } + + const boost::optional< std::string >& getSubscriptionID() const { + return subscriptionID; + } + + void setSubscriptionID(const boost::optional< std::string >& value) { + this->subscriptionID = value ; + } + + + private: + std::string node; + std::vector< boost::shared_ptr<PubSubItem> > items; + boost::optional< unsigned int > maximumItems; + boost::optional< std::string > subscriptionID; + }; +} diff --git a/Swiften/Elements/PubSubOptions.cpp b/Swiften/Elements/PubSubOptions.cpp new file mode 100644 index 0000000..a72ff5d --- /dev/null +++ b/Swiften/Elements/PubSubOptions.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOptions.h> + +using namespace Swift; + +PubSubOptions::PubSubOptions() { +} + +PubSubOptions::~PubSubOptions() { +} diff --git a/Swiften/Elements/PubSubOptions.h b/Swiften/Elements/PubSubOptions.h new file mode 100644 index 0000000..0f47c26 --- /dev/null +++ b/Swiften/Elements/PubSubOptions.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/PubSubPayload.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API PubSubOptions : public PubSubPayload { + public: + + PubSubOptions(); + + virtual ~PubSubOptions(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& value) { + this->jid = value ; + } + + boost::shared_ptr<Form> getData() const { + return data; + } + + void setData(boost::shared_ptr<Form> value) { + this->data = value ; + } + + const boost::optional< std::string >& getSubscriptionID() const { + return subscriptionID; + } + + void setSubscriptionID(const boost::optional< std::string >& value) { + this->subscriptionID = value ; + } + + + private: + std::string node; + JID jid; + boost::shared_ptr<Form> data; + boost::optional< std::string > subscriptionID; + }; +} diff --git a/Swiften/Elements/PubSubOwnerAffiliation.cpp b/Swiften/Elements/PubSubOwnerAffiliation.cpp new file mode 100644 index 0000000..12c871d --- /dev/null +++ b/Swiften/Elements/PubSubOwnerAffiliation.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerAffiliation.h> + +using namespace Swift; + +PubSubOwnerAffiliation::PubSubOwnerAffiliation() : type(None) { +} + +PubSubOwnerAffiliation::~PubSubOwnerAffiliation() { +} diff --git a/Swiften/Elements/PubSubOwnerAffiliation.h b/Swiften/Elements/PubSubOwnerAffiliation.h new file mode 100644 index 0000000..67853f7 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerAffiliation.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + + +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerAffiliation : public Payload { + public: + enum Type { + None, + Member, + Outcast, + Owner, + Publisher, + PublishOnly + }; + + PubSubOwnerAffiliation(); + + virtual ~PubSubOwnerAffiliation(); + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& value) { + this->jid = value ; + } + + Type getType() const { + return type; + } + + void setType(Type value) { + this->type = value ; + } + + + private: + JID jid; + Type type; + }; +} diff --git a/Swiften/Elements/PubSubOwnerAffiliations.cpp b/Swiften/Elements/PubSubOwnerAffiliations.cpp new file mode 100644 index 0000000..7093298 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerAffiliations.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerAffiliations.h> + +using namespace Swift; + +PubSubOwnerAffiliations::PubSubOwnerAffiliations() { +} + +PubSubOwnerAffiliations::~PubSubOwnerAffiliations() { +} diff --git a/Swiften/Elements/PubSubOwnerAffiliations.h b/Swiften/Elements/PubSubOwnerAffiliations.h new file mode 100644 index 0000000..4aeb278 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerAffiliations.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubOwnerAffiliation.h> +#include <Swiften/Elements/PubSubOwnerPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerAffiliations : public PubSubOwnerPayload { + public: + + PubSubOwnerAffiliations(); + + virtual ~PubSubOwnerAffiliations(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubOwnerAffiliation> >& getAffiliations() const { + return affiliations; + } + + void setAffiliations(const std::vector< boost::shared_ptr<PubSubOwnerAffiliation> >& value) { + this->affiliations = value ; + } + + void addAffiliation(boost::shared_ptr<PubSubOwnerAffiliation> value) { + this->affiliations.push_back(value); + } + + + private: + std::string node; + std::vector< boost::shared_ptr<PubSubOwnerAffiliation> > affiliations; + }; +} diff --git a/Swiften/Elements/PubSubOwnerConfigure.cpp b/Swiften/Elements/PubSubOwnerConfigure.cpp new file mode 100644 index 0000000..57405fa --- /dev/null +++ b/Swiften/Elements/PubSubOwnerConfigure.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerConfigure.h> + +using namespace Swift; + +PubSubOwnerConfigure::PubSubOwnerConfigure() { +} + +PubSubOwnerConfigure::~PubSubOwnerConfigure() { +} diff --git a/Swiften/Elements/PubSubOwnerConfigure.h b/Swiften/Elements/PubSubOwnerConfigure.h new file mode 100644 index 0000000..5dae983 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerConfigure.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/PubSubOwnerPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerConfigure : public PubSubOwnerPayload { + public: + + PubSubOwnerConfigure(); + PubSubOwnerConfigure(const std::string& node) : node(node) {} + virtual ~PubSubOwnerConfigure(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + boost::shared_ptr<Form> getData() const { + return data; + } + + void setData(boost::shared_ptr<Form> value) { + this->data = value ; + } + + + private: + boost::optional< std::string > node; + boost::shared_ptr<Form> data; + }; +} diff --git a/Swiften/Elements/PubSubOwnerDefault.cpp b/Swiften/Elements/PubSubOwnerDefault.cpp new file mode 100644 index 0000000..7aad448 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerDefault.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerDefault.h> + +using namespace Swift; + +PubSubOwnerDefault::PubSubOwnerDefault() { +} + +PubSubOwnerDefault::~PubSubOwnerDefault() { +} diff --git a/Swiften/Elements/PubSubOwnerDefault.h b/Swiften/Elements/PubSubOwnerDefault.h new file mode 100644 index 0000000..2133dff --- /dev/null +++ b/Swiften/Elements/PubSubOwnerDefault.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/PubSubOwnerPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerDefault : public PubSubOwnerPayload { + public: + + PubSubOwnerDefault(); + + virtual ~PubSubOwnerDefault(); + + boost::shared_ptr<Form> getData() const { + return data; + } + + void setData(boost::shared_ptr<Form> value) { + this->data = value ; + } + + + private: + boost::shared_ptr<Form> data; + }; +} diff --git a/Swiften/Elements/PubSubOwnerDelete.cpp b/Swiften/Elements/PubSubOwnerDelete.cpp new file mode 100644 index 0000000..8659611 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerDelete.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerDelete.h> + +using namespace Swift; + +PubSubOwnerDelete::PubSubOwnerDelete() { +} + +PubSubOwnerDelete::~PubSubOwnerDelete() { +} diff --git a/Swiften/Elements/PubSubOwnerDelete.h b/Swiften/Elements/PubSubOwnerDelete.h new file mode 100644 index 0000000..f15e363 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerDelete.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/PubSubOwnerPayload.h> +#include <Swiften/Elements/PubSubOwnerRedirect.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerDelete : public PubSubOwnerPayload { + public: + + PubSubOwnerDelete(); + PubSubOwnerDelete(const std::string& node) : node(node) {} + virtual ~PubSubOwnerDelete(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + boost::shared_ptr<PubSubOwnerRedirect> getRedirect() const { + return redirect; + } + + void setRedirect(boost::shared_ptr<PubSubOwnerRedirect> value) { + this->redirect = value ; + } + + + private: + std::string node; + boost::shared_ptr<PubSubOwnerRedirect> redirect; + }; +} diff --git a/Swiften/Elements/PubSubOwnerPayload.cpp b/Swiften/Elements/PubSubOwnerPayload.cpp new file mode 100644 index 0000000..92c1dd2 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerPayload.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/PubSubOwnerPayload.h> + +using namespace Swift; + +PubSubOwnerPayload::~PubSubOwnerPayload() { +} diff --git a/Swiften/Elements/PubSubOwnerPayload.h b/Swiften/Elements/PubSubOwnerPayload.h new file mode 100644 index 0000000..a2ddaaa --- /dev/null +++ b/Swiften/Elements/PubSubOwnerPayload.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerPayload : public Payload { + public: + virtual ~PubSubOwnerPayload(); + }; +} diff --git a/Swiften/Elements/PubSubOwnerPubSub.cpp b/Swiften/Elements/PubSubOwnerPubSub.cpp new file mode 100644 index 0000000..022452d --- /dev/null +++ b/Swiften/Elements/PubSubOwnerPubSub.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/PubSubOwnerPubSub.h> + +using namespace Swift; + +PubSubOwnerPubSub::PubSubOwnerPubSub() { +} + +PubSubOwnerPubSub::~PubSubOwnerPubSub() { +} diff --git a/Swiften/Elements/PubSubOwnerPubSub.h b/Swiften/Elements/PubSubOwnerPubSub.h new file mode 100644 index 0000000..dd72abe --- /dev/null +++ b/Swiften/Elements/PubSubOwnerPubSub.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ContainerPayload.h> + +#include <Swiften/Elements/PubSubOwnerPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerPubSub : public ContainerPayload<PubSubOwnerPayload> { + public: + PubSubOwnerPubSub(); + virtual ~PubSubOwnerPubSub(); + }; +} diff --git a/Swiften/Elements/PubSubOwnerPurge.cpp b/Swiften/Elements/PubSubOwnerPurge.cpp new file mode 100644 index 0000000..6331cf2 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerPurge.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerPurge.h> + +using namespace Swift; + +PubSubOwnerPurge::PubSubOwnerPurge() { +} + +PubSubOwnerPurge::~PubSubOwnerPurge() { +} diff --git a/Swiften/Elements/PubSubOwnerPurge.h b/Swiften/Elements/PubSubOwnerPurge.h new file mode 100644 index 0000000..05dfb63 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerPurge.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + +#include <Swiften/Elements/PubSubOwnerPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerPurge : public PubSubOwnerPayload { + public: + + PubSubOwnerPurge(); + + virtual ~PubSubOwnerPurge(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + + private: + std::string node; + }; +} diff --git a/Swiften/Elements/PubSubOwnerRedirect.cpp b/Swiften/Elements/PubSubOwnerRedirect.cpp new file mode 100644 index 0000000..75e9819 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerRedirect.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerRedirect.h> + +using namespace Swift; + +PubSubOwnerRedirect::PubSubOwnerRedirect() { +} + +PubSubOwnerRedirect::~PubSubOwnerRedirect() { +} diff --git a/Swiften/Elements/PubSubOwnerRedirect.h b/Swiften/Elements/PubSubOwnerRedirect.h new file mode 100644 index 0000000..50ba66f --- /dev/null +++ b/Swiften/Elements/PubSubOwnerRedirect.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> + + + +namespace Swift { + class SWIFTEN_API PubSubOwnerRedirect : public Payload { + public: + + PubSubOwnerRedirect(); + + virtual ~PubSubOwnerRedirect(); + + const std::string& getURI() const { + return uri; + } + + void setURI(const std::string& value) { + this->uri = value ; + } + + + private: + std::string uri; + }; +} diff --git a/Swiften/Elements/PubSubOwnerSubscription.cpp b/Swiften/Elements/PubSubOwnerSubscription.cpp new file mode 100644 index 0000000..0e83951 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerSubscription.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerSubscription.h> + +using namespace Swift; + +PubSubOwnerSubscription::PubSubOwnerSubscription() : subscription(None) { +} + +PubSubOwnerSubscription::~PubSubOwnerSubscription() { +} diff --git a/Swiften/Elements/PubSubOwnerSubscription.h b/Swiften/Elements/PubSubOwnerSubscription.h new file mode 100644 index 0000000..7ba5e3a --- /dev/null +++ b/Swiften/Elements/PubSubOwnerSubscription.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + + +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerSubscription : public Payload { + public: + enum SubscriptionType { + None, + Pending, + Subscribed, + Unconfigured + }; + + PubSubOwnerSubscription(); + + virtual ~PubSubOwnerSubscription(); + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& value) { + this->jid = value ; + } + + SubscriptionType getSubscription() const { + return subscription; + } + + void setSubscription(SubscriptionType value) { + this->subscription = value ; + } + + + private: + JID jid; + SubscriptionType subscription; + }; +} diff --git a/Swiften/Elements/PubSubOwnerSubscriptions.cpp b/Swiften/Elements/PubSubOwnerSubscriptions.cpp new file mode 100644 index 0000000..02a1f34 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerSubscriptions.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubOwnerSubscriptions.h> + +using namespace Swift; + +PubSubOwnerSubscriptions::PubSubOwnerSubscriptions() { +} + +PubSubOwnerSubscriptions::~PubSubOwnerSubscriptions() { +} diff --git a/Swiften/Elements/PubSubOwnerSubscriptions.h b/Swiften/Elements/PubSubOwnerSubscriptions.h new file mode 100644 index 0000000..ea64517 --- /dev/null +++ b/Swiften/Elements/PubSubOwnerSubscriptions.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubOwnerPayload.h> +#include <Swiften/Elements/PubSubOwnerSubscription.h> + +namespace Swift { + class SWIFTEN_API PubSubOwnerSubscriptions : public PubSubOwnerPayload { + public: + + PubSubOwnerSubscriptions(); + + virtual ~PubSubOwnerSubscriptions(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubOwnerSubscription> >& getSubscriptions() const { + return subscriptions; + } + + void setSubscriptions(const std::vector< boost::shared_ptr<PubSubOwnerSubscription> >& value) { + this->subscriptions = value ; + } + + void addSubscription(boost::shared_ptr<PubSubOwnerSubscription> value) { + this->subscriptions.push_back(value); + } + + + private: + std::string node; + std::vector< boost::shared_ptr<PubSubOwnerSubscription> > subscriptions; + }; +} diff --git a/Swiften/Elements/PubSubPayload.cpp b/Swiften/Elements/PubSubPayload.cpp new file mode 100644 index 0000000..b529959 --- /dev/null +++ b/Swiften/Elements/PubSubPayload.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/PubSubPayload.h> + +using namespace Swift; + +PubSubPayload::~PubSubPayload() { +} diff --git a/Swiften/Elements/PubSubPayload.h b/Swiften/Elements/PubSubPayload.h new file mode 100644 index 0000000..476939b --- /dev/null +++ b/Swiften/Elements/PubSubPayload.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API PubSubPayload : public Payload { + public: + virtual ~PubSubPayload(); + }; +} diff --git a/Swiften/Elements/PubSubPublish.cpp b/Swiften/Elements/PubSubPublish.cpp new file mode 100644 index 0000000..90cf6bb --- /dev/null +++ b/Swiften/Elements/PubSubPublish.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubPublish.h> + +using namespace Swift; + +PubSubPublish::PubSubPublish() { +} + +PubSubPublish::~PubSubPublish() { +} diff --git a/Swiften/Elements/PubSubPublish.h b/Swiften/Elements/PubSubPublish.h new file mode 100644 index 0000000..916ed05 --- /dev/null +++ b/Swiften/Elements/PubSubPublish.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubItem.h> +#include <Swiften/Elements/PubSubPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubPublish : public PubSubPayload { + public: + + PubSubPublish(); + + virtual ~PubSubPublish(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubItem> >& getItems() const { + return items; + } + + void setItems(const std::vector< boost::shared_ptr<PubSubItem> >& value) { + this->items = value ; + } + + void addItem(boost::shared_ptr<PubSubItem> value) { + this->items.push_back(value); + } + + + private: + std::string node; + std::vector< boost::shared_ptr<PubSubItem> > items; + }; +} diff --git a/Swiften/Elements/PubSubRetract.cpp b/Swiften/Elements/PubSubRetract.cpp new file mode 100644 index 0000000..41b9346 --- /dev/null +++ b/Swiften/Elements/PubSubRetract.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubRetract.h> + +using namespace Swift; + +PubSubRetract::PubSubRetract() : notify(false) { +} + +PubSubRetract::~PubSubRetract() { +} diff --git a/Swiften/Elements/PubSubRetract.h b/Swiften/Elements/PubSubRetract.h new file mode 100644 index 0000000..13fa594 --- /dev/null +++ b/Swiften/Elements/PubSubRetract.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubItem.h> +#include <Swiften/Elements/PubSubPayload.h> + +namespace Swift { + class SWIFTEN_API PubSubRetract : public PubSubPayload { + public: + + PubSubRetract(); + + virtual ~PubSubRetract(); + + const std::string& getNode() const { + return node; + } + + void setNode(const std::string& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubItem> >& getItems() const { + return items; + } + + void setItems(const std::vector< boost::shared_ptr<PubSubItem> >& value) { + this->items = value ; + } + + void addItem(boost::shared_ptr<PubSubItem> value) { + this->items.push_back(value); + } + + bool isNotify() const { + return notify; + } + + void setNotify(bool value) { + this->notify = value ; + } + + + private: + std::string node; + std::vector< boost::shared_ptr<PubSubItem> > items; + bool notify; + }; +} diff --git a/Swiften/Elements/PubSubSubscribe.cpp b/Swiften/Elements/PubSubSubscribe.cpp new file mode 100644 index 0000000..0d13525 --- /dev/null +++ b/Swiften/Elements/PubSubSubscribe.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubSubscribe.h> + +using namespace Swift; + +PubSubSubscribe::PubSubSubscribe() { +} + +PubSubSubscribe::~PubSubSubscribe() { +} diff --git a/Swiften/Elements/PubSubSubscribe.h b/Swiften/Elements/PubSubSubscribe.h new file mode 100644 index 0000000..93eb3a5 --- /dev/null +++ b/Swiften/Elements/PubSubSubscribe.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/PubSubOptions.h> +#include <Swiften/Elements/PubSubPayload.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API PubSubSubscribe : public PubSubPayload { + public: + + PubSubSubscribe(); + + virtual ~PubSubSubscribe(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& value) { + this->jid = value ; + } + + boost::shared_ptr<PubSubOptions> getOptions() const { + return options; + } + + void setOptions(boost::shared_ptr<PubSubOptions> value) { + this->options = value ; + } + + + private: + boost::optional< std::string > node; + JID jid; + boost::shared_ptr<PubSubOptions> options; + }; +} diff --git a/Swiften/Elements/PubSubSubscribeOptions.cpp b/Swiften/Elements/PubSubSubscribeOptions.cpp new file mode 100644 index 0000000..19cf084 --- /dev/null +++ b/Swiften/Elements/PubSubSubscribeOptions.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubSubscribeOptions.h> + +using namespace Swift; + +PubSubSubscribeOptions::PubSubSubscribeOptions() : required(false) { +} + +PubSubSubscribeOptions::~PubSubSubscribeOptions() { +} diff --git a/Swiften/Elements/PubSubSubscribeOptions.h b/Swiften/Elements/PubSubSubscribeOptions.h new file mode 100644 index 0000000..9801136 --- /dev/null +++ b/Swiften/Elements/PubSubSubscribeOptions.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> + + + + +namespace Swift { + class SWIFTEN_API PubSubSubscribeOptions : public Payload { + public: + + PubSubSubscribeOptions(); + + virtual ~PubSubSubscribeOptions(); + + bool isRequired() const { + return required; + } + + void setRequired(bool value) { + this->required = value ; + } + + + private: + bool required; + }; +} diff --git a/Swiften/Elements/PubSubSubscription.cpp b/Swiften/Elements/PubSubSubscription.cpp new file mode 100644 index 0000000..8d6d2d7 --- /dev/null +++ b/Swiften/Elements/PubSubSubscription.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubSubscription.h> + +using namespace Swift; + +PubSubSubscription::PubSubSubscription() : subscription(None) { +} + +PubSubSubscription::~PubSubSubscription() { +} diff --git a/Swiften/Elements/PubSubSubscription.h b/Swiften/Elements/PubSubSubscription.h new file mode 100644 index 0000000..07a85ec --- /dev/null +++ b/Swiften/Elements/PubSubSubscription.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/PubSubPayload.h> +#include <Swiften/Elements/PubSubSubscribeOptions.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API PubSubSubscription : public PubSubPayload { + public: + enum SubscriptionType { + None, + Pending, + Subscribed, + Unconfigured + }; + + PubSubSubscription(); + + virtual ~PubSubSubscription(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + const boost::optional< std::string >& getSubscriptionID() const { + return subscriptionID; + } + + void setSubscriptionID(const boost::optional< std::string >& value) { + this->subscriptionID = value ; + } + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& value) { + this->jid = value ; + } + + boost::shared_ptr<PubSubSubscribeOptions> getOptions() const { + return options; + } + + void setOptions(boost::shared_ptr<PubSubSubscribeOptions> value) { + this->options = value ; + } + + SubscriptionType getSubscription() const { + return subscription; + } + + void setSubscription(SubscriptionType value) { + this->subscription = value ; + } + + + private: + boost::optional< std::string > node; + boost::optional< std::string > subscriptionID; + JID jid; + boost::shared_ptr<PubSubSubscribeOptions> options; + SubscriptionType subscription; + }; +} diff --git a/Swiften/Elements/PubSubSubscriptions.cpp b/Swiften/Elements/PubSubSubscriptions.cpp new file mode 100644 index 0000000..895f1b6 --- /dev/null +++ b/Swiften/Elements/PubSubSubscriptions.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubSubscriptions.h> + +using namespace Swift; + +PubSubSubscriptions::PubSubSubscriptions() { +} + +PubSubSubscriptions::~PubSubSubscriptions() { +} diff --git a/Swiften/Elements/PubSubSubscriptions.h b/Swiften/Elements/PubSubSubscriptions.h new file mode 100644 index 0000000..a5e8b14 --- /dev/null +++ b/Swiften/Elements/PubSubSubscriptions.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/Elements/PubSubPayload.h> +#include <Swiften/Elements/PubSubSubscription.h> + +namespace Swift { + class SWIFTEN_API PubSubSubscriptions : public PubSubPayload { + public: + + PubSubSubscriptions(); + PubSubSubscriptions(const std::string& node) : node(node) {} + virtual ~PubSubSubscriptions(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + const std::vector< boost::shared_ptr<PubSubSubscription> >& getSubscriptions() const { + return subscriptions; + } + + void setSubscriptions(const std::vector< boost::shared_ptr<PubSubSubscription> >& value) { + this->subscriptions = value ; + } + + void addSubscription(boost::shared_ptr<PubSubSubscription> value) { + this->subscriptions.push_back(value); + } + + + private: + boost::optional< std::string > node; + std::vector< boost::shared_ptr<PubSubSubscription> > subscriptions; + }; +} diff --git a/Swiften/Elements/PubSubUnsubscribe.cpp b/Swiften/Elements/PubSubUnsubscribe.cpp new file mode 100644 index 0000000..a9c8e71 --- /dev/null +++ b/Swiften/Elements/PubSubUnsubscribe.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/PubSubUnsubscribe.h> + +using namespace Swift; + +PubSubUnsubscribe::PubSubUnsubscribe() { +} + +PubSubUnsubscribe::~PubSubUnsubscribe() { +} diff --git a/Swiften/Elements/PubSubUnsubscribe.h b/Swiften/Elements/PubSubUnsubscribe.h new file mode 100644 index 0000000..21f857b --- /dev/null +++ b/Swiften/Elements/PubSubUnsubscribe.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <string> + +#include <Swiften/Elements/PubSubPayload.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class SWIFTEN_API PubSubUnsubscribe : public PubSubPayload { + public: + + PubSubUnsubscribe(); + + virtual ~PubSubUnsubscribe(); + + const boost::optional< std::string >& getNode() const { + return node; + } + + void setNode(const boost::optional< std::string >& value) { + this->node = value ; + } + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& value) { + this->jid = value ; + } + + const boost::optional< std::string >& getSubscriptionID() const { + return subscriptionID; + } + + void setSubscriptionID(const boost::optional< std::string >& value) { + this->subscriptionID = value ; + } + + + private: + boost::optional< std::string > node; + JID jid; + boost::optional< std::string > subscriptionID; + }; +} diff --git a/Swiften/Elements/Replace.h b/Swiften/Elements/Replace.h index 230bce7..96935f5 100644 --- a/Swiften/Elements/Replace.h +++ b/Swiften/Elements/Replace.h @@ -16,5 +16,5 @@ namespace Swift { public: typedef boost::shared_ptr<Replace> ref; - Replace(const std::string& id = std::string()) : replaceID_(id) {}; + Replace(const std::string& id = std::string()) : replaceID_(id) {} const std::string& getID() const { return replaceID_; diff --git a/Swiften/Elements/ResultSet.cpp b/Swiften/Elements/ResultSet.cpp new file mode 100644 index 0000000..2565bbb --- /dev/null +++ b/Swiften/Elements/ResultSet.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/ResultSet.h> + +using namespace Swift; + +ResultSet::~ResultSet() { +} diff --git a/Swiften/Elements/ResultSet.h b/Swiften/Elements/ResultSet.h new file mode 100644 index 0000000..e84be35 --- /dev/null +++ b/Swiften/Elements/ResultSet.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/API.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class SWIFTEN_API ResultSet : public Payload { + public: + virtual ~ResultSet(); + + void setMaxItems(const boost::optional<int>& maxItems) { maxItems_ = maxItems; } + const boost::optional<int>& getMaxItems() const { return maxItems_; } + + void setCount(const boost::optional<int>& count) { count_ = count; } + const boost::optional<int>& getCount() const { return count_; } + + void setFirstIDIndex(const boost::optional<int>& firstIndex) { firstIndex_ = firstIndex; } + const boost::optional<int>& getFirstIDIndex() const { return firstIndex_; } + + void setFirstID(const boost::optional<std::string>& firstID) { firstID_ = firstID; } + const boost::optional<std::string>& getFirstID() const { return firstID_; } + + void setLastID(const boost::optional<std::string>& lastID) { lastID_ = lastID; } + const boost::optional<std::string>& getLastID() const { return lastID_; } + + void setBefore(const boost::optional<std::string>& before) { before_ = before; } + const boost::optional<std::string>& getBefore() const { return before_; } + + void setAfter(const boost::optional<std::string>& after) { after_ = after; } + const boost::optional<std::string>& getAfter() const { return after_; } + + private: + boost::optional<int> maxItems_; + boost::optional<int> count_; + boost::optional<int> firstIndex_; + boost::optional<std::string> firstID_; + boost::optional<std::string> lastID_; + boost::optional<std::string> before_; + boost::optional<std::string> after_; + }; +} diff --git a/Swiften/Elements/RosterItemExchangePayload.h b/Swiften/Elements/RosterItemExchangePayload.h index f9aa2c8..622c775 100644 --- a/Swiften/Elements/RosterItemExchangePayload.h +++ b/Swiften/Elements/RosterItemExchangePayload.h @@ -11,14 +11,14 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Payload.h> #include <Swiften/JID/JID.h> - namespace Swift { - class RosterItemExchangePayload : public Payload { + class SWIFTEN_API RosterItemExchangePayload : public Payload { public: typedef boost::shared_ptr<RosterItemExchangePayload> ref; - class Item { + class SWIFTEN_API Item { public: enum Action { Add, Modify, Delete }; diff --git a/Swiften/Elements/RosterPayload.h b/Swiften/Elements/RosterPayload.h index c4907cb..47d27f2 100644 --- a/Swiften/Elements/RosterPayload.h +++ b/Swiften/Elements/RosterPayload.h @@ -11,4 +11,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/RosterItemPayload.h> #include <Swiften/Elements/Payload.h> @@ -16,5 +17,5 @@ namespace Swift { - class RosterPayload : public Payload { + class SWIFTEN_API RosterPayload : public Payload { public: typedef boost::shared_ptr<RosterPayload> ref; diff --git a/Swiften/Elements/SecurityLabel.cpp b/Swiften/Elements/SecurityLabel.cpp new file mode 100644 index 0000000..f2981c8 --- /dev/null +++ b/Swiften/Elements/SecurityLabel.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2010-2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/SecurityLabel.h> + +using namespace Swift; + +SecurityLabel::SecurityLabel() { +} + +SecurityLabel::~SecurityLabel() { +} diff --git a/Swiften/Elements/SecurityLabel.h b/Swiften/Elements/SecurityLabel.h index a1714c8..9a61123 100644 --- a/Swiften/Elements/SecurityLabel.h +++ b/Swiften/Elements/SecurityLabel.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,55 +7,71 @@ #pragma once +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <string> #include <vector> -#include <string> -#include <Swiften/Elements/Payload.h> + namespace Swift { - class SecurityLabel : public Payload { + class SWIFTEN_API SecurityLabel : public Payload { public: - typedef boost::shared_ptr<SecurityLabel> ref; - SecurityLabel() {} - const std::string& getDisplayMarking() const { return displayMarking_; } + SecurityLabel(); + + virtual ~SecurityLabel(); + + const std::vector< std::string >& getEquivalentLabels() const { + return equivalentLabels; + } - void setDisplayMarking(const std::string& displayMarking) { - displayMarking_ = displayMarking; + void setEquivalentLabels(const std::vector< std::string >& value) { + this->equivalentLabels = value ; + } + + void addEquivalentLabel(const std::string& value) { + this->equivalentLabels.push_back(value); } const std::string& getForegroundColor() const { - return foregroundColor_; + return foregroundColor; } - void setForegroundColor(const std::string& foregroundColor) { - foregroundColor_ = foregroundColor; + void setForegroundColor(const std::string& value) { + this->foregroundColor = value ; } - const std::string& getBackgroundColor() const { - return backgroundColor_; + const std::string& getDisplayMarking() const { + return displayMarking; } - void setBackgroundColor(const std::string& backgroundColor) { - backgroundColor_ = backgroundColor; + void setDisplayMarking(const std::string& value) { + this->displayMarking = value ; } - const std::string& getLabel() const { return label_; } + const std::string& getBackgroundColor() const { + return backgroundColor; + } - void setLabel(const std::string& label) { - label_ = label; + void setBackgroundColor(const std::string& value) { + this->backgroundColor = value ; } - const std::vector<std::string>& getEquivalentLabels() const { return equivalentLabels_; } + const std::string& getLabel() const { + return label; + } - void addEquivalentLabel(const std::string& label) { - equivalentLabels_.push_back(label); + void setLabel(const std::string& value) { + this->label = value ; } + private: - std::string displayMarking_; - std::string foregroundColor_; - std::string backgroundColor_; - std::string label_; - std::vector<std::string> equivalentLabels_; + std::vector< std::string > equivalentLabels; + std::string foregroundColor; + std::string displayMarking; + std::string backgroundColor; + std::string label; }; } diff --git a/Swiften/Elements/SecurityLabelsCatalog.h b/Swiften/Elements/SecurityLabelsCatalog.h index 5498fcf..000240e 100644 --- a/Swiften/Elements/SecurityLabelsCatalog.h +++ b/Swiften/Elements/SecurityLabelsCatalog.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,4 +11,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <Swiften/Elements/Payload.h> @@ -16,5 +17,5 @@ namespace Swift { - class SecurityLabelsCatalog : public Payload { + class SWIFTEN_API SecurityLabelsCatalog : public Payload { public: typedef boost::shared_ptr<SecurityLabelsCatalog> ref; @@ -22,9 +23,9 @@ namespace Swift { public: Item() : default_(false) {} - SecurityLabel::ref getLabel() const { + boost::shared_ptr<SecurityLabel> getLabel() const { return label_; } - void setLabel(SecurityLabel::ref label) { + void setLabel(boost::shared_ptr<SecurityLabel> label) { label_ = label; } @@ -42,5 +43,5 @@ namespace Swift { } private: - SecurityLabel::ref label_; + boost::shared_ptr<SecurityLabel> label_; std::string selector_; bool default_; diff --git a/Swiften/Elements/SoftwareVersion.h b/Swiften/Elements/SoftwareVersion.h index c49b47b..e0eeaa3 100644 --- a/Swiften/Elements/SoftwareVersion.h +++ b/Swiften/Elements/SoftwareVersion.h @@ -10,8 +10,9 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Payload.h> namespace Swift { - class SoftwareVersion : public Payload { + class SWIFTEN_API SoftwareVersion : public Payload { public: typedef boost::shared_ptr<SoftwareVersion> ref; diff --git a/Swiften/Elements/Stanza.h b/Swiften/Elements/Stanza.h index 9e082cc..648c4df 100644 --- a/Swiften/Elements/Stanza.h +++ b/Swiften/Elements/Stanza.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,5 +13,6 @@ #include <boost/date_time/posix_time/ptime.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/JID/JID.h> @@ -19,10 +20,14 @@ namespace Swift { class Payload; - class Stanza : public Element { + class SWIFTEN_API Stanza : public ToplevelElement { public: typedef boost::shared_ptr<Stanza> ref; + protected: Stanza(); + + public: virtual ~Stanza(); + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(Stanza) template<typename T> @@ -58,4 +63,9 @@ namespace Swift { } + template<typename InputIterator> + void addPayloads(InputIterator begin, InputIterator end) { + payloads_.insert(payloads_.end(), begin, end); + } + void updatePayload(boost::shared_ptr<Payload> payload); diff --git a/Swiften/Elements/StanzaAck.cpp b/Swiften/Elements/StanzaAck.cpp new file mode 100644 index 0000000..5bcab73 --- /dev/null +++ b/Swiften/Elements/StanzaAck.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StanzaAck.h> + +#include <boost/numeric/conversion/cast.hpp> + +using namespace Swift; + +StanzaAck::~StanzaAck() { +} + +void StanzaAck::setHandledStanzasCount(int i) { + handledStanzasCount = boost::numeric_cast<unsigned int>(i); + valid = true; +} diff --git a/Swiften/Elements/StanzaAck.h b/Swiften/Elements/StanzaAck.h index 3aa2dfd..0d99c5b 100644 --- a/Swiften/Elements/StanzaAck.h +++ b/Swiften/Elements/StanzaAck.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,9 +7,10 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <boost/shared_ptr.hpp> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StanzaAck : public Element { + class StanzaAck : public ToplevelElement { public: typedef boost::shared_ptr<StanzaAck> ref; @@ -17,4 +18,5 @@ namespace Swift { StanzaAck() : valid(false), handledStanzasCount(0) {} StanzaAck(unsigned int handledStanzasCount) : valid(true), handledStanzasCount(handledStanzasCount) {} + virtual ~StanzaAck(); unsigned int getHandledStanzasCount() const { @@ -22,8 +24,5 @@ namespace Swift { } - void setHandledStanzasCount(int i) { - handledStanzasCount = i; - valid = true; - } + void setHandledStanzasCount(int i); bool isValid() const { diff --git a/Swiften/Elements/StanzaAckRequest.h b/Swiften/Elements/StanzaAckRequest.h index 81b3871..0ae11ad 100644 --- a/Swiften/Elements/StanzaAckRequest.h +++ b/Swiften/Elements/StanzaAckRequest.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,9 +7,9 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StanzaAckRequest : public Element { + class StanzaAckRequest : public ToplevelElement { }; } diff --git a/Swiften/Elements/StartTLSFailure.h b/Swiften/Elements/StartTLSFailure.h index 5e233fb..ce13fd6 100644 --- a/Swiften/Elements/StartTLSFailure.h +++ b/Swiften/Elements/StartTLSFailure.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,8 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StartTLSFailure : public Element { + class StartTLSFailure : public ToplevelElement { public: StartTLSFailure() {} diff --git a/Swiften/Elements/StartTLSRequest.h b/Swiften/Elements/StartTLSRequest.h index e284f75..4b4f1f1 100644 --- a/Swiften/Elements/StartTLSRequest.h +++ b/Swiften/Elements/StartTLSRequest.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,8 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StartTLSRequest : public Element { + class StartTLSRequest : public ToplevelElement { public: StartTLSRequest() {} diff --git a/Swiften/Elements/StatusShow.h b/Swiften/Elements/StatusShow.h index cd3477e..afa30de 100644 --- a/Swiften/Elements/StatusShow.h +++ b/Swiften/Elements/StatusShow.h @@ -7,8 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Elements/Payload.h> +#include <cassert> namespace Swift { - class StatusShow : public Payload { + class SWIFTEN_API StatusShow : public Payload { public: enum Type { Online, Away, FFC, XA, DND, None }; @@ -37,4 +39,5 @@ namespace Swift { case None: return 0; } + assert(false); return 0; } diff --git a/Swiften/Elements/StreamError.h b/Swiften/Elements/StreamError.h index 0d0551c..300f1c7 100644 --- a/Swiften/Elements/StreamError.h +++ b/Swiften/Elements/StreamError.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,9 +9,9 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <string> namespace Swift { - class StreamError : public Element { + class StreamError : public ToplevelElement { public: typedef boost::shared_ptr<StreamError> ref; @@ -42,5 +42,5 @@ namespace Swift { UnsupportedEncoding, UnsupportedStanzaType, - UnsupportedVersion, + UnsupportedVersion }; diff --git a/Swiften/Elements/StreamFeatures.h b/Swiften/Elements/StreamFeatures.h index cae5532..ed40544 100644 --- a/Swiften/Elements/StreamFeatures.h +++ b/Swiften/Elements/StreamFeatures.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,8 +11,9 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StreamFeatures : public Element { + class SWIFTEN_API StreamFeatures : public ToplevelElement { public: typedef boost::shared_ptr<StreamFeatures> ref; diff --git a/Swiften/Elements/StreamInitiationFileInfo.h b/Swiften/Elements/StreamInitiationFileInfo.h index 9484bc0..d7907b9 100644 --- a/Swiften/Elements/StreamInitiationFileInfo.h +++ b/Swiften/Elements/StreamInitiationFileInfo.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -20,5 +20,5 @@ public: public: - StreamInitiationFileInfo(const std::string& name = "", const std::string& description = "", int size = 0, + StreamInitiationFileInfo(const std::string& name = "", const std::string& description = "", unsigned long long size = 0, const std::string& hash = "", const boost::posix_time::ptime &date = boost::posix_time::ptime(), const std::string& algo="md5") : name(name), description(description), size(size), hash(hash), date(date), algo(algo), supportsRangeRequests(false), rangeOffset(0) {} @@ -40,9 +40,9 @@ public: } - void setSize(const boost::uintmax_t size) { + void setSize(const unsigned long long size) { this->size = size; } - boost::uintmax_t getSize() const { + unsigned long long getSize() const { return this->size; } @@ -80,10 +80,10 @@ public: } - void setRangeOffset(const int offset) { - supportsRangeRequests = offset >= 0 ? true : false; + void setRangeOffset(unsigned long long offset) { + supportsRangeRequests = true; rangeOffset = offset; } - int getRangeOffset() const { + unsigned long long getRangeOffset() const { return rangeOffset; } @@ -92,10 +92,10 @@ private: std::string name; std::string description; - boost::uintmax_t size; + unsigned long long size; std::string hash; boost::posix_time::ptime date; std::string algo; bool supportsRangeRequests; - boost::uintmax_t rangeOffset; + unsigned long long rangeOffset; }; diff --git a/Swiften/Elements/StreamManagementEnabled.cpp b/Swiften/Elements/StreamManagementEnabled.cpp index bab7516..1f1a1f5 100644 --- a/Swiften/Elements/StreamManagementEnabled.cpp +++ b/Swiften/Elements/StreamManagementEnabled.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,5 +9,5 @@ using namespace Swift; -StreamManagementEnabled::StreamManagementEnabled() { +StreamManagementEnabled::StreamManagementEnabled() : resumeSupported(false) { } diff --git a/Swiften/Elements/StreamManagementEnabled.h b/Swiften/Elements/StreamManagementEnabled.h index 02e77f3..bb1f858 100644 --- a/Swiften/Elements/StreamManagementEnabled.h +++ b/Swiften/Elements/StreamManagementEnabled.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010-2011 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,8 +9,9 @@ #include <string> -#include <Swiften/Elements/Element.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StreamManagementEnabled : public Element { + class SWIFTEN_API StreamManagementEnabled : public ToplevelElement { public: StreamManagementEnabled(); diff --git a/Swiften/Elements/StreamManagementFailed.h b/Swiften/Elements/StreamManagementFailed.h index 7c6d1b7..a90bddd 100644 --- a/Swiften/Elements/StreamManagementFailed.h +++ b/Swiften/Elements/StreamManagementFailed.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,9 +7,9 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StreamManagementFailed : public Element { + class StreamManagementFailed : public ToplevelElement { public: StreamManagementFailed() {} diff --git a/Swiften/Elements/StreamResume.h b/Swiften/Elements/StreamResume.h index aec0909..e87dabb 100644 --- a/Swiften/Elements/StreamResume.h +++ b/Swiften/Elements/StreamResume.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,8 +10,8 @@ #include <boost/optional.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StreamResume : public Element { + class StreamResume : public ToplevelElement { public: StreamResume(); diff --git a/Swiften/Elements/StreamResumed.h b/Swiften/Elements/StreamResumed.h index cf9a755..7890901 100644 --- a/Swiften/Elements/StreamResumed.h +++ b/Swiften/Elements/StreamResumed.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,8 +10,8 @@ #include <boost/optional.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class StreamResumed : public Element { + class StreamResumed : public ToplevelElement { public: StreamResumed(); diff --git a/Swiften/Elements/TLSProceed.h b/Swiften/Elements/TLSProceed.h index 4bd790a..27faf26 100644 --- a/Swiften/Elements/TLSProceed.h +++ b/Swiften/Elements/TLSProceed.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,8 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class TLSProceed : public Element { + class TLSProceed : public ToplevelElement { public: TLSProceed() {} diff --git a/Swiften/FileTransfer/JingleTransport.cpp b/Swiften/Elements/ToplevelElement.cpp index c507922..c58a914 100644 --- a/Swiften/FileTransfer/JingleTransport.cpp +++ b/Swiften/Elements/ToplevelElement.cpp @@ -1,14 +1,13 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { -JingleTransport::~JingleTransport() { - +ToplevelElement::~ToplevelElement() { } diff --git a/Swiften/Elements/ToplevelElement.h b/Swiften/Elements/ToplevelElement.h new file mode 100644 index 0000000..bce90b9 --- /dev/null +++ b/Swiften/Elements/ToplevelElement.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010-2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Element.h> + +namespace Swift { + class SWIFTEN_API ToplevelElement : public Element { + public: + ToplevelElement() {} + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(ToplevelElement) + virtual ~ToplevelElement(); + }; +} diff --git a/Swiften/Elements/UnblockPayload.h b/Swiften/Elements/UnblockPayload.h index b6593ab..c5e7c80 100644 --- a/Swiften/Elements/UnblockPayload.h +++ b/Swiften/Elements/UnblockPayload.h @@ -15,5 +15,5 @@ namespace Swift { class UnblockPayload : public Payload { public: - UnblockPayload() { + UnblockPayload(const std::vector<JID>& jids = std::vector<JID>()) : items(jids) { } diff --git a/Swiften/Elements/UnitTest/FormTest.cpp b/Swiften/Elements/UnitTest/FormTest.cpp index 1134182..3000c22 100644 --- a/Swiften/Elements/UnitTest/FormTest.cpp +++ b/Swiften/Elements/UnitTest/FormTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Elements/Form.h> @@ -24,11 +25,11 @@ class FormTest : public CppUnit::TestFixture { Form form; - form.addField(FixedFormField::create("Foo")); + form.addField(boost::make_shared<FormField>(FormField::FixedType, "Foo")); - FormField::ref field = HiddenFormField::create("jabber:bot"); + FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:bot"); field->setName("FORM_TYPE"); form.addField(field); - form.addField(FixedFormField::create("Bar")); + form.addField(boost::make_shared<FormField>(FormField::FixedType, "Bar")); CPPUNIT_ASSERT_EQUAL(std::string("jabber:bot"), form.getFormType()); @@ -38,5 +39,5 @@ class FormTest : public CppUnit::TestFixture { Form form; - FormField::ref field = FixedFormField::create("jabber:bot"); + FormField::ref field = boost::make_shared<FormField>(FormField::FixedType, "jabber:bot"); field->setName("FORM_TYPE"); form.addField(field); @@ -48,5 +49,5 @@ class FormTest : public CppUnit::TestFixture { Form form; - form.addField(FixedFormField::create("Foo")); + form.addField(boost::make_shared<FormField>(FormField::FixedType, "Foo")); CPPUNIT_ASSERT_EQUAL(std::string(""), form.getFormType()); diff --git a/Swiften/Elements/UnknownElement.h b/Swiften/Elements/UnknownElement.h index 100ba92..48072ef 100644 --- a/Swiften/Elements/UnknownElement.h +++ b/Swiften/Elements/UnknownElement.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,8 @@ #pragma once -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { - class UnknownElement : public Element { + class UnknownElement : public ToplevelElement { public: UnknownElement() {} diff --git a/Swiften/Elements/UserLocation.cpp b/Swiften/Elements/UserLocation.cpp new file mode 100644 index 0000000..6f78ccb --- /dev/null +++ b/Swiften/Elements/UserLocation.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/UserLocation.h> + +using namespace Swift; + +UserLocation::UserLocation() { +} + +UserLocation::~UserLocation() { +} diff --git a/Swiften/Elements/UserLocation.h b/Swiften/Elements/UserLocation.h new file mode 100644 index 0000000..817b259 --- /dev/null +++ b/Swiften/Elements/UserLocation.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <boost/optional.hpp> +#include <string> + + + +namespace Swift { + class SWIFTEN_API UserLocation : public Payload { + public: + + UserLocation(); + + virtual ~UserLocation(); + + const boost::optional< std::string >& getArea() const { + return area; + } + + void setArea(const boost::optional< std::string >& value) { + this->area = value ; + } + + const boost::optional< float >& getAltitude() const { + return altitude; + } + + void setAltitude(const boost::optional< float >& value) { + this->altitude = value ; + } + + const boost::optional< std::string >& getLocality() const { + return locality; + } + + void setLocality(const boost::optional< std::string >& value) { + this->locality = value ; + } + + const boost::optional< float >& getLatitude() const { + return latitude; + } + + void setLatitude(const boost::optional< float >& value) { + this->latitude = value ; + } + + const boost::optional< float >& getAccuracy() const { + return accuracy; + } + + void setAccuracy(const boost::optional< float >& value) { + this->accuracy = value ; + } + + const boost::optional< std::string >& getDescription() const { + return description; + } + + void setDescription(const boost::optional< std::string >& value) { + this->description = value ; + } + + const boost::optional< std::string >& getCountryCode() const { + return countryCode; + } + + void setCountryCode(const boost::optional< std::string >& value) { + this->countryCode = value ; + } + + const boost::optional< boost::posix_time::ptime >& getTimestamp() const { + return timestamp; + } + + void setTimestamp(const boost::optional< boost::posix_time::ptime >& value) { + this->timestamp = value ; + } + + const boost::optional< std::string >& getFloor() const { + return floor; + } + + void setFloor(const boost::optional< std::string >& value) { + this->floor = value ; + } + + const boost::optional< std::string >& getBuilding() const { + return building; + } + + void setBuilding(const boost::optional< std::string >& value) { + this->building = value ; + } + + const boost::optional< std::string >& getRoom() const { + return room; + } + + void setRoom(const boost::optional< std::string >& value) { + this->room = value ; + } + + const boost::optional< std::string >& getCountry() const { + return country; + } + + void setCountry(const boost::optional< std::string >& value) { + this->country = value ; + } + + const boost::optional< std::string >& getRegion() const { + return region; + } + + void setRegion(const boost::optional< std::string >& value) { + this->region = value ; + } + + const boost::optional< std::string >& getURI() const { + return uri; + } + + void setURI(const boost::optional< std::string >& value) { + this->uri = value ; + } + + const boost::optional< float >& getLongitude() const { + return longitude; + } + + void setLongitude(const boost::optional< float >& value) { + this->longitude = value ; + } + + const boost::optional< float >& getError() const { + return error; + } + + void setError(const boost::optional< float >& value) { + this->error = value ; + } + + const boost::optional< std::string >& getPostalCode() const { + return postalCode; + } + + void setPostalCode(const boost::optional< std::string >& value) { + this->postalCode = value ; + } + + const boost::optional< float >& getBearing() const { + return bearing; + } + + void setBearing(const boost::optional< float >& value) { + this->bearing = value ; + } + + const boost::optional< std::string >& getText() const { + return text; + } + + void setText(const boost::optional< std::string >& value) { + this->text = value ; + } + + const boost::optional< std::string >& getDatum() const { + return datum; + } + + void setDatum(const boost::optional< std::string >& value) { + this->datum = value ; + } + + const boost::optional< std::string >& getStreet() const { + return street; + } + + void setStreet(const boost::optional< std::string >& value) { + this->street = value ; + } + + const boost::optional< float >& getSpeed() const { + return speed; + } + + void setSpeed(const boost::optional< float >& value) { + this->speed = value ; + } + + + private: + boost::optional< std::string > area; + boost::optional< float > altitude; + boost::optional< std::string > locality; + boost::optional< float > latitude; + boost::optional< float > accuracy; + boost::optional< std::string > description; + boost::optional< std::string > countryCode; + boost::optional< boost::posix_time::ptime > timestamp; + boost::optional< std::string > floor; + boost::optional< std::string > building; + boost::optional< std::string > room; + boost::optional< std::string > country; + boost::optional< std::string > region; + boost::optional< std::string > uri; + boost::optional< float > longitude; + boost::optional< float > error; + boost::optional< std::string > postalCode; + boost::optional< float > bearing; + boost::optional< std::string > text; + boost::optional< std::string > datum; + boost::optional< std::string > street; + boost::optional< float > speed; + }; +} diff --git a/Swiften/Elements/UserTune.cpp b/Swiften/Elements/UserTune.cpp new file mode 100644 index 0000000..4b99e0a --- /dev/null +++ b/Swiften/Elements/UserTune.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/UserTune.h> + +using namespace Swift; + +UserTune::UserTune() { +} + +UserTune::~UserTune() { +} diff --git a/Swiften/Elements/UserTune.h b/Swiften/Elements/UserTune.h new file mode 100644 index 0000000..968da17 --- /dev/null +++ b/Swiften/Elements/UserTune.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <string> + + + +namespace Swift { + class SWIFTEN_API UserTune : public Payload { + public: + + UserTune(); + + virtual ~UserTune(); + + const boost::optional< unsigned int >& getRating() const { + return rating; + } + + void setRating(const boost::optional< unsigned int >& value) { + this->rating = value ; + } + + const boost::optional< std::string >& getTitle() const { + return title; + } + + void setTitle(const boost::optional< std::string >& value) { + this->title = value ; + } + + const boost::optional< std::string >& getTrack() const { + return track; + } + + void setTrack(const boost::optional< std::string >& value) { + this->track = value ; + } + + const boost::optional< std::string >& getArtist() const { + return artist; + } + + void setArtist(const boost::optional< std::string >& value) { + this->artist = value ; + } + + const boost::optional< std::string >& getURI() const { + return uri; + } + + void setURI(const boost::optional< std::string >& value) { + this->uri = value ; + } + + const boost::optional< std::string >& getSource() const { + return source; + } + + void setSource(const boost::optional< std::string >& value) { + this->source = value ; + } + + const boost::optional< unsigned int >& getLength() const { + return length; + } + + void setLength(const boost::optional< unsigned int >& value) { + this->length = value ; + } + + + private: + boost::optional< unsigned int > rating; + boost::optional< std::string > title; + boost::optional< std::string > track; + boost::optional< std::string > artist; + boost::optional< std::string > uri; + boost::optional< std::string > source; + boost::optional< unsigned int > length; + }; +} diff --git a/Swiften/Elements/VCard.h b/Swiften/Elements/VCard.h index f9822c9..409a8ab 100644 --- a/Swiften/Elements/VCard.h +++ b/Swiften/Elements/VCard.h @@ -8,6 +8,8 @@ #include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/ptime.hpp> #include <string> +#include <Swiften/JID/JID.h> #include <Swiften/Base/ByteArray.h> #include <Swiften/Elements/Payload.h> @@ -30,4 +32,69 @@ namespace Swift { }; + struct Telephone { + Telephone() : isHome(false), isWork(false), isVoice(false), isFax(false), isPager(false), isMSG(false), isCell(false), + isVideo(false), isBBS(false), isModem(false), isISDN(false), isPCS(false), isPreferred(false) { + } + + bool isHome; + bool isWork; + bool isVoice; + bool isFax; + bool isPager; + bool isMSG; + bool isCell; + bool isVideo; + bool isBBS; + bool isModem; + bool isISDN; + bool isPCS; + bool isPreferred; + std::string number; + }; + + enum DeliveryType { + DomesticDelivery, + InternationalDelivery, + None + }; + + struct Address { + Address() : isHome(false), isWork(false), isPostal(false), isParcel(false), deliveryType(None), isPreferred(false) { + } + + bool isHome; + bool isWork; + bool isPostal; + bool isParcel; + DeliveryType deliveryType; + bool isPreferred; + + std::string poBox; + std::string addressExtension; + std::string street; + std::string locality; + std::string region; + std::string postalCode; + std::string country; + }; + + struct AddressLabel { + AddressLabel() : isHome(false), isWork(false), isPostal(false), isParcel(false), deliveryType(None), isPreferred(false) { + } + + bool isHome; + bool isWork; + bool isPostal; + bool isParcel; + DeliveryType deliveryType; + bool isPreferred; + std::vector<std::string> lines; + }; + + struct Organization { + std::string name; + std::vector<std::string> units; + }; + VCard() {} @@ -79,6 +146,132 @@ namespace Swift { } + void clearEMailAddresses() { + emailAddresses_.clear(); + } + EMailAddress getPreferredEMailAddress() const; + void setBirthday(const boost::posix_time::ptime& birthday) { + birthday_ = birthday; + } + + const boost::posix_time::ptime& getBirthday() const { + return birthday_; + } + + const std::vector<Telephone>& getTelephones() const { + return telephones_; + } + + void addTelephone(const Telephone& phone) { + telephones_.push_back(phone); + } + + void clearTelephones() { + telephones_.clear(); + } + + const std::vector<Address>& getAddresses() const { + return addresses_; + } + + void addAddress(const Address& address) { + addresses_.push_back(address); + } + + void clearAddresses() { + addresses_.clear(); + } + + const std::vector<AddressLabel>& getAddressLabels() const { + return addressLabels_; + } + + void addAddressLabel(const AddressLabel& addressLabel) { + addressLabels_.push_back(addressLabel); + } + + void clearAddressLabels() { + addressLabels_.clear(); + } + + const std::vector<JID>& getJIDs() const { + return jids_; + } + + void addJID(const JID& jid) { + jids_.push_back(jid); + } + + void clearJIDs() { + jids_.clear(); + } + + const std::string& getDescription() const { + return description_; + } + + void setDescription(const std::string& description) { + this->description_ = description; + } + + const std::vector<Organization>& getOrganizations() const { + return organizations_; + } + + void addOrganization(const Organization& organization) { + organizations_.push_back(organization); + } + + void clearOrganizations() { + organizations_.clear(); + } + + const std::vector<std::string>& getTitles() const { + return titles_; + } + + void addTitle(const std::string& title) { + titles_.push_back(title); + } + + void clearTitles() { + titles_.clear(); + } + + const std::vector<std::string>& getRoles() const { + return roles_; + } + + void addRole(const std::string& role) { + roles_.push_back(role); + } + + void clearRoles() { + roles_.clear(); + } + + const std::vector<std::string>& getURLs() const { + return urls_; + } + + void addURL(const std::string& url) { + urls_.push_back(url); + } + + void clearURLs() { + urls_.clear(); + } + + bool isEmpty() const { + bool empty = version_.empty() && fullName_.empty() && familyName_.empty() && givenName_.empty() && middleName_.empty() && prefix_.empty() && suffix_.empty(); + empty &= photo_.empty() && photoType_.empty() && nick_.empty(); + empty &= birthday_.is_not_a_date_time(); + empty &= unknownContent_.empty(); + empty &= emailAddresses_.empty() && telephones_.empty() && addresses_.empty() && addressLabels_.empty() && jids_.empty(); + empty &= description_.empty() && organizations_.empty() && titles_.empty() && roles_.empty() && urls_.empty(); + return empty; + } + private: std::string version_; @@ -93,6 +286,16 @@ namespace Swift { std::string photoType_; std::string nick_; + boost::posix_time::ptime birthday_; std::string unknownContent_; std::vector<EMailAddress> emailAddresses_; + std::vector<Telephone> telephones_; + std::vector<Address> addresses_; + std::vector<AddressLabel> addressLabels_; + std::vector<JID> jids_; + std::string description_; + std::vector<Organization> organizations_; + std::vector<std::string> titles_; + std::vector<std::string> roles_; + std::vector<std::string> urls_; }; } diff --git a/Swiften/Elements/Whiteboard/WhiteboardColor.cpp b/Swiften/Elements/Whiteboard/WhiteboardColor.cpp new file mode 100644 index 0000000..f4ff01a --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardColor.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> +#include <Swiften/Base/String.h> +#include <cstdio> +#include <iomanip> +#include <sstream> +#include <iostream> + +namespace Swift { + WhiteboardColor::WhiteboardColor() : red_(0), green_(0), blue_(0), alpha_(255) { + } + + WhiteboardColor::WhiteboardColor(int red, int green, int blue, int alpha) : red_(red), green_(green), blue_(blue), alpha_(alpha) { + } + + WhiteboardColor::WhiteboardColor(const std::string& hex) : alpha_(255) { + int value = String::convertHexStringToInt(hex.substr(1)); + red_ = (value >> 16)&0xFF; + green_ = (value >> 8)&0xFF; + blue_ = value&0xFF; + } + + std::string WhiteboardColor::toHex() const { + std::string value = String::convertIntToHexString((red_ << 16) + (green_ << 8) + blue_); + while (value.size() < 6) { + value.insert(0, "0"); + } + return "#"+value; + } + + int WhiteboardColor::getRed() const { + return red_; + } + + int WhiteboardColor::getGreen() const { + return green_; + } + + int WhiteboardColor::getBlue() const { + return blue_; + } + + int WhiteboardColor::getAlpha() const { + return alpha_; + } + + void WhiteboardColor::setAlpha(int alpha) { + alpha_ = alpha; + } +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardColor.h b/Swiften/Elements/Whiteboard/WhiteboardColor.h new file mode 100644 index 0000000..3b3d93c --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardColor.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/Base/API.h> + +namespace Swift { + class SWIFTEN_API WhiteboardColor { + public: + WhiteboardColor(); + WhiteboardColor(int red, int green, int blue, int alpha = 255); + WhiteboardColor(const std::string& hex); + std::string toHex() const; + int getRed() const; + int getGreen() const; + int getBlue() const; + int getAlpha() const; + void setAlpha(int alpha); + + private: + int red_, green_, blue_; + int alpha_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h b/Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h new file mode 100644 index 0000000..95015c9 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardOperation.h> + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> + +namespace Swift { + class WhiteboardDeleteOperation : public WhiteboardOperation { + public: + typedef boost::shared_ptr<WhiteboardDeleteOperation> ref; + public: + std::string getElementID() const { + return elementID_; + } + + void setElementID(const std::string& elementID) { + elementID_ = elementID; + } + + private: + std::string elementID_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardElement.h b/Swiften/Elements/Whiteboard/WhiteboardElement.h new file mode 100644 index 0000000..df774d9 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardElement.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Elements/Whiteboard/WhiteboardElementVisitor.h> + +namespace Swift { + class WhiteboardElement { + public: + typedef boost::shared_ptr<WhiteboardElement> ref; + + public: + virtual ~WhiteboardElement() {} + virtual void accept(WhiteboardElementVisitor& visitor) = 0; + + const std::string& getID() const { + return id_; + } + + void setID(const std::string& id) { + id_ = id; + } + + private: + std::string id_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardElementVisitor.h b/Swiften/Elements/Whiteboard/WhiteboardElementVisitor.h new file mode 100644 index 0000000..413d6cf --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardElementVisitor.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +namespace Swift { + class WhiteboardLineElement; + class WhiteboardFreehandPathElement; + class WhiteboardRectElement; + class WhiteboardPolygonElement; + class WhiteboardTextElement; + class WhiteboardEllipseElement; + + class WhiteboardElementVisitor { + public: + virtual ~WhiteboardElementVisitor() {} + virtual void visit(WhiteboardLineElement& /*element*/) = 0; + virtual void visit(WhiteboardFreehandPathElement& /*element*/) = 0; + virtual void visit(WhiteboardRectElement& /*element*/) = 0; + virtual void visit(WhiteboardPolygonElement& /*element*/) = 0; + virtual void visit(WhiteboardTextElement& /*element*/) = 0; + virtual void visit(WhiteboardEllipseElement& /*element*/) = 0; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardEllipseElement.h b/Swiften/Elements/Whiteboard/WhiteboardEllipseElement.h new file mode 100644 index 0000000..0078479 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardEllipseElement.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> + +namespace Swift { + class WhiteboardEllipseElement : public WhiteboardElement { + public: + typedef boost::shared_ptr<WhiteboardEllipseElement> ref; + public: + WhiteboardEllipseElement(int cx, int cy, int rx, int ry) { + cx_ = cx; + cy_ = cy; + rx_ = rx; + ry_ = ry; + } + + int getCX() const { + return cx_; + } + + int getCY() const { + return cy_; + } + + int getRX() const { + return rx_; + } + + int getRY() const { + return ry_; + } + + const WhiteboardColor& getPenColor() const { + return penColor_; + } + + void setPenColor(const WhiteboardColor& color) { + penColor_ = color; + } + + const WhiteboardColor& getBrushColor() const { + return brushColor_; + } + + void setBrushColor(const WhiteboardColor& color) { + brushColor_ = color; + } + + int getPenWidth() const { + return penWidth_; + } + + void setPenWidth(const int penWidth) { + penWidth_ = penWidth; + } + + void accept(WhiteboardElementVisitor& visitor) { + visitor.visit(*this); + } + + private: + int cx_, cy_, rx_, ry_; + WhiteboardColor penColor_; + WhiteboardColor brushColor_; + int penWidth_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardFreehandPathElement.h b/Swiften/Elements/Whiteboard/WhiteboardFreehandPathElement.h new file mode 100644 index 0000000..bcf3bf9 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardFreehandPathElement.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> + +#include <vector> +#include <utility> + +namespace Swift { + class WhiteboardFreehandPathElement : public WhiteboardElement { + typedef std::pair<int, int> Point; + public: + typedef boost::shared_ptr<WhiteboardFreehandPathElement> ref; + public: + WhiteboardFreehandPathElement() { + } + + void setPoints(const std::vector<Point>& points) { + points_ = points; + } + + const std::vector<Point>& getPoints() const { + return points_; + } + + const WhiteboardColor& getColor() const { + return color_; + } + + void setColor(const WhiteboardColor& color) { + color_ = color; + } + + int getPenWidth() const { + return penWidth_; + } + + void setPenWidth(const int penWidth) { + penWidth_ = penWidth; + } + + void accept(WhiteboardElementVisitor& visitor) { + visitor.visit(*this); + } + + private: + std::vector<Point> points_; + WhiteboardColor color_; + int penWidth_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h b/Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h new file mode 100644 index 0000000..fd52405 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardOperation.h> + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> + +namespace Swift { + class WhiteboardInsertOperation : public WhiteboardOperation { + public: + typedef boost::shared_ptr<WhiteboardInsertOperation> ref; + public: + WhiteboardElement::ref getElement() const { + return element_; + } + + void setElement(WhiteboardElement::ref element) { + element_ = element; + } + + private: + WhiteboardElement::ref element_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardLineElement.h b/Swiften/Elements/Whiteboard/WhiteboardLineElement.h new file mode 100644 index 0000000..df6e7d6 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardLineElement.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> + +namespace Swift { + class WhiteboardLineElement : public WhiteboardElement { + public: + typedef boost::shared_ptr<WhiteboardLineElement> ref; + public: + WhiteboardLineElement(int x1, int y1, int x2, int y2) : penWidth_(1) { + x1_ = x1; + y1_ = y1; + x2_ = x2; + y2_ = y2; + } + + int x1() const { + return x1_; + } + + int y1() const { + return y1_; + } + + int x2() const { + return x2_; + } + + int y2() const { + return y2_; + } + + const WhiteboardColor& getColor() const { + return color_; + } + + void setColor(const WhiteboardColor& color) { + color_ = color; + } + + int getPenWidth() const { + return penWidth_; + } + + void setPenWidth(const int penWidth) { + penWidth_ = penWidth; + } + + void accept(WhiteboardElementVisitor& visitor) { + visitor.visit(*this); + } + + private: + int x1_, y1_, x2_, y2_; + WhiteboardColor color_; + int penWidth_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardOperation.h b/Swiften/Elements/Whiteboard/WhiteboardOperation.h new file mode 100644 index 0000000..497d551 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardOperation.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <boost/smart_ptr/shared_ptr.hpp> +#include <string> + +namespace Swift { + class WhiteboardOperation { + public: + typedef boost::shared_ptr<WhiteboardOperation> ref; + public: + WhiteboardOperation() {} + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(WhiteboardOperation) + virtual ~WhiteboardOperation(){} + + std::string getID() const { + return id_; + } + + void setID(const std::string& id) { + id_ = id; + } + + std::string getParentID() const { + return parentID_; + } + + void setParentID(const std::string& parentID) { + parentID_ = parentID; + } + + int getPos() const { + return pos_; + } + + void setPos(int pos) { + pos_ = pos; + } + + private: + std::string id_; + std::string parentID_; + int pos_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardPolygonElement.h b/Swiften/Elements/Whiteboard/WhiteboardPolygonElement.h new file mode 100644 index 0000000..679ac01 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardPolygonElement.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> + +namespace Swift { + class WhiteboardPolygonElement : public WhiteboardElement { + typedef std::pair<int, int> Point; + public: + typedef boost::shared_ptr<WhiteboardPolygonElement> ref; + public: + WhiteboardPolygonElement() { + } + + const std::vector<Point>& getPoints() const { + return points_; + } + + void setPoints(const std::vector<Point>& points) { + points_ = points; + } + + const WhiteboardColor& getPenColor() const { + return penColor_; + } + + void setPenColor(const WhiteboardColor& color) { + penColor_ = color; + } + + const WhiteboardColor& getBrushColor() const { + return brushColor_; + } + + void setBrushColor(const WhiteboardColor& color) { + brushColor_ = color; + } + + int getPenWidth() const { + return penWidth_; + } + + void setPenWidth(const int penWidth) { + penWidth_ = penWidth; + } + + void accept(WhiteboardElementVisitor& visitor) { + visitor.visit(*this); + } + + private: + std::vector<Point> points_; + WhiteboardColor penColor_; + WhiteboardColor brushColor_; + int penWidth_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardRectElement.h b/Swiften/Elements/Whiteboard/WhiteboardRectElement.h new file mode 100644 index 0000000..0fd1338 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardRectElement.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> + +namespace Swift { + class WhiteboardRectElement : public WhiteboardElement { + public: + typedef boost::shared_ptr<WhiteboardRectElement> ref; + public: + WhiteboardRectElement(int x, int y, int width, int height) : penWidth_(1) { + x_ = x; + y_ = y; + width_ = width; + height_ = height; + } + + int getX() const { + return x_; + } + + int getY() const { + return y_; + } + + int getWidth() const { + return width_; + } + + int getHeight() const { + return height_; + } + + const WhiteboardColor& getPenColor() const { + return penColor_; + } + + void setPenColor(const WhiteboardColor& color) { + penColor_ = color; + } + + const WhiteboardColor& getBrushColor() const { + return brushColor_; + } + + void setBrushColor(const WhiteboardColor& color) { + brushColor_ = color; + } + + int getPenWidth() const { + return penWidth_; + } + + void setPenWidth(const int penWidth) { + penWidth_ = penWidth; + } + + void accept(WhiteboardElementVisitor& visitor) { + visitor.visit(*this); + } + + private: + int x_, y_, width_, height_; + WhiteboardColor penColor_; + WhiteboardColor brushColor_; + int penWidth_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardTextElement.h b/Swiften/Elements/Whiteboard/WhiteboardTextElement.h new file mode 100644 index 0000000..7118ac9 --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardTextElement.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> + +namespace Swift { + class WhiteboardTextElement : public WhiteboardElement { + public: + typedef boost::shared_ptr<WhiteboardTextElement> ref; + public: + WhiteboardTextElement(int x, int y) { + x_ = x; + y_ = y; + } + + void setText(const std::string text) { + text_ = text; + } + + const std::string& getText() const { + return text_; + } + + int getX() const { + return x_; + } + + int getY() const { + return y_; + } + + const WhiteboardColor& getColor() const { + return color_; + } + + void setColor(const WhiteboardColor& color) { + color_ = color; + } + + int getSize() const { + return size_; + } + + void setSize(const int size) { + size_ = size; + } + + void accept(WhiteboardElementVisitor& visitor) { + visitor.visit(*this); + } + + private: + int x_, y_; + int size_; + std::string text_; + WhiteboardColor color_; + }; +} diff --git a/Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h b/Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h new file mode 100644 index 0000000..a68cc7d --- /dev/null +++ b/Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardOperation.h> + +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> + +namespace Swift { + class WhiteboardUpdateOperation : public WhiteboardOperation { + public: + typedef boost::shared_ptr<WhiteboardUpdateOperation> ref; + public: + WhiteboardElement::ref getElement() const { + return element_; + } + + void setElement(WhiteboardElement::ref element) { + element_ = element; + } + + int getNewPos() const { + return newPos_; + } + + void setNewPos(int newPos) { + newPos_ = newPos; + } + + private: + WhiteboardElement::ref element_; + int newPos_; + }; +} diff --git a/Swiften/Elements/WhiteboardPayload.h b/Swiften/Elements/WhiteboardPayload.h new file mode 100644 index 0000000..ceb2b27 --- /dev/null +++ b/Swiften/Elements/WhiteboardPayload.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardOperation.h> + +namespace Swift { + class WhiteboardPayload : public Payload { + public: + typedef boost::shared_ptr<WhiteboardPayload> ref; + + public: + enum Type {UnknownType, Data, SessionRequest, SessionAccept, SessionTerminate}; + + WhiteboardPayload(Type type = WhiteboardPayload::Data) : type_(type) { + } + + void setData(const std::string &data) { + data_ = data; + } + + std::string getData() const { + return data_; + } + + Type getType() const { + return type_; + } + + void setType(Type type) { + type_ = type; + } + + WhiteboardElement::ref getElement() const { + return element_; + } + + void setElement(WhiteboardElement::ref element) { + element_ = element; + } + + WhiteboardOperation::ref getOperation() const { + return operation_; + } + + void setOperation(WhiteboardOperation::ref operation) { + operation_ = operation; + } + + private: + std::string data_; + Type type_; + WhiteboardElement::ref element_; + WhiteboardOperation::ref operation_; + }; +} diff --git a/Swiften/Entity/Entity.h b/Swiften/Entity/Entity.h index 65480d0..0dc2929 100644 --- a/Swiften/Entity/Entity.h +++ b/Swiften/Entity/Entity.h @@ -7,4 +7,6 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { class PayloadParserFactory; @@ -18,5 +20,5 @@ namespace Swift { * The base class for XMPP entities (Clients, Components). */ - class Entity { + class SWIFTEN_API Entity { public: Entity(); diff --git a/Swiften/Entity/PayloadPersister.cpp b/Swiften/Entity/PayloadPersister.cpp index 729d36a..ace7b4a 100644 --- a/Swiften/Entity/PayloadPersister.cpp +++ b/Swiften/Entity/PayloadPersister.cpp @@ -43,5 +43,5 @@ boost::shared_ptr<Payload> PayloadPersister::loadPayload(const boost::filesystem if (boost::filesystem::exists(path)) { ByteArray data; - readByteArrayFromFile(data, path.string()); + readByteArrayFromFile(data, path); boost::shared_ptr<PayloadParser> parser(createParser()); PayloadParserTester tester(parser.get()); diff --git a/Swiften/Entity/PayloadPersister.h b/Swiften/Entity/PayloadPersister.h index ea7c74c..bc406ab 100644 --- a/Swiften/Entity/PayloadPersister.h +++ b/Swiften/Entity/PayloadPersister.h @@ -10,4 +10,6 @@ #include <boost/filesystem/path.hpp> +#include <Swiften/Base/API.h> + namespace Swift { class Payload; @@ -15,5 +17,5 @@ namespace Swift { class PayloadParser; - class PayloadPersister { + class SWIFTEN_API PayloadPersister { public: PayloadPersister(); diff --git a/Swiften/EventLoop/Cocoa/CocoaEvent.h b/Swiften/EventLoop/Cocoa/CocoaEvent.h index bede7ff..89d056f 100644 --- a/Swiften/EventLoop/Cocoa/CocoaEvent.h +++ b/Swiften/EventLoop/Cocoa/CocoaEvent.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,4 +14,9 @@ namespace Swift { } +// Using deprecated declaration of instance vars in interface, because this +// is required for older runtimes (e.g. 32-bit Mac OS X) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-interface-ivars" + @interface CocoaEvent : NSObject { Swift::Event* event; @@ -19,4 +24,6 @@ namespace Swift { } +#pragma clang diagnostic pop + // Takes ownership of event - (id) initWithEvent: (Swift::Event*) e eventLoop: (Swift::CocoaEventLoop*) el; diff --git a/Swiften/EventLoop/Cocoa/CocoaEvent.mm b/Swiften/EventLoop/Cocoa/CocoaEvent.mm index 049e3b6..7b1b4b0 100644 --- a/Swiften/EventLoop/Cocoa/CocoaEvent.mm +++ b/Swiften/EventLoop/Cocoa/CocoaEvent.mm diff --git a/Swiften/EventLoop/DummyEventLoop.h b/Swiften/EventLoop/DummyEventLoop.h index 4c01c16..0e5e06d 100644 --- a/Swiften/EventLoop/DummyEventLoop.h +++ b/Swiften/EventLoop/DummyEventLoop.h @@ -9,8 +9,9 @@ #include <deque> +#include <Swiften/Base/API.h> #include <Swiften/EventLoop/EventLoop.h> namespace Swift { - class DummyEventLoop : public EventLoop { + class SWIFTEN_API DummyEventLoop : public EventLoop { public: DummyEventLoop(); diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp index afb6858..502bc49 100644 --- a/Swiften/EventLoop/EventLoop.cpp +++ b/Swiften/EventLoop/EventLoop.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,10 +8,14 @@ #include <algorithm> -#include <boost/bind.hpp> #include <iostream> #include <cassert> +#include <boost/bind.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> +#include <boost/thread/locks.hpp> #include <Swiften/Base/Log.h> +namespace lambda = boost::lambda; namespace Swift { @@ -84,5 +88,5 @@ void EventLoop::postEvent(boost::function<void ()> callback, boost::shared_ptr<E void EventLoop::removeEventsFromOwner(boost::shared_ptr<EventOwner> owner) { boost::lock_guard<boost::mutex> lock(eventsMutex_); - events_.remove_if(HasOwner(owner)); + events_.remove_if(lambda::bind(&Event::owner, lambda::_1) == owner); } diff --git a/Swiften/EventLoop/EventLoop.h b/Swiften/EventLoop/EventLoop.h index 9e47112..79ade49 100644 --- a/Swiften/EventLoop/EventLoop.h +++ b/Swiften/EventLoop/EventLoop.h @@ -8,13 +8,15 @@ #include <boost/function.hpp> -#include <boost/thread/mutex.hpp> +#include <boost/thread.hpp> #include <list> #include <deque> +#include <Swiften/Base/API.h> #include <Swiften/EventLoop/Event.h> namespace Swift { class EventOwner; - class EventLoop { + + class SWIFTEN_API EventLoop { public: EventLoop(); @@ -34,9 +36,4 @@ namespace Swift { private: - struct HasOwner { - HasOwner(boost::shared_ptr<EventOwner> owner) : owner(owner) {} - bool operator()(const Event& event) const { return event.owner == owner; } - boost::shared_ptr<EventOwner> owner; - }; boost::mutex eventsMutex_; unsigned int nextEventID_; diff --git a/Swiften/EventLoop/EventOwner.h b/Swiften/EventLoop/EventOwner.h index 4bbd1c4..43a059b 100644 --- a/Swiften/EventLoop/EventOwner.h +++ b/Swiften/EventLoop/EventOwner.h @@ -7,6 +7,8 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { - class EventOwner { + class SWIFTEN_API EventOwner { public: virtual ~EventOwner(); diff --git a/Swiften/EventLoop/SConscript b/Swiften/EventLoop/SConscript index b405f6b..8bef8fb 100644 --- a/Swiften/EventLoop/SConscript +++ b/Swiften/EventLoop/SConscript @@ -13,5 +13,5 @@ objects = swiften_env.SwiftenObject(sources) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) -if swiften_env["PLATFORM"] == "darwin" : +if swiften_env["PLATFORM"] == "darwin" and swiften_env["target"] == "native": myenv = swiften_env.Clone() myenv.Append(CXXFLAGS = myenv["OBJCCFLAGS"]) diff --git a/Swiften/EventLoop/SimpleEventLoop.cpp b/Swiften/EventLoop/SimpleEventLoop.cpp index 63b8ba5..42a5481 100644 --- a/Swiften/EventLoop/SimpleEventLoop.cpp +++ b/Swiften/EventLoop/SimpleEventLoop.cpp @@ -15,6 +15,4 @@ namespace Swift { -void nop() {} - SimpleEventLoop::SimpleEventLoop() : isRunning_(true) { } diff --git a/Swiften/EventLoop/SimpleEventLoop.h b/Swiften/EventLoop/SimpleEventLoop.h index 72bd6a6..da1c039 100644 --- a/Swiften/EventLoop/SimpleEventLoop.h +++ b/Swiften/EventLoop/SimpleEventLoop.h @@ -12,8 +12,9 @@ #include <boost/thread/condition_variable.hpp> +#include <Swiften/Base/API.h> #include <Swiften/EventLoop/EventLoop.h> namespace Swift { - class SimpleEventLoop : public EventLoop { + class SWIFTEN_API SimpleEventLoop : public EventLoop { public: SimpleEventLoop(); diff --git a/Swiften/EventLoop/SingleThreadedEventLoop.cpp b/Swiften/EventLoop/SingleThreadedEventLoop.cpp index 4c5e209..c2235b1 100644 --- a/Swiften/EventLoop/SingleThreadedEventLoop.cpp +++ b/Swiften/EventLoop/SingleThreadedEventLoop.cpp @@ -28,5 +28,5 @@ SingleThreadedEventLoop::~SingleThreadedEventLoop() { void SingleThreadedEventLoop::waitForEvents() { boost::unique_lock<boost::mutex> lock(eventsMutex_); - while (events_.size() == 0 && !shouldShutDown_) { + while (events_.empty() && !shouldShutDown_) { eventsAvailable_.wait(lock); } diff --git a/Swiften/Examples/BenchTool/BenchTool.cpp b/Swiften/Examples/BenchTool/BenchTool.cpp index ba6cf84..9725b7e 100644 --- a/Swiften/Examples/BenchTool/BenchTool.cpp +++ b/Swiften/Examples/BenchTool/BenchTool.cpp @@ -21,11 +21,11 @@ using namespace Swift; -SimpleEventLoop eventLoop; -BoostNetworkFactories networkFactories(&eventLoop); -int numberOfConnectedClients = 0; -int numberOfInstances = 100; +static SimpleEventLoop eventLoop; +static BoostNetworkFactories networkFactories(&eventLoop); +static int numberOfConnectedClients = 0; +static int numberOfInstances = 100; -void handleConnected() { +static void handleConnected() { numberOfConnectedClients++; std::cout << "Connected " << numberOfConnectedClients << std::endl; diff --git a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp index c957481..df2a23d 100644 --- a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp +++ b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp @@ -22,13 +22,13 @@ using namespace Swift; enum ExitCodes {OK = 0, CANNOT_CONNECT, CANNOT_AUTH, NO_RESPONSE, DISCO_ERROR}; -SimpleEventLoop eventLoop; -BoostNetworkFactories networkFactories(&eventLoop); +static SimpleEventLoop eventLoop; +static BoostNetworkFactories networkFactories(&eventLoop); -Client* client = 0; -JID recipient; -int exitCode = CANNOT_CONNECT; -boost::bsignals::connection errorConnection; +static Client* client = 0; +static JID recipient; +static int exitCode = CANNOT_CONNECT; +static boost::bsignals::connection errorConnection; -void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> /*info*/, ErrorPayload::ref error) { +static void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> /*info*/, ErrorPayload::ref error) { if (!error) { errorConnection.disconnect(); @@ -42,5 +42,5 @@ void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> /*info*/, ErrorP } -void handleConnected() { +static void handleConnected() { exitCode = NO_RESPONSE; GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(), client->getIQRouter()); @@ -49,5 +49,5 @@ void handleConnected() { } -void handleDisconnected(const boost::optional<ClientError>&) { +static void handleDisconnected(const boost::optional<ClientError>&) { exitCode = CANNOT_AUTH; eventLoop.stop(); @@ -80,5 +80,7 @@ int main(int argc, char* argv[]) { if (!connectHost.empty()) { std::cout << connectHost << std::endl; - client->connect(connectHost); + ClientOptions options; + options.manualHostname = connectHost; + client->connect(options); } else { std::cout << " Default" << std::endl; diff --git a/Swiften/Examples/ConnectivityTest/SConscript b/Swiften/Examples/ConnectivityTest/SConscript index 7bc3892..55a0821 100644 --- a/Swiften/Examples/ConnectivityTest/SConscript +++ b/Swiften/Examples/ConnectivityTest/SConscript @@ -2,6 +2,6 @@ Import("env") myenv = env.Clone() -myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_DEP_FLAGS"]) tester = myenv.Program("ConnectivityTest", ["ConnectivityTest.cpp"]) diff --git a/Swiften/Examples/LinkLocalTool/SConscript b/Swiften/Examples/LinkLocalTool/SConscript index 8318515..18eb91f 100644 --- a/Swiften/Examples/LinkLocalTool/SConscript +++ b/Swiften/Examples/LinkLocalTool/SConscript @@ -2,14 +2,6 @@ Import("env") myenv = env.Clone() -myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) -myenv.MergeFlags(myenv["BOOST_FLAGS"]) -myenv.MergeFlags(myenv["ZLIB_FLAGS"]) -myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) -myenv.MergeFlags(myenv.get("SQLITE_FLAGS", {})) -myenv.MergeFlags(myenv.get("LIBXML_FLAGS", {})) -myenv.MergeFlags(myenv.get("EXPAT_FLAGS", {})) -myenv.MergeFlags(myenv.get("AVAHI_FLAGS", {})) -myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_DEP_FLAGS"]) linkLocalTool = myenv.Program("LinkLocalTool", [ diff --git a/Swiften/Examples/NetworkTool/main.cpp b/Swiften/Examples/NetworkTool/main.cpp index 00c12d2..77ba3f6 100644 --- a/Swiften/Examples/NetworkTool/main.cpp +++ b/Swiften/Examples/NetworkTool/main.cpp @@ -17,7 +17,7 @@ using namespace Swift; -SimpleEventLoop eventLoop; +static SimpleEventLoop eventLoop; -void handleGetPublicIPRequestResponse(const boost::optional<HostAddress>& result) { +static void handleGetPublicIPRequestResponse(const boost::optional<HostAddress>& result) { if (result) { std::cerr << "Result: " << result->toString() << std::endl;; @@ -29,5 +29,5 @@ void handleGetPublicIPRequestResponse(const boost::optional<HostAddress>& result } -void handleGetForwardPortRequestResponse(const boost::optional<NATPortMapping>& result) { +static void handleGetForwardPortRequestResponse(const boost::optional<NATPortMapping>& result) { if (result) { std::cerr << "Result: " << result->getPublicPort() << " -> " << result->getLocalPort() << std::endl;; @@ -39,6 +39,6 @@ void handleGetForwardPortRequestResponse(const boost::optional<NATPortMapping>& } -void handleRemovePortForwardingRequestResponse(bool result) { - if (result) { +static void handleRemovePortForwardingRequestResponse(const boost::optional<bool> result) { + if (result && result.get()) { std::cerr << "Result: OK" << std::endl; } @@ -59,5 +59,5 @@ int main(int argc, char* argv[]) { boost::shared_ptr<NATTraversalGetPublicIPRequest> query = natTraverser.createGetPublicIPRequest(); query->onResult.connect(boost::bind(&handleGetPublicIPRequestResponse, _1)); - query->run(); + query->start(); eventLoop.run(); } @@ -68,5 +68,5 @@ int main(int argc, char* argv[]) { boost::shared_ptr<NATTraversalForwardPortRequest> query = natTraverser.createForwardPortRequest(boost::lexical_cast<int>(argv[2]), boost::lexical_cast<int>(argv[3])); query->onResult.connect(boost::bind(&handleGetForwardPortRequestResponse, _1)); - query->run(); + query->start(); eventLoop.run(); } @@ -77,5 +77,5 @@ int main(int argc, char* argv[]) { boost::shared_ptr<NATTraversalRemovePortForwardingRequest> query = natTraverser.createRemovePortForwardingRequest(boost::lexical_cast<int>(argv[2]), boost::lexical_cast<int>(argv[3])); query->onResult.connect(boost::bind(&handleRemovePortForwardingRequestResponse, _1)); - query->run(); + query->start(); eventLoop.run(); } diff --git a/Swiften/Examples/ParserTester/ParserTester.cpp b/Swiften/Examples/ParserTester/ParserTester.cpp index 009eef4..5ce44ef 100644 --- a/Swiften/Examples/ParserTester/ParserTester.cpp +++ b/Swiften/Examples/ParserTester/ParserTester.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -22,5 +22,5 @@ class MyXMPPParserClient : public XMPPParserClient { std::cout << "-> Stream start" << std::endl; } - virtual void handleElement(boost::shared_ptr<Element> element) { + virtual void handleElement(boost::shared_ptr<ToplevelElement> element) { std::cout << "-> Element " << typeid(*element.get()).name() << std::endl; } diff --git a/Swiften/Examples/ParserTester/SConscript b/Swiften/Examples/ParserTester/SConscript index e3df0ba..5c93552 100644 --- a/Swiften/Examples/ParserTester/SConscript +++ b/Swiften/Examples/ParserTester/SConscript @@ -2,10 +2,6 @@ Import("env") myenv = env.Clone() -myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) -myenv.MergeFlags(myenv["BOOST_FLAGS"]) -myenv.MergeFlags(myenv.get("LIBXML_FLAGS", "")) -myenv.MergeFlags(myenv.get("EXPAT_FLAGS", "")) -myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_DEP_FLAGS"]) myenv.Program("ParserTester", ["ParserTester.cpp"]) diff --git a/Swiften/Examples/SendFile/ReceiveFile.cpp b/Swiften/Examples/SendFile/ReceiveFile.cpp index f80f03a..c777fee 100644 --- a/Swiften/Examples/SendFile/ReceiveFile.cpp +++ b/Swiften/Examples/SendFile/ReceiveFile.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,4 +11,5 @@ #include <Swiften/Elements/Presence.h> +#include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> #include <Swiften/Client/Client.h> @@ -21,6 +22,4 @@ #include <Swiften/FileTransfer/FileWriteBytestream.h> #include <Swiften/Jingle/JingleSessionManager.h> -#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> #include <Swiften/FileTransfer/FileTransferManager.h> @@ -28,8 +27,8 @@ using namespace Swift; -SimpleEventLoop eventLoop; -BoostNetworkFactories networkFactories(&eventLoop); +static SimpleEventLoop eventLoop; +static BoostNetworkFactories networkFactories(&eventLoop); -int exitCode = 2; +static int exitCode = 2; static const std::string CLIENT_NAME = "Swiften FT Test"; @@ -38,5 +37,5 @@ static const std::string CLIENT_NODE = "http://swift.im"; class FileReceiver { public: - FileReceiver(const JID& jid, const std::string& password) : jid(jid), password(password), jingleSessionManager(NULL), incomingFileTransferManager(NULL) { + FileReceiver(const JID& jid, const std::string& password) : jid(jid), password(password) { client = new Swift::Client(jid, password, &networkFactories); client->onConnected.connect(boost::bind(&FileReceiver::handleConnected, this)); @@ -65,6 +64,5 @@ class FileReceiver { private: void handleConnected() { - Swift::logging = true; - client->getFileTransferManager()->startListeningOnPort(9999); + Log::setLogLevel(Log::debug); client->getFileTransferManager()->onIncomingFileTransfer.connect(boost::bind(&FileReceiver::handleIncomingFileTransfer, this, _1)); @@ -84,7 +82,7 @@ class FileReceiver { SWIFT_LOG(debug) << "foo" << std::endl; incomingFileTransfers.push_back(transfer); - transfer->accept(boost::make_shared<FileWriteBytestream>("out")); - //transfer->onFinished.connect(boost::bind(&FileReceiver::handleFileTransferFinished, this, _1)); - //transfer->start(); + boost::shared_ptr<FileWriteBytestream> out = boost::make_shared<FileWriteBytestream>("out"); + transfer->onFinished.connect(boost::bind(&FileReceiver::handleFileTransferFinished, this, _1, out)); + transfer->accept(out); } @@ -94,7 +92,9 @@ class FileReceiver { } - /* - void handleFileTransferFinished(const boost::optional<FileTransferError>& error) { + void handleFileTransferFinished( + const boost::optional<FileTransferError>& error, + boost::shared_ptr<FileWriteBytestream> out) { std::cout << "File transfer finished" << std::endl; + out->close(); if (error) { exit(-1); @@ -103,5 +103,5 @@ class FileReceiver { exit(0); } - }*/ + } void exit(int code) { @@ -116,10 +116,5 @@ class FileReceiver { Client* client; ClientXMLTracer* tracer; - JingleSessionManager* jingleSessionManager; - IncomingFileTransferManager* incomingFileTransferManager; std::vector<IncomingFileTransfer::ref> incomingFileTransfers; - DefaultLocalJingleTransportCandidateGeneratorFactory *localFactory; - DefaultRemoteJingleTransportCandidateSelectorFactory *remoteFactory; - SOCKS5BytestreamRegistry* bytestreamRegistry; }; diff --git a/Swiften/Examples/SendFile/SConscript b/Swiften/Examples/SendFile/SConscript index d335513..e0f1256 100644 --- a/Swiften/Examples/SendFile/SConscript +++ b/Swiften/Examples/SendFile/SConscript @@ -2,6 +2,6 @@ Import("env") myenv = env.Clone() -myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_DEP_FLAGS"]) myenv.Program("SendFile", ["SendFile.cpp"]) diff --git a/Swiften/Examples/SendFile/SendFile.cpp b/Swiften/Examples/SendFile/SendFile.cpp index df3cea4..b056842 100644 --- a/Swiften/Examples/SendFile/SendFile.cpp +++ b/Swiften/Examples/SendFile/SendFile.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,4 +12,5 @@ #include <Swiften/Client/Client.h> #include <Swiften/Elements/Presence.h> +#include <Swiften/Base/Log.h> #include <Swiften/Network/BoostTimer.h> #include <Swiften/Network/TimerFactory.h> @@ -26,9 +27,5 @@ #include <Swiften/Jingle/JingleSessionManager.h> #include <Swiften/Disco/EntityCapsManager.h> -#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h> #include <Swiften/Base/ByteArray.h> -#include <Swiften/StringCodecs/MD5.h> -#include <Swiften/StringCodecs/SHA1.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/FileTransfer/FileTransferManager.h> @@ -36,8 +33,8 @@ using namespace Swift; -SimpleEventLoop eventLoop; -BoostNetworkFactories networkFactories(&eventLoop); +static SimpleEventLoop eventLoop; +static BoostNetworkFactories networkFactories(&eventLoop); -int exitCode = 2; +static int exitCode = 2; class FileSender { @@ -67,7 +64,6 @@ class FileSender { client->sendPresence(Presence::create()); - client->getFileTransferManager()->startListeningOnPort(19999); //ByteArray fileData; - //readByteArrayFromFile(fileData, file.string()); + //readByteArrayFromFile(fileData, file); // gather file information @@ -126,6 +122,4 @@ class FileSender { private: BoostConnectionServer::ref connectionServer; - SOCKS5BytestreamServer* socksBytestreamServer; - SOCKS5BytestreamRegistry* registry; OutgoingFileTransfer::ref outgoingFileTransfer; JID jid; @@ -146,5 +140,5 @@ int main(int argc, char* argv[]) { JID sender(argv[1]); JID recipient(argv[3]); - Swift::logging = true; + Log::setLogLevel(Log::debug); FileSender fileSender(sender, std::string(argv[2]), recipient, boost::filesystem::path(argv[4])); fileSender.start(); diff --git a/Swiften/Examples/SendMessage/SConscript b/Swiften/Examples/SendMessage/SConscript index 8907d25..0466187 100644 --- a/Swiften/Examples/SendMessage/SConscript +++ b/Swiften/Examples/SendMessage/SConscript @@ -2,6 +2,6 @@ Import("env") myenv = env.Clone() -myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_FLAGS"]) +myenv.UseFlags(myenv["SWIFTEN_DEP_FLAGS"]) tester = myenv.Program("SendMessage", ["SendMessage.cpp"]) diff --git a/Swiften/Examples/SendMessage/SendMessage.cpp b/Swiften/Examples/SendMessage/SendMessage.cpp index f4dbf53..2a3170f 100644 --- a/Swiften/Examples/SendMessage/SendMessage.cpp +++ b/Swiften/Examples/SendMessage/SendMessage.cpp @@ -19,15 +19,15 @@ using namespace Swift; -SimpleEventLoop eventLoop; -BoostNetworkFactories networkFactories(&eventLoop); +static SimpleEventLoop eventLoop; +static BoostNetworkFactories networkFactories(&eventLoop); -Client* client = 0; -JID recipient; -std::string messageBody; -int exitCode = 2; -boost::bsignals::connection errorConnection; +static Client* client = 0; +static JID recipient; +static std::string messageBody; +static int exitCode = 2; +static boost::bsignals::connection errorConnection; -void handleConnected() { +static void handleConnected() { boost::shared_ptr<Message> message(new Message()); message->setBody(messageBody); @@ -40,5 +40,5 @@ void handleConnected() { } -void handleDisconnected(const boost::optional<ClientError>&) { +static void handleDisconnected(const boost::optional<ClientError>&) { std::cerr << "Error!" << std::endl; exitCode = 1; @@ -70,5 +70,7 @@ int main(int argc, char* argv[]) { errorConnection = client->onDisconnected.connect(&handleDisconnected); if (!connectHost.empty()) { - client->connect(connectHost); + ClientOptions options; + options.manualHostname = connectHost; + client->connect(options); } else { client->connect(); diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.cpp b/Swiften/FileTransfer/ByteArrayReadBytestream.cpp new file mode 100644 index 0000000..4ba791f --- /dev/null +++ b/Swiften/FileTransfer/ByteArrayReadBytestream.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/ByteArrayReadBytestream.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <Swiften/Base/Algorithm.h> + +using namespace Swift; + +boost::shared_ptr<ByteArray> ByteArrayReadBytestream::read(size_t size) { + size_t readSize = size; + if (position + readSize > data.size()) { + readSize = data.size() - position; + } + boost::shared_ptr<ByteArray> result = boost::make_shared<ByteArray>( + data.begin() + boost::numeric_cast<long long>(position), + data.begin() + boost::numeric_cast<long long>(position) + boost::numeric_cast<long long>(readSize)); + + onRead(*result); + position += readSize; + return result; +} + +void ByteArrayReadBytestream::addData(const std::vector<unsigned char>& moreData) { + append(data, moreData); + onDataAvailable(); +} diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.h b/Swiften/FileTransfer/ByteArrayReadBytestream.h index 9311099..664698a 100644 --- a/Swiften/FileTransfer/ByteArrayReadBytestream.h +++ b/Swiften/FileTransfer/ByteArrayReadBytestream.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,7 +8,5 @@ #include <vector> -#include <boost/smart_ptr/make_shared.hpp> -#include <Swiften/Base/Algorithm.h> #include <Swiften/FileTransfer/ReadBytestream.h> #include <Swiften/Base/ByteArray.h> @@ -20,15 +18,5 @@ namespace Swift { } - virtual boost::shared_ptr<ByteArray> read(size_t size) { - size_t readSize = size; - if (position + readSize > data.size()) { - readSize = data.size() - position; - } - boost::shared_ptr<ByteArray> result = boost::make_shared<ByteArray>(data.begin() + position, data.begin() + position + readSize); - - onRead(*result); - position += readSize; - return result; - } + virtual boost::shared_ptr<ByteArray> read(size_t size); virtual bool isFinished() const { @@ -40,8 +28,5 @@ namespace Swift { } - void addData(const std::vector<unsigned char>& moreData) { - append(data, moreData); - onDataAvailable(); - } + void addData(const std::vector<unsigned char>& moreData); private: diff --git a/Swiften/FileTransfer/ConnectivityManager.cpp b/Swiften/FileTransfer/ConnectivityManager.cpp deleted file mode 100644 index 7d25991..0000000 --- a/Swiften/FileTransfer/ConnectivityManager.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "ConnectivityManager.h" - -#include <boost/bind.hpp> - -#include <Swiften/Base/foreach.h> -#include <Swiften/Base/Log.h> -#include <Swiften/Network/NetworkInterface.h> -#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> -#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> -#include <Swiften/Network/NATTraverser.h> -#include <Swiften/Network/PlatformNetworkEnvironment.h> - -namespace Swift { - -ConnectivityManager::ConnectivityManager(NATTraverser* worker) : natTraversalWorker(worker) { - -} - -ConnectivityManager::~ConnectivityManager() { - std::set<int> leftOpenPorts = ports; - foreach(int port, leftOpenPorts) { - removeListeningPort(port); - } -} - -void ConnectivityManager::addListeningPort(int port) { - ports.insert(port); - boost::shared_ptr<NATTraversalGetPublicIPRequest> getIPRequest = natTraversalWorker->createGetPublicIPRequest(); - if (getIPRequest) { - getIPRequest->onResult.connect(boost::bind(&ConnectivityManager::natTraversalGetPublicIPResult, this, _1)); - getIPRequest->run(); - } - - boost::shared_ptr<NATTraversalForwardPortRequest> forwardPortRequest = natTraversalWorker->createForwardPortRequest(port, port); - if (forwardPortRequest) { - forwardPortRequest->onResult.connect(boost::bind(&ConnectivityManager::natTraversalForwardPortResult, this, _1)); - forwardPortRequest->run(); - } -} - -void ConnectivityManager::removeListeningPort(int port) { - SWIFT_LOG(debug) << "remove listening port " << port << std::endl; - ports.erase(port); - boost::shared_ptr<NATTraversalRemovePortForwardingRequest> removePortForwardingRequest = natTraversalWorker->createRemovePortForwardingRequest(port, port); - if (removePortForwardingRequest) { - removePortForwardingRequest->run(); - } -} - -std::vector<HostAddressPort> ConnectivityManager::getHostAddressPorts() const { - PlatformNetworkEnvironment env; - std::vector<HostAddressPort> results; - - std::vector<HostAddress> addresses; - - std::vector<NetworkInterface> networkInterfaces; - foreach (const NetworkInterface& iface, networkInterfaces) { - foreach (const HostAddress& address, iface.getAddresses()) { - foreach (int port, ports) { - results.push_back(HostAddressPort(address, port)); - } - } - } - - return results; -} - -std::vector<HostAddressPort> ConnectivityManager::getAssistedHostAddressPorts() const { - std::vector<HostAddressPort> results; - - if (publicAddress) { - foreach (int port, ports) { - results.push_back(HostAddressPort(publicAddress.get(), port)); - } - } - - return results; -} - -void ConnectivityManager::natTraversalGetPublicIPResult(boost::optional<HostAddress> address) { - if (address) { - publicAddress = address; - SWIFT_LOG(debug) << "Public IP discovered as " << publicAddress.get().toString() << "." << std::endl; - } else { - SWIFT_LOG(debug) << "No public IP discoverable." << std::endl; - } -} - -void ConnectivityManager::natTraversalForwardPortResult(boost::optional<NATPortMapping> mapping) { - if (mapping) { - SWIFT_LOG(debug) << "Mapping port was successful." << std::endl; - } else { - SWIFT_LOG(debug) << "Mapping port has failed." << std::endl; - } -} - - -} diff --git a/Swiften/FileTransfer/ConnectivityManager.h b/Swiften/FileTransfer/ConnectivityManager.h deleted file mode 100644 index c094c02..0000000 --- a/Swiften/FileTransfer/ConnectivityManager.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <vector> -#include <set> - -#include <boost/optional.hpp> - -#include <Swiften/Network/HostAddressPort.h> -#include <Swiften/Network/NATTraverser.h> -#include <Swiften/Network/NATTraversalForwardPortRequest.h> -#include <Swiften/Network/NATPortMapping.h> - -namespace Swift { - -class NATTraverser; - -class ConnectivityManager { -public: - ConnectivityManager(NATTraverser*); - ~ConnectivityManager(); -public: - void addListeningPort(int port); - void removeListeningPort(int port); - - std::vector<HostAddressPort> getHostAddressPorts() const; - std::vector<HostAddressPort> getAssistedHostAddressPorts() const; - -private: - void natTraversalGetPublicIPResult(boost::optional<HostAddress> address); - void natTraversalForwardPortResult(boost::optional<NATPortMapping> mapping); - -private: - NATTraverser* natTraversalWorker; - - std::set<int> ports; - boost::optional<HostAddress> publicAddress; -}; - -} diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp new file mode 100644 index 0000000..af87fd2 --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/DefaultFileTransferTransporter.h> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/FileTransfer/IBBSendSession.h> +#include <Swiften/FileTransfer/IBBReceiveSession.h> +#include <Swiften/FileTransfer/TransportSession.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Queries/GenericRequest.h> + +using namespace Swift; + +namespace { + class IBBSendTransportSession : public TransportSession { + public: + IBBSendTransportSession(boost::shared_ptr<IBBSendSession> session) : session(session) { + finishedConnection = session->onFinished.connect(boost::bind(boost::ref(onFinished), _1)); + bytesSentConnection = session->onBytesSent.connect(boost::bind(boost::ref(onBytesSent), _1)); + } + + virtual void start() SWIFTEN_OVERRIDE { + session->start(); + } + + virtual void stop() SWIFTEN_OVERRIDE { + session->stop(); + } + + private: + boost::shared_ptr<IBBSendSession> session; + boost::bsignals::scoped_connection finishedConnection; + boost::bsignals::scoped_connection bytesSentConnection; + }; + + class IBBReceiveTransportSession : public TransportSession { + public: + IBBReceiveTransportSession(boost::shared_ptr<IBBReceiveSession> session) : session(session) { + finishedConnection = session->onFinished.connect(boost::bind(boost::ref(onFinished), _1)); + } + + virtual void start() SWIFTEN_OVERRIDE { + session->start(); + } + + virtual void stop() SWIFTEN_OVERRIDE { + session->stop(); + } + + private: + boost::shared_ptr<IBBReceiveSession> session; + boost::bsignals::scoped_connection finishedConnection; + boost::bsignals::scoped_connection bytesSentConnection; + }; + + class FailingTransportSession : public TransportSession { + public: + virtual void start() SWIFTEN_OVERRIDE { + onFinished(FileTransferError(FileTransferError::PeerError)); + } + + virtual void stop() SWIFTEN_OVERRIDE { + } + }; + + template <typename T> + class S5BTransportSession : public TransportSession { + public: + S5BTransportSession( + boost::shared_ptr<T> session, + boost::shared_ptr<ReadBytestream> readStream) : + session(session), + readStream(readStream) { + initialize(); + } + + S5BTransportSession( + boost::shared_ptr<T> session, + boost::shared_ptr<WriteBytestream> writeStream) : + session(session), + writeStream(writeStream) { + initialize(); + } + + virtual void start() SWIFTEN_OVERRIDE { + if (readStream) { + session->startSending(readStream); + } + else { + session->startReceiving(writeStream); + } + } + + virtual void stop() SWIFTEN_OVERRIDE { + session->stop(); + } + + private: + void initialize() { + finishedConnection = session->onFinished.connect(boost::bind(boost::ref(onFinished), _1)); + bytesSentConnection = session->onBytesSent.connect(boost::bind(boost::ref(onBytesSent), _1)); + } + + private: + boost::shared_ptr<T> session; + boost::shared_ptr<ReadBytestream> readStream; + boost::shared_ptr<WriteBytestream> writeStream; + + boost::bsignals::scoped_connection finishedConnection; + boost::bsignals::scoped_connection bytesSentConnection; + }; +} + +DefaultFileTransferTransporter::DefaultFileTransferTransporter( + const JID& initiator, + const JID& responder, + Role role, + SOCKS5BytestreamRegistry* s5bRegistry, + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + IDGenerator* idGenerator, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + CryptoProvider* crypto, + IQRouter* router) : + initiator(initiator), + responder(responder), + role(role), + s5bRegistry(s5bRegistry), + s5bServerManager(s5bServerManager), + crypto(crypto), + router(router) { + + localCandidateGenerator = new LocalJingleTransportCandidateGenerator( + s5bServerManager, + s5bProxy, + role == Initiator ? initiator : responder, + idGenerator); + localCandidateGenerator->onLocalTransportCandidatesGenerated.connect( + boost::bind(&DefaultFileTransferTransporter::handleLocalCandidatesGenerated, this, _1)); + + remoteCandidateSelector = new RemoteJingleTransportCandidateSelector( + connectionFactory, + timerFactory); + remoteCandidateSelector->onCandidateSelectFinished.connect( + boost::bind(&DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished, this, _1, _2)); +} + +DefaultFileTransferTransporter::~DefaultFileTransferTransporter() { + delete remoteCandidateSelector; + delete localCandidateGenerator; +} + +void DefaultFileTransferTransporter::initialize() { + s5bSessionID = s5bRegistry->generateSessionID(); +} + +void DefaultFileTransferTransporter::initialize(const std::string& s5bSessionID) { + this->s5bSessionID = s5bSessionID; +} + +void DefaultFileTransferTransporter::startGeneratingLocalCandidates() { + localCandidateGenerator->start(); +} + +void DefaultFileTransferTransporter::stopGeneratingLocalCandidates() { + localCandidateGenerator->stop(); +} + +void DefaultFileTransferTransporter::handleLocalCandidatesGenerated( + const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), true); + onLocalCandidatesGenerated(s5bSessionID, candidates); +} + +void DefaultFileTransferTransporter::handleRemoteCandidateSelectFinished( + const boost::optional<JingleS5BTransportPayload::Candidate>& candidate, + boost::shared_ptr<SOCKS5BytestreamClientSession> session) { + remoteS5BClientSession = session; + onRemoteCandidateSelectFinished(s5bSessionID, candidate); +} + + +void DefaultFileTransferTransporter::addRemoteCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + remoteCandidateSelector->setSOCKS5DstAddr(getSOCKS5DstAddr()); + remoteCandidateSelector->addCandidates(candidates); +} + +void DefaultFileTransferTransporter::startTryingRemoteCandidates() { + remoteCandidateSelector->startSelectingCandidate(); +} + +void DefaultFileTransferTransporter::stopTryingRemoteCandidates() { + remoteCandidateSelector->stopSelectingCandidate(); +} + +void DefaultFileTransferTransporter::startActivatingProxy(const JID&) { + // TODO + assert(false); + /* + S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); + proxyRequest->setSID(s5bSessionID); + proxyRequest->setActivate(getTarget()); + + boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxy, proxyRequest, router); + request->onResponse.connect(boost::bind(&OutgoingJingleFileTransfer::handleActivateProxySessionResult, this, _1, _2)); + request->send(); + */ +} + +void DefaultFileTransferTransporter::stopActivatingProxy() { + // TODO + assert(false); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createIBBSendSession( + const std::string& sessionID, unsigned int blockSize, boost::shared_ptr<ReadBytestream> stream) { + closeLocalSession(); + closeRemoteSession(); + boost::shared_ptr<IBBSendSession> ibbSession = boost::make_shared<IBBSendSession>( + sessionID, initiator, responder, stream, router); + ibbSession->setBlockSize(blockSize); + return boost::make_shared<IBBSendTransportSession>(ibbSession); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createIBBReceiveSession( + const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream> stream) { + closeLocalSession(); + closeRemoteSession(); + boost::shared_ptr<IBBReceiveSession> ibbSession = boost::make_shared<IBBReceiveSession>( + sessionID, initiator, responder, size, stream, router); + return boost::make_shared<IBBReceiveTransportSession>(ibbSession); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createRemoteCandidateSession( + boost::shared_ptr<ReadBytestream> stream) { + closeLocalSession(); + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >( + remoteS5BClientSession, stream); +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createRemoteCandidateSession( + boost::shared_ptr<WriteBytestream> stream) { + closeLocalSession(); + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamClientSession> >( + remoteS5BClientSession, stream); +} + +boost::shared_ptr<SOCKS5BytestreamServerSession> DefaultFileTransferTransporter::getServerSession() { + s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), false); + std::vector<boost::shared_ptr<SOCKS5BytestreamServerSession> > serverSessions = + s5bServerManager->getServer()->getSessions(getSOCKS5DstAddr()); + while (serverSessions.size() > 1) { + boost::shared_ptr<SOCKS5BytestreamServerSession> session = serverSessions.back(); + serverSessions.pop_back(); + session->stop(); + } + return !serverSessions.empty() ? serverSessions.front() : boost::shared_ptr<SOCKS5BytestreamServerSession>(); +} + + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCandidateSession( + boost::shared_ptr<ReadBytestream> stream) { + closeRemoteSession(); + boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession(); + if (serverSession) { + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream); + } + else { + return boost::make_shared<FailingTransportSession>(); + } +} + +boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createLocalCandidateSession( + boost::shared_ptr<WriteBytestream> stream) { + closeRemoteSession(); + boost::shared_ptr<SOCKS5BytestreamServerSession> serverSession = getServerSession(); + if (serverSession) { + return boost::make_shared<S5BTransportSession<SOCKS5BytestreamServerSession> >(serverSession, stream); + } + else { + return boost::make_shared<FailingTransportSession>(); + } +} + +std::string DefaultFileTransferTransporter::getSOCKS5DstAddr() const { + return Hexify::hexify(crypto->getSHA1Hash( + createSafeByteArray(s5bSessionID + initiator.toString() + initiator.toString()))); +} + +void DefaultFileTransferTransporter::closeLocalSession() { + s5bRegistry->setHasBytestream(getSOCKS5DstAddr(), false); + std::vector<boost::shared_ptr<SOCKS5BytestreamServerSession> > serverSessions = + s5bServerManager->getServer()->getSessions(getSOCKS5DstAddr()); + foreach(boost::shared_ptr<SOCKS5BytestreamServerSession> session, serverSessions) { + session->stop(); + } +} + +void DefaultFileTransferTransporter::closeRemoteSession() { + if (remoteS5BClientSession) { + remoteS5BClientSession->stop(); + remoteS5BClientSession.reset(); + } +} diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.h b/Swiften/FileTransfer/DefaultFileTransferTransporter.h new file mode 100644 index 0000000..ef982c0 --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/FileTransfer/FileTransferTransporter.h> + +namespace Swift { + class LocalJingleTransportCandidateGenerator; + class RemoteJingleTransportCandidateSelector; + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamServerManager; + class SOCKS5BytestreamProxiesManager; + class SOCKS5BytestreamClientSession; + class SOCKS5BytestreamServerSession; + class IDGenerator; + class IQRouter; + class ReadBytestream; + class WriteBytestream; + class ConnectionFactory; + class TimerFactory; + class CryptoProvider; + + class SWIFTEN_API DefaultFileTransferTransporter : public FileTransferTransporter { + public: + enum Role { + Initiator, + Responder + }; + + DefaultFileTransferTransporter( + const JID& initiator, + const JID& responder, + Role role, + SOCKS5BytestreamRegistry*, + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + IDGenerator* idGenerator, + ConnectionFactory*, + TimerFactory*, + CryptoProvider*, + IQRouter*); + virtual ~DefaultFileTransferTransporter(); + + + virtual void initialize(); + virtual void initialize(const std::string& s5bSessionID); + + virtual void startGeneratingLocalCandidates() SWIFTEN_OVERRIDE; + virtual void stopGeneratingLocalCandidates() SWIFTEN_OVERRIDE; + + virtual void addRemoteCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE; + virtual void startTryingRemoteCandidates() SWIFTEN_OVERRIDE; + virtual void stopTryingRemoteCandidates() SWIFTEN_OVERRIDE; + + virtual void startActivatingProxy(const JID& jid); + virtual void stopActivatingProxy(); + + virtual boost::shared_ptr<TransportSession> createIBBSendSession( + const std::string& sessionID, unsigned int blockSize, boost::shared_ptr<ReadBytestream>) SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createIBBReceiveSession( + const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream>) SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession( + boost::shared_ptr<ReadBytestream>) SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession( + boost::shared_ptr<WriteBytestream>) SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<ReadBytestream>) SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<WriteBytestream>) SWIFTEN_OVERRIDE; + + private: + void handleLocalCandidatesGenerated(const std::vector<JingleS5BTransportPayload::Candidate>&); + void handleRemoteCandidateSelectFinished( + const boost::optional<JingleS5BTransportPayload::Candidate>&, + boost::shared_ptr<SOCKS5BytestreamClientSession>); + std::string getSOCKS5DstAddr() const; + void closeLocalSession(); + void closeRemoteSession(); + boost::shared_ptr<SOCKS5BytestreamServerSession> getServerSession(); + + private: + JID initiator; + JID responder; + Role role; + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamServerManager* s5bServerManager; + CryptoProvider* crypto; + IQRouter* router; + LocalJingleTransportCandidateGenerator* localCandidateGenerator; + RemoteJingleTransportCandidateSelector* remoteCandidateSelector; + std::string s5bSessionID; + boost::shared_ptr<SOCKS5BytestreamClientSession> remoteS5BClientSession; + }; +} + diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.cpp b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.cpp new file mode 100644 index 0000000..4c8a55e --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h> + +#include <Swiften/FileTransfer/DefaultFileTransferTransporter.h> + +using namespace Swift; + +DefaultFileTransferTransporterFactory::DefaultFileTransferTransporterFactory( + SOCKS5BytestreamRegistry* s5bRegistry, + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxiesManager, + IDGenerator* idGenerator, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + CryptoProvider* cryptoProvider, + IQRouter* iqRouter) : + s5bRegistry(s5bRegistry), + s5bServerManager(s5bServerManager), + s5bProxiesManager(s5bProxiesManager), + idGenerator(idGenerator), + connectionFactory(connectionFactory), + timerFactory(timerFactory), + cryptoProvider(cryptoProvider), + iqRouter(iqRouter) +{ +} + +DefaultFileTransferTransporterFactory::~DefaultFileTransferTransporterFactory() { +} + +FileTransferTransporter* DefaultFileTransferTransporterFactory::createInitiatorTransporter( + const JID& initiator, const JID& responder) { + DefaultFileTransferTransporter* transporter = new DefaultFileTransferTransporter( + initiator, + responder, + DefaultFileTransferTransporter::Initiator, + s5bRegistry, + s5bServerManager, + s5bProxiesManager, + idGenerator, + connectionFactory, + timerFactory, + cryptoProvider, + iqRouter); + transporter->initialize(); + return transporter; +} + +FileTransferTransporter* DefaultFileTransferTransporterFactory::createResponderTransporter( + const JID& initiator, const JID& responder, const std::string& s5bSessionID) { + DefaultFileTransferTransporter* transporter = new DefaultFileTransferTransporter( + initiator, + responder, + DefaultFileTransferTransporter::Initiator, + s5bRegistry, + s5bServerManager, + s5bProxiesManager, + idGenerator, + connectionFactory, + timerFactory, + cryptoProvider, + iqRouter); + transporter->initialize(s5bSessionID); + return transporter; +} diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h new file mode 100644 index 0000000..b5e8f95 --- /dev/null +++ b/Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> + +namespace Swift { + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamServerManager; + class SOCKS5BytestreamProxiesManager; + class IDGenerator; + class ConnectionFactory; + class TimerFactory; + class CryptoProvider; + class IQRouter; + + class SWIFTEN_API DefaultFileTransferTransporterFactory : public FileTransferTransporterFactory { + public: + DefaultFileTransferTransporterFactory( + SOCKS5BytestreamRegistry*, + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + IDGenerator* idGenerator, + ConnectionFactory*, + TimerFactory*, + CryptoProvider*, + IQRouter*); + virtual ~DefaultFileTransferTransporterFactory(); + + virtual FileTransferTransporter* createInitiatorTransporter( + const JID& initiator, const JID& responder) SWIFTEN_OVERRIDE; + virtual FileTransferTransporter* createResponderTransporter( + const JID& initiator, const JID& responder, const std::string& s5bSessionID) SWIFTEN_OVERRIDE; + + private: + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamServerManager* s5bServerManager; + SOCKS5BytestreamProxiesManager* s5bProxiesManager; + IDGenerator* idGenerator; + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; + CryptoProvider* cryptoProvider; + IQRouter* iqRouter; + }; +} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp deleted file mode 100644 index 4b205cb..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultLocalJingleTransportCandidateGenerator.h" - -#include <vector> - -#include <boost/shared_ptr.hpp> -#include <boost/smart_ptr/make_shared.hpp> - -#include <Swiften/Base/foreach.h> -#include <Swiften/Base/Log.h> -#include <Swiften/Elements/JingleIBBTransportPayload.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/FileTransfer/ConnectivityManager.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> - -namespace Swift { - -DefaultLocalJingleTransportCandidateGenerator::DefaultLocalJingleTransportCandidateGenerator(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, JID& ownJID) : connectivityManager(connectivityManager), s5bRegistry(s5bRegistry), s5bProxy(s5bProxy), ownJID(ownJID) { -} - -DefaultLocalJingleTransportCandidateGenerator::~DefaultLocalJingleTransportCandidateGenerator() { -} - -void DefaultLocalJingleTransportCandidateGenerator::generateLocalTransportCandidates(JingleTransportPayload::ref transportPayload) { - if (boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transportPayload)) { - JingleTransportPayload::ref payL = boost::make_shared<JingleTransportPayload>(); - payL->setSessionID(transportPayload->getSessionID()); - onLocalTransportCandidatesGenerated(payL); - } - if (boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload)) { - JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); - payL->setSessionID(transportPayload->getSessionID()); - payL->setMode(JingleS5BTransportPayload::TCPMode); - - const unsigned long localPreference = 0; - - // get direct candidates - std::vector<HostAddressPort> directCandidates = connectivityManager->getHostAddressPorts(); - foreach(HostAddressPort addressPort, directCandidates) { - JingleS5BTransportPayload::Candidate candidate; - candidate.type = JingleS5BTransportPayload::Candidate::DirectType; - candidate.jid = ownJID; - candidate.hostPort = addressPort; - candidate.priority = 65536 * 126 + localPreference; - candidate.cid = idGenerator.generateID(); - payL->addCandidate(candidate); - } - - // get assissted candidates - std::vector<HostAddressPort> assisstedCandidates = connectivityManager->getAssistedHostAddressPorts(); - foreach(HostAddressPort addressPort, assisstedCandidates) { - JingleS5BTransportPayload::Candidate candidate; - candidate.type = JingleS5BTransportPayload::Candidate::AssistedType; - candidate.jid = ownJID; - candidate.hostPort = addressPort; - candidate.priority = 65536 * 120 + localPreference; - candidate.cid = idGenerator.generateID(); - payL->addCandidate(candidate); - } - - // get proxy candidates - std::vector<S5BProxyRequest::ref> proxyCandidates = s5bProxy->getS5BProxies(); - foreach(S5BProxyRequest::ref proxy, proxyCandidates) { - if (proxy->getStreamHost()) { // FIXME: Added this test, because there were cases where this wasn't initialized. Investigate this. (Remko) - JingleS5BTransportPayload::Candidate candidate; - candidate.type = JingleS5BTransportPayload::Candidate::ProxyType; - candidate.jid = (*proxy->getStreamHost()).jid; - candidate.hostPort = (*proxy->getStreamHost()).addressPort; - candidate.priority = 65536 * 10 + localPreference; - candidate.cid = idGenerator.generateID(); - payL->addCandidate(candidate); - } - } - - onLocalTransportCandidatesGenerated(payL); - } - -} - -bool DefaultLocalJingleTransportCandidateGenerator::isActualCandidate(JingleTransportPayload::ref transportPayload) { - if (!transportPayload.get()) return false; - return false; -} - -int DefaultLocalJingleTransportCandidateGenerator::getPriority(JingleTransportPayload::ref /* transportPayload */) { - return 0; -} - -JingleTransport::ref DefaultLocalJingleTransportCandidateGenerator::selectTransport(JingleTransportPayload::ref /* transportPayload */) { - return JingleTransport::ref(); -} - -} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h deleted file mode 100644 index 7d45491..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> - -#include <Swiften/Base/IDGenerator.h> -#include <Swiften/JID/JID.h> - -namespace Swift { - -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; -class ConnectivityManager; - -class DefaultLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { -public: - DefaultLocalJingleTransportCandidateGenerator(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, JID& ownJID); - virtual ~DefaultLocalJingleTransportCandidateGenerator(); - - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref); - - virtual bool isActualCandidate(JingleTransportPayload::ref); - virtual int getPriority(JingleTransportPayload::ref); - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref); - -private: - IDGenerator idGenerator; - ConnectivityManager* connectivityManager; - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - JID ownJID; -}; - -} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp deleted file mode 100644 index ed0386e..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultLocalJingleTransportCandidateGeneratorFactory.h" - -#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h> -#include <Swiften/Base/Log.h> - -namespace Swift { - -DefaultLocalJingleTransportCandidateGeneratorFactory::DefaultLocalJingleTransportCandidateGeneratorFactory(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, const JID& ownJID) : connectivityManager(connectivityManager), s5bRegistry(s5bRegistry), s5bProxy(s5bProxy), ownJID(ownJID) { -} - -DefaultLocalJingleTransportCandidateGeneratorFactory::~DefaultLocalJingleTransportCandidateGeneratorFactory() { -} - -LocalJingleTransportCandidateGenerator* DefaultLocalJingleTransportCandidateGeneratorFactory::createCandidateGenerator() { - return new DefaultLocalJingleTransportCandidateGenerator(connectivityManager, s5bRegistry, s5bProxy, ownJID); -} - - -} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h deleted file mode 100644 index 511d0a1..0000000 --- a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> - -#include <Swiften/JID/JID.h> - -namespace Swift { - -class ConnectivityManager; -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; - -class DefaultLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory{ -public: - DefaultLocalJingleTransportCandidateGeneratorFactory(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, const JID& ownJID); - virtual ~DefaultLocalJingleTransportCandidateGeneratorFactory(); - - LocalJingleTransportCandidateGenerator* createCandidateGenerator(); - -private: - ConnectivityManager* connectivityManager; - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - JID ownJID; -}; - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp deleted file mode 100644 index 32b4df8..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultRemoteJingleTransportCandidateSelector.h" - -#include <boost/smart_ptr/make_shared.hpp> -#include <boost/bind.hpp> - -#include <Swiften/Base/Log.h> -#include <Swiften/Base/boost_bsignals.h> -#include <Swiften/Base/foreach.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/Network/ConnectionFactory.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> - -namespace Swift { - -DefaultRemoteJingleTransportCandidateSelector::DefaultRemoteJingleTransportCandidateSelector(ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : connectionFactory(connectionFactory), timerFactory(timerFactory) { -} - -DefaultRemoteJingleTransportCandidateSelector::~DefaultRemoteJingleTransportCandidateSelector() { -} - -void DefaultRemoteJingleTransportCandidateSelector::addRemoteTransportCandidates(JingleTransportPayload::ref transportPayload) { - JingleS5BTransportPayload::ref s5bPayload; - transportSID = transportPayload->getSessionID(); - if ((s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload))) { - foreach(JingleS5BTransportPayload::Candidate c, s5bPayload->getCandidates()) { - candidates.push(c); - } - } -} - -void DefaultRemoteJingleTransportCandidateSelector::selectCandidate() { - tryNextCandidate(true); -} - -void DefaultRemoteJingleTransportCandidateSelector::tryNextCandidate(bool error) { - if (error) { - if (s5bSession) { - SWIFT_LOG(debug) << "failed to connect" << std::endl; - } - if (candidates.empty()) { - // failed to connect to any of the candidates - // issue an error - SWIFT_LOG(debug) << "out of candidates )=" << std::endl; - JingleS5BTransportPayload::ref failed = boost::make_shared<JingleS5BTransportPayload>(); - failed->setCandidateError(true); - failed->setSessionID(transportSID); - onRemoteTransportCandidateSelectFinished(failed); - } else { - lastCandidate = candidates.top(); - // only try direct or assisted for now - if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType || - lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType || lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType ) { - // create connection - connection = connectionFactory->createConnection(); - s5bSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, lastCandidate.hostPort, SOCKS5BytestreamRegistry::getHostname(transportSID, requester, target), timerFactory); - - // bind onReady to this method - s5bSession->onSessionReady.connect(boost::bind(&DefaultRemoteJingleTransportCandidateSelector::tryNextCandidate, this, _1)); - - std::string candidateType; - if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType) { - candidateType = "direct"; - } else if (lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType) { - candidateType = "assisted"; - } else if (lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - candidateType = "proxy"; - } - - // initiate connect - SWIFT_LOG(debug) << "try to connect to candidate of type " << candidateType << " : " << lastCandidate.hostPort.toString() << std::endl; - s5bSession->start(); - - // that's it. we're gonna be called back - candidates.pop(); - } else { - s5bSession.reset(); - candidates.pop(); - tryNextCandidate(true); - } - } - } else { - // we have a working connection, hooray - JingleS5BTransportPayload::ref success = boost::make_shared<JingleS5BTransportPayload>(); - success->setCandidateUsed(lastCandidate.cid); - success->setSessionID(transportSID); - onRemoteTransportCandidateSelectFinished(success); - } -} - -void DefaultRemoteJingleTransportCandidateSelector::setMinimumPriority(int priority) { - SWIFT_LOG(debug) << "priority: " << priority << std::endl; -} - -void DefaultRemoteJingleTransportCandidateSelector::setRequesterTargtet(const JID& requester, const JID& target) { - this->requester = requester; - this->target = target; -} - -SOCKS5BytestreamClientSession::ref DefaultRemoteJingleTransportCandidateSelector::getS5BSession() { - return s5bSession; -} - -bool DefaultRemoteJingleTransportCandidateSelector::isActualCandidate(JingleTransportPayload::ref /* transportPayload */) { - return false; -} - -int DefaultRemoteJingleTransportCandidateSelector::getPriority(JingleTransportPayload::ref /* transportPayload */) { - return 0; -} - -JingleTransport::ref DefaultRemoteJingleTransportCandidateSelector::selectTransport(JingleTransportPayload::ref /* transportPayload */) { - return JingleTransport::ref(); -} - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h deleted file mode 100644 index 255acd9..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <queue> -#include <vector> - -#include <boost/shared_ptr.hpp> - -#include <Swiften/JID/JID.h> -#include <Swiften/Network/Connection.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> - - -namespace Swift { - -class ConnectionFactory; -class TimerFactory; - -class DefaultRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { -public: - DefaultRemoteJingleTransportCandidateSelector(ConnectionFactory*, TimerFactory*); - virtual ~DefaultRemoteJingleTransportCandidateSelector(); - - virtual void addRemoteTransportCandidates(JingleTransportPayload::ref); - virtual void selectCandidate(); - virtual void setMinimumPriority(int); - void setRequesterTargtet(const JID& requester, const JID& target); - virtual SOCKS5BytestreamClientSession::ref getS5BSession(); - - virtual bool isActualCandidate(JingleTransportPayload::ref); - virtual int getPriority(JingleTransportPayload::ref); - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref); - -private: - void tryNextCandidate(bool error); - -private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; - - std::priority_queue<JingleS5BTransportPayload::Candidate, std::vector<JingleS5BTransportPayload::Candidate>, JingleS5BTransportPayload::CompareCandidate> candidates; - - std::string transportSID; - boost::shared_ptr<Connection> connection; - boost::shared_ptr<SOCKS5BytestreamClientSession> s5bSession; - JingleS5BTransportPayload::Candidate lastCandidate; - JID requester; - JID target; -}; - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp deleted file mode 100644 index 8ebbf46..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "DefaultRemoteJingleTransportCandidateSelectorFactory.h" - -#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h> - -#include <Swiften/Base/Log.h> - -namespace Swift { - -DefaultRemoteJingleTransportCandidateSelectorFactory::DefaultRemoteJingleTransportCandidateSelectorFactory(ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : connectionFactory(connectionFactory), timerFactory(timerFactory) { -} - -DefaultRemoteJingleTransportCandidateSelectorFactory::~DefaultRemoteJingleTransportCandidateSelectorFactory() { -} - -RemoteJingleTransportCandidateSelector* DefaultRemoteJingleTransportCandidateSelectorFactory::createCandidateSelector() { - return new DefaultRemoteJingleTransportCandidateSelector(connectionFactory, timerFactory); -} - -} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h deleted file mode 100644 index ca29e1f..0000000 --- a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> - -namespace Swift { - -class ConnectionFactory; -class TimerFactory; - -class DefaultRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory { -public: - DefaultRemoteJingleTransportCandidateSelectorFactory(ConnectionFactory*, TimerFactory*); - virtual ~DefaultRemoteJingleTransportCandidateSelectorFactory(); - - RemoteJingleTransportCandidateSelector* createCandidateSelector(); - -private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; -}; - -} diff --git a/Swiften/FileTransfer/FileReadBytestream.cpp b/Swiften/FileTransfer/FileReadBytestream.cpp index a8946a0..4257f8b 100644 --- a/Swiften/FileTransfer/FileReadBytestream.cpp +++ b/Swiften/FileTransfer/FileReadBytestream.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <cassert> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/FileTransfer/FileReadBytestream.h> @@ -31,6 +32,6 @@ boost::shared_ptr<ByteArray> FileReadBytestream::read(size_t size) { result->resize(size); assert(stream->good()); - stream->read(reinterpret_cast<char*>(vecptr(*result)), size); - result->resize(stream->gcount()); + stream->read(reinterpret_cast<char*>(vecptr(*result)), boost::numeric_cast<std::streamsize>(size)); + result->resize(boost::numeric_cast<size_t>(stream->gcount())); onRead(*result); return result; diff --git a/Swiften/FileTransfer/FileReadBytestream.h b/Swiften/FileTransfer/FileReadBytestream.h index e9db2a4..4a2d738 100644 --- a/Swiften/FileTransfer/FileReadBytestream.h +++ b/Swiften/FileTransfer/FileReadBytestream.h @@ -10,8 +10,9 @@ #include <boost/filesystem/fstream.hpp> +#include <Swiften/Base/API.h> #include <Swiften/FileTransfer/ReadBytestream.h> namespace Swift { - class FileReadBytestream : public ReadBytestream { + class SWIFTEN_API FileReadBytestream : public ReadBytestream { public: FileReadBytestream(const boost::filesystem::path& file); diff --git a/Swiften/FileTransfer/FileTransfer.cpp b/Swiften/FileTransfer/FileTransfer.cpp new file mode 100644 index 0000000..912a78a --- /dev/null +++ b/Swiften/FileTransfer/FileTransfer.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2013-2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransfer.h> + +using namespace Swift; + +FileTransfer::FileTransfer() : fileSizeInBytes(0) { +} + +FileTransfer::~FileTransfer() { +} + +void FileTransfer::setFileInfo(const std::string& name, boost::uintmax_t size) { + filename = name; + fileSizeInBytes = size; +} diff --git a/Swiften/FileTransfer/FileTransfer.h b/Swiften/FileTransfer/FileTransfer.h index 336c51c..c01aadb 100644 --- a/Swiften/FileTransfer/FileTransfer.h +++ b/Swiften/FileTransfer/FileTransfer.h @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once @@ -15,45 +21,50 @@ namespace Swift { - class FileTransfer { public: struct State { - enum FTState { - Canceled, - Failed, - Finished, - Negotiating, - Transferring, + enum Type { + Initial, WaitingForStart, + Negotiating, WaitingForAccept, + Transferring, + Canceled, + Failed, + Finished }; - FTState state; - std::string message; + State(Type type, const std::string& message = "") : type(type), message(message) {} - State(FTState state) : state(state), message("") {} - State(FTState state, std::string message) : state(state), message(message) {} + Type type; + std::string message; }; - -public: typedef boost::shared_ptr<FileTransfer> ref; public: - boost::uintmax_t fileSizeInBytes; - std::string filename; - std::string algo; - std::string hash; + FileTransfer(); + virtual ~FileTransfer(); -public: virtual void cancel() = 0; + const std::string& getFileName() const { + return filename; + } + + boost::uintmax_t getFileSizeInBytes() const { + return fileSizeInBytes; + } + public: - boost::signal<void (int /* proccessedBytes */)> onProcessedBytes; - boost::signal<void (State)> onStateChange; + boost::signal<void (size_t /* proccessedBytes */)> onProcessedBytes; + boost::signal<void (const State&)> onStateChanged; boost::signal<void (boost::optional<FileTransferError>)> onFinished; -public: - virtual ~FileTransfer() {} -}; + protected: + void setFileInfo(const std::string& name, boost::uintmax_t size); + private: + boost::uintmax_t fileSizeInBytes; + std::string filename; + }; } diff --git a/Swiften/FileTransfer/FileTransferError.h b/Swiften/FileTransfer/FileTransferError.h index 6a6b454..eb1e8f8 100644 --- a/Swiften/FileTransfer/FileTransferError.h +++ b/Swiften/FileTransfer/FileTransferError.h @@ -14,5 +14,5 @@ namespace Swift { PeerError, ReadError, - ClosedError, + ClosedError }; diff --git a/Swiften/FileTransfer/FileTransferManager.cpp b/Swiften/FileTransfer/FileTransferManager.cpp index 69be852..0c7d894 100644 --- a/Swiften/FileTransfer/FileTransferManager.cpp +++ b/Swiften/FileTransfer/FileTransferManager.cpp @@ -12,3 +12,12 @@ FileTransferManager::~FileTransferManager() { } +bool FileTransferManager::isSupportedBy(const DiscoInfo::ref info) { + if (info) { + return info->hasFeature(DiscoInfo::JingleFeature) + && info->hasFeature(DiscoInfo::JingleFTFeature) + && (info->hasFeature(DiscoInfo::JingleTransportsIBBFeature) || info->hasFeature(DiscoInfo::JingleTransportsS5BFeature)); + } + return false; +} + } diff --git a/Swiften/FileTransfer/FileTransferManager.h b/Swiften/FileTransfer/FileTransferManager.h index d59f029..bc6530b 100644 --- a/Swiften/FileTransfer/FileTransferManager.h +++ b/Swiften/FileTransfer/FileTransferManager.h @@ -5,12 +5,21 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <string> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/date_time/posix_time/posix_time.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/DiscoInfo.h> #include <Swiften/JID/JID.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> #include <Swiften/FileTransfer/OutgoingFileTransfer.h> #include <Swiften/FileTransfer/IncomingFileTransfer.h> @@ -18,14 +27,25 @@ namespace Swift { class ReadBytestream; - class S5BProxyRequest; - class FileTransferManager { + class SWIFTEN_API FileTransferManager { public: virtual ~FileTransferManager(); - virtual void startListeningOnPort(int port) = 0; - - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream) = 0; - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream) = 0; + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const boost::filesystem::path& filepath, + const std::string& description, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& = FileTransferOptions()) = 0; + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const std::string& filename, + const std::string& description, + const boost::uintmax_t sizeInBytes, + const boost::posix_time::ptime& lastModified, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& = FileTransferOptions()) = 0; + + static bool isSupportedBy(const DiscoInfo::ref info); boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer; diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp index 83320b2..04a2332 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp +++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp @@ -5,22 +5,28 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <Swiften/FileTransfer/FileTransferManagerImpl.h> #include <boost/bind.hpp> +#include <boost/filesystem.hpp> #include <boost/cstdint.hpp> #include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/Path.h> #include "Swiften/Disco/EntityCapsProvider.h" #include <Swiften/JID/JID.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> -#include <Swiften/FileTransfer/ConnectivityManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> #include <Swiften/FileTransfer/OutgoingFileTransferManager.h> #include <Swiften/FileTransfer/IncomingFileTransferManager.h> -#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <Swiften/Presence/PresenceOracle.h> #include <Swiften/Elements/Presence.h> @@ -30,52 +36,66 @@ #include <Swiften/Network/NATTraverser.h> +#include <Swiften/Base/BoostFilesystemVersion.h> + namespace Swift { -FileTransferManagerImpl::FileTransferManagerImpl(const JID& ownFullJID, JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, PresenceOracle* presOracle, ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, NATTraverser* natTraverser) : ownJID(ownFullJID), jingleSM(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), presenceOracle(presOracle), timerFactory(timerFactory), connectionFactory(connectionFactory), connectionServerFactory(connectionServerFactory), natTraverser(natTraverser), bytestreamServer(NULL), s5bProxyFinder(NULL) { +FileTransferManagerImpl::FileTransferManagerImpl( + const JID& ownFullJID, + JingleSessionManager* jingleSessionManager, + IQRouter* router, + EntityCapsProvider* capsProvider, + PresenceOracle* presOracle, + ConnectionFactory* connectionFactory, + ConnectionServerFactory* connectionServerFactory, + TimerFactory* timerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser, + CryptoProvider* crypto) : + ownJID(ownFullJID), + iqRouter(router), + capsProvider(capsProvider), + presenceOracle(presOracle) { assert(!ownFullJID.isBare()); - connectivityManager = new ConnectivityManager(natTraverser); bytestreamRegistry = new SOCKS5BytestreamRegistry(); - bytestreamProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); - - localCandidateGeneratorFactory = new DefaultLocalJingleTransportCandidateGeneratorFactory(connectivityManager, bytestreamRegistry, bytestreamProxy, ownFullJID); - remoteCandidateSelectorFactory = new DefaultRemoteJingleTransportCandidateSelectorFactory(connectionFactory, timerFactory); - outgoingFTManager = new OutgoingFileTransferManager(jingleSM, iqRouter, capsProvider, remoteCandidateSelectorFactory, localCandidateGeneratorFactory, bytestreamRegistry, bytestreamProxy); - incomingFTManager = new IncomingFileTransferManager(jingleSM, iqRouter, remoteCandidateSelectorFactory, localCandidateGeneratorFactory, bytestreamRegistry, bytestreamProxy, timerFactory); + s5bServerManager = new SOCKS5BytestreamServerManager( + bytestreamRegistry, connectionServerFactory, networkEnvironment, natTraverser); + bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); + + transporterFactory = new DefaultFileTransferTransporterFactory( + bytestreamRegistry, + s5bServerManager, + bytestreamProxy, + &idGenerator, + connectionFactory, + timerFactory, + crypto, + iqRouter); + outgoingFTManager = new OutgoingFileTransferManager( + jingleSessionManager, + iqRouter, + transporterFactory, + crypto); + incomingFTManager = new IncomingFileTransferManager( + jingleSessionManager, + iqRouter, + transporterFactory, + timerFactory, + crypto); incomingFTManager->onIncomingFileTransfer.connect(onIncomingFileTransfer); } FileTransferManagerImpl::~FileTransferManagerImpl() { - if (s5bProxyFinder) { - s5bProxyFinder->stop(); - delete s5bProxyFinder; - } - if (bytestreamServer) { - bytestreamServer->stop(); - delete bytestreamServer; - } + delete s5bServerManager; delete incomingFTManager; delete outgoingFTManager; - delete remoteCandidateSelectorFactory; - delete localCandidateGeneratorFactory; - delete connectivityManager; + delete transporterFactory; } -void FileTransferManagerImpl::startListeningOnPort(int port) { - // TODO: create a server for each interface we're on - SWIFT_LOG(debug) << "Start listening on port " << port << " and hope it's not in use." << std::endl; - boost::shared_ptr<ConnectionServer> server = connectionServerFactory->createConnectionServer(HostAddress("0.0.0.0"), port); - server->start(); - bytestreamServer = new SOCKS5BytestreamServer(server, bytestreamRegistry); - bytestreamServer->start(); - connectivityManager->addListeningPort(port); - - s5bProxyFinder = new SOCKS5BytestreamProxyFinder(ownJID.getDomain(), iqRouter); - s5bProxyFinder->onProxyFound.connect(boost::bind(&FileTransferManagerImpl::addS5BProxy, this, _1)); - s5bProxyFinder->start(); +void FileTransferManagerImpl::start() { } -void FileTransferManagerImpl::addS5BProxy(S5BProxyRequest::ref proxy) { - bytestreamProxy->addS5BProxy(proxy); +void FileTransferManagerImpl::stop() { + s5bServerManager->stop(); } @@ -92,6 +112,5 @@ boost::optional<JID> FileTransferManagerImpl::highestPriorityJIDSupportingFileTr // look up caps from the jid DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom()); - if (info && info->hasFeature(DiscoInfo::JingleFeature) && info->hasFeature(DiscoInfo::JingleFTFeature) && (info->hasFeature(DiscoInfo::JingleTransportsIBBFeature) || info->hasFeature(DiscoInfo::JingleTransportsS5BFeature))) { - + if (isSupportedBy(info)) { priority = pres->getPriority(); fullReceipientJID = pres->getFrom(); @@ -103,12 +122,29 @@ boost::optional<JID> FileTransferManagerImpl::highestPriorityJIDSupportingFileTr } -OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream) { +OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer( + const JID& to, + const boost::filesystem::path& filepath, + const std::string& description, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& config) { +#if BOOST_FILESYSTEM_VERSION == 2 // TODO: Delete this when boost 1.44 becomes a minimum requirement, and we no longer need v2 std::string filename = filepath.filename(); +#else + std::string filename = pathToString(filepath.filename()); +#endif + boost::uintmax_t sizeInBytes = boost::filesystem::file_size(filepath); boost::posix_time::ptime lastModified = boost::posix_time::from_time_t(boost::filesystem::last_write_time(filepath)); - return createOutgoingFileTransfer(to, filename, description, sizeInBytes, lastModified, bytestream); + return createOutgoingFileTransfer(to, filename, description, sizeInBytes, lastModified, bytestream, config); } -OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream) { +OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer( + const JID& to, + const std::string& filename, + const std::string& description, + const boost::uintmax_t sizeInBytes, + const boost::posix_time::ptime& lastModified, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions& config) { StreamInitiationFileInfo fileInfo; fileInfo.setDate(lastModified); @@ -128,5 +164,5 @@ OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(co } - return outgoingFTManager->createOutgoingFileTransfer(ownJID, receipient, bytestream, fileInfo); + return outgoingFTManager->createOutgoingFileTransfer(ownJID, receipient, bytestream, fileInfo, config); } diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.h b/Swiften/FileTransfer/FileTransferManagerImpl.h index 248b437..addbbd7 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.h +++ b/Swiften/FileTransfer/FileTransferManagerImpl.h @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once @@ -10,10 +16,14 @@ #include <string> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/optional.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> #include <Swiften/FileTransfer/FileTransferManager.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/IDGenerator.h> #include <Swiften/JID/JID.h> #include <Swiften/FileTransfer/OutgoingFileTransfer.h> @@ -22,34 +32,55 @@ namespace Swift { - class Client; class ConnectionFactory; class ConnectionServerFactory; - class ConnectivityManager; + class SOCKS5BytestreamServerManager; class EntityCapsProvider; class IQRouter; class IncomingFileTransferManager; class JingleSessionManager; - class LocalJingleTransportCandidateGeneratorFactory; class OutgoingFileTransferManager; class NATTraverser; class PresenceOracle; class ReadBytestream; - class RemoteJingleTransportCandidateSelectorFactory; + class FileTransferTransporterFactory; class SOCKS5BytestreamRegistry; - class SOCKS5BytestreamServer; - class SOCKS5BytestreamProxy; + class SOCKS5BytestreamProxiesManager; class TimerFactory; - class SOCKS5BytestreamProxyFinder; + class CryptoProvider; + class NetworkEnvironment; - class FileTransferManagerImpl : public FileTransferManager { + class SWIFTEN_API FileTransferManagerImpl : public FileTransferManager { public: - FileTransferManagerImpl(const JID& ownFullJID, JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, PresenceOracle* presOracle, ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, NATTraverser* natTraverser); + FileTransferManagerImpl( + const JID& ownFullJID, + JingleSessionManager* jingleSessionManager, + IQRouter* router, + EntityCapsProvider* capsProvider, + PresenceOracle* presOracle, + ConnectionFactory* connectionFactory, + ConnectionServerFactory* connectionServerFactory, + TimerFactory* timerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser, + CryptoProvider* crypto); ~FileTransferManagerImpl(); - void startListeningOnPort(int port); - void addS5BProxy(S5BProxyRequest::ref proxy); + OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const boost::filesystem::path& filepath, + const std::string& description, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions&) SWIFTEN_OVERRIDE; + OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID& to, + const std::string& filename, + const std::string& description, + const boost::uintmax_t sizeInBytes, + const boost::posix_time::ptime& lastModified, + boost::shared_ptr<ReadBytestream> bytestream, + const FileTransferOptions&) SWIFTEN_OVERRIDE; - OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream); - OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream); + void start(); + void stop(); private: @@ -61,21 +92,12 @@ namespace Swift { OutgoingFileTransferManager* outgoingFTManager; IncomingFileTransferManager* incomingFTManager; - RemoteJingleTransportCandidateSelectorFactory* remoteCandidateSelectorFactory; - LocalJingleTransportCandidateGeneratorFactory* localCandidateGeneratorFactory; - JingleSessionManager* jingleSM; + FileTransferTransporterFactory* transporterFactory; IQRouter* iqRouter; EntityCapsProvider* capsProvider; PresenceOracle* presenceOracle; - - TimerFactory* timerFactory; - ConnectionFactory* connectionFactory; - ConnectionServerFactory* connectionServerFactory; - NATTraverser* natTraverser; + IDGenerator idGenerator; SOCKS5BytestreamRegistry* bytestreamRegistry; - SOCKS5BytestreamServer* bytestreamServer; - SOCKS5BytestreamProxy* bytestreamProxy; - ConnectivityManager* connectivityManager; - SOCKS5BytestreamProxyFinder* s5bProxyFinder; + SOCKS5BytestreamProxiesManager* bytestreamProxy; + SOCKS5BytestreamServerManager* s5bServerManager; }; - } diff --git a/Swiften/FileTransfer/FileTransferOptions.cpp b/Swiften/FileTransfer/FileTransferOptions.cpp new file mode 100644 index 0000000..af816ec --- /dev/null +++ b/Swiften/FileTransfer/FileTransferOptions.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransferOptions.h> + +using namespace Swift; + +FileTransferOptions::~FileTransferOptions() { +} diff --git a/Swiften/FileTransfer/FileTransferOptions.h b/Swiften/FileTransfer/FileTransferOptions.h new file mode 100644 index 0000000..993b14b --- /dev/null +++ b/Swiften/FileTransfer/FileTransferOptions.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> + +namespace Swift { + class SWIFTEN_API FileTransferOptions { + public: + FileTransferOptions() : allowInBand(false) { + } + SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(FileTransferOptions) + ~FileTransferOptions(); + + FileTransferOptions& withInBandAllowed(bool b) { + allowInBand = b; + return *this; + } + + bool isInBandAllowed() const { + return allowInBand; + } + + SWIFTEN_DEFAULT_COPY_ASSIGMNENT_OPERATOR(FileTransferOptions) + + private: + bool allowInBand; + }; +} diff --git a/Swiften/FileTransfer/FileTransferTransporter.cpp b/Swiften/FileTransfer/FileTransferTransporter.cpp new file mode 100644 index 0000000..30966c4 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporter.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransferTransporter.h> + +using namespace Swift; + +FileTransferTransporter::~FileTransferTransporter() { +} diff --git a/Swiften/FileTransfer/FileTransferTransporter.h b/Swiften/FileTransfer/FileTransferTransporter.h new file mode 100644 index 0000000..b7b7090 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporter.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <vector> + +#include <boost/optional/optional_fwd.hpp> + +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class TransportSession; + class ErrorPayload; + class ReadBytestream; + class WriteBytestream; + + class SWIFTEN_API FileTransferTransporter { + public: + virtual ~FileTransferTransporter(); + + virtual void startGeneratingLocalCandidates() = 0; + virtual void stopGeneratingLocalCandidates() = 0; + + virtual void addRemoteCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>&) = 0; + virtual void startTryingRemoteCandidates() = 0; + virtual void stopTryingRemoteCandidates() = 0; + + virtual void startActivatingProxy(const JID& proxy) = 0; + virtual void stopActivatingProxy() = 0; + + virtual boost::shared_ptr<TransportSession> createIBBSendSession( + const std::string& sessionID, unsigned int blockSize, boost::shared_ptr<ReadBytestream>) = 0; + virtual boost::shared_ptr<TransportSession> createIBBReceiveSession( + const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream>) = 0; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession( + boost::shared_ptr<ReadBytestream>) = 0; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession( + boost::shared_ptr<WriteBytestream>) = 0; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<ReadBytestream>) = 0; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession( + boost::shared_ptr<WriteBytestream>) = 0; + + boost::signal<void (const std::string& /* sessionID */, const std::vector<JingleS5BTransportPayload::Candidate>&)> onLocalCandidatesGenerated; + boost::signal<void (const std::string& /* sessionID */, const boost::optional<JingleS5BTransportPayload::Candidate>&)> onRemoteCandidateSelectFinished; + boost::signal<void (const std::string& /* sessionID */, boost::shared_ptr<ErrorPayload>)> onProxyActivated; + }; +} diff --git a/Swiften/FileTransfer/FileTransferTransporterFactory.cpp b/Swiften/FileTransfer/FileTransferTransporterFactory.cpp new file mode 100644 index 0000000..0acc016 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporterFactory.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> + +using namespace Swift; + +FileTransferTransporterFactory::~FileTransferTransporterFactory() { +} diff --git a/Swiften/FileTransfer/FileTransferTransporterFactory.h b/Swiften/FileTransfer/FileTransferTransporterFactory.h new file mode 100644 index 0000000..f7f9acc --- /dev/null +++ b/Swiften/FileTransfer/FileTransferTransporterFactory.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/Base/API.h> + +namespace Swift { + class JID; + class FileTransferTransporter; + + class SWIFTEN_API FileTransferTransporterFactory { + public: + virtual ~FileTransferTransporterFactory(); + + virtual FileTransferTransporter* createInitiatorTransporter( + const JID& initiator, + const JID& responder) = 0; + virtual FileTransferTransporter* createResponderTransporter( + const JID& initiator, + const JID& responder, + const std::string& s5bSessionID) = 0; + }; +} diff --git a/Swiften/FileTransfer/FileWriteBytestream.cpp b/Swiften/FileTransfer/FileWriteBytestream.cpp index 6a22c6a..6c11eb0 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.cpp +++ b/Swiften/FileTransfer/FileWriteBytestream.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #include <boost/filesystem/fstream.hpp> #include <cassert> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/FileTransfer/FileWriteBytestream.h> @@ -23,9 +24,12 @@ FileWriteBytestream::~FileWriteBytestream() { void FileWriteBytestream::write(const std::vector<unsigned char>& data) { + if (data.empty()) { + return; + } if (!stream) { stream = new boost::filesystem::ofstream(file, std::ios_base::out|std::ios_base::binary); } assert(stream->good()); - stream->write(reinterpret_cast<const char*>(&data[0]), data.size()); + stream->write(reinterpret_cast<const char*>(&data[0]), boost::numeric_cast<std::streamsize>(data.size())); onWrite(data); } diff --git a/Swiften/FileTransfer/FileWriteBytestream.h b/Swiften/FileTransfer/FileWriteBytestream.h index 82c4a65..f72ac17 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.h +++ b/Swiften/FileTransfer/FileWriteBytestream.h @@ -10,8 +10,9 @@ #include <boost/filesystem/fstream.hpp> +#include <Swiften/Base/API.h> #include <Swiften/FileTransfer/WriteBytestream.h> namespace Swift { - class FileWriteBytestream : public WriteBytestream { + class SWIFTEN_API FileWriteBytestream : public WriteBytestream { public: FileWriteBytestream(const boost::filesystem::path& file); diff --git a/Swiften/FileTransfer/IBBReceiveSession.cpp b/Swiften/FileTransfer/IBBReceiveSession.cpp index 1a2bb3a..8cfd95d 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.cpp +++ b/Swiften/FileTransfer/IBBReceiveSession.cpp @@ -28,5 +28,5 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { if (ibb->getAction() == IBB::Data) { if (sequenceNumber == ibb->getSequenceNumber()) { - session->onDataReceived(ibb->getData()); + session->bytestream->write(ibb->getData()); receivedSize += ibb->getData().size(); sequenceNumber++; @@ -34,5 +34,5 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { if (receivedSize >= session->size) { if (receivedSize > session->size) { - std::cerr << "Warning: Received more data than expected" << std::endl; + SWIFT_LOG(warning) << "Received more data than expected"; } session->finish(boost::optional<FileTransferError>()); @@ -40,5 +40,5 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { } else { - SWIFT_LOG(warning) << "Received data out of order" << std::endl; + SWIFT_LOG(warning) << "Received data out of order"; sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel); session->finish(FileTransferError(FileTransferError::ClosedError)); @@ -46,9 +46,9 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { } else if (ibb->getAction() == IBB::Open) { - SWIFT_LOG(debug) << "IBB open received" << std::endl; + SWIFT_LOG(debug) << "IBB open received"; sendResponse(from, id, IBB::ref()); } else if (ibb->getAction() == IBB::Close) { - SWIFT_LOG(debug) << "IBB close received" << std::endl; + SWIFT_LOG(debug) << "IBB close received"; sendResponse(from, id, IBB::ref()); session->finish(FileTransferError(FileTransferError::ClosedError)); @@ -56,5 +56,5 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { return true; } - SWIFT_LOG(debug) << "wrong from/sessionID: " << from << " == " << session->from << " / " <<ibb->getStreamID() << " == " << session->id << std::endl; + SWIFT_LOG(debug) << "wrong from/sessionID: " << from << " == " << session->from << " / " <<ibb->getStreamID() << " == " << session->id; return false; } @@ -63,5 +63,5 @@ class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { IBBReceiveSession* session; int sequenceNumber; - size_t receivedSize; + unsigned long long receivedSize; }; @@ -71,5 +71,6 @@ IBBReceiveSession::IBBReceiveSession( const JID& from, const JID& to, - size_t size, + unsigned long long size, + boost::shared_ptr<WriteBytestream> bytestream, IQRouter* router) : id(id), @@ -77,4 +78,5 @@ IBBReceiveSession::IBBReceiveSession( to(to), size(size), + bytestream(bytestream), router(router), active(false) { @@ -86,5 +88,5 @@ IBBReceiveSession::IBBReceiveSession( IBBReceiveSession::~IBBReceiveSession() { if (active) { - SWIFT_LOG(warning) << "Session still active" << std::endl; + SWIFT_LOG(warning) << "Session still active"; } delete responder; @@ -92,5 +94,5 @@ IBBReceiveSession::~IBBReceiveSession() { void IBBReceiveSession::start() { - SWIFT_LOG(debug) << "receive session started" << std::endl; + SWIFT_LOG(debug) << "receive session started"; active = true; responder->start(); @@ -98,5 +100,5 @@ void IBBReceiveSession::start() { void IBBReceiveSession::stop() { - SWIFT_LOG(debug) << "receive session stopped" << std::endl; + SWIFT_LOG(debug) << "receive session stopped"; responder->stop(); if (active) { diff --git a/Swiften/FileTransfer/IBBReceiveSession.h b/Swiften/FileTransfer/IBBReceiveSession.h index d1c47bf..23d9648 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.h +++ b/Swiften/FileTransfer/IBBReceiveSession.h @@ -10,4 +10,5 @@ #include <boost/optional/optional_fwd.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/FileTransfer/WriteBytestream.h> @@ -19,5 +20,5 @@ namespace Swift { class IQRouter; - class IBBReceiveSession { + class SWIFTEN_API IBBReceiveSession { public: IBBReceiveSession( @@ -25,5 +26,6 @@ namespace Swift { const JID& from, const JID& to, - size_t size, + unsigned long long size, + boost::shared_ptr<WriteBytestream> bytestream, IQRouter* router); ~IBBReceiveSession(); @@ -40,5 +42,4 @@ namespace Swift { } - boost::signal<void (const std::vector<unsigned char>&)> onDataReceived; boost::signal<void (boost::optional<FileTransferError>)> onFinished; @@ -54,5 +55,6 @@ namespace Swift { JID from; JID to; - size_t size; + unsigned long long size; + boost::shared_ptr<WriteBytestream> bytestream; IQRouter* router; IBBResponder* responder; diff --git a/Swiften/FileTransfer/IBBSendSession.cpp b/Swiften/FileTransfer/IBBSendSession.cpp index c24cc0a..d8b7c7b 100644 --- a/Swiften/FileTransfer/IBBSendSession.cpp +++ b/Swiften/FileTransfer/IBBSendSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/ByteArray.h> @@ -16,5 +17,19 @@ namespace Swift { -IBBSendSession::IBBSendSession(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router) : id(id), from(from), to(to), bytestream(bytestream), router(router), blockSize(4096), sequenceNumber(0), active(false), waitingForData(false) { +IBBSendSession::IBBSendSession( + const std::string& id, + const JID& from, + const JID& to, + boost::shared_ptr<ReadBytestream> bytestream, + IQRouter* router) : + id(id), + from(from), + to(to), + bytestream(bytestream), + router(router), + blockSize(4096), + sequenceNumber(0), + active(false), + waitingForData(false) { bytestream->onDataAvailable.connect(boost::bind(&IBBSendSession::handleDataAvailable, this)); } @@ -25,5 +40,6 @@ IBBSendSession::~IBBSendSession() { void IBBSendSession::start() { - IBBRequest::ref request = IBBRequest::create(from, to, IBB::createIBBOpen(id, blockSize), router); + IBBRequest::ref request = IBBRequest::create( + from, to, IBB::createIBBOpen(id, boost::numeric_cast<int>(blockSize)), router); request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); active = true; diff --git a/Swiften/FileTransfer/IBBSendSession.h b/Swiften/FileTransfer/IBBSendSession.h index abd217b..f6ba7b3 100644 --- a/Swiften/FileTransfer/IBBSendSession.h +++ b/Swiften/FileTransfer/IBBSendSession.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,5 @@ #include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/FileTransfer/ReadBytestream.h> @@ -20,7 +21,12 @@ namespace Swift { class IQRouter; - class IBBSendSession { + class SWIFTEN_API IBBSendSession { public: - IBBSendSession(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router); + IBBSendSession( + const std::string& id, + const JID& from, + const JID& to, + boost::shared_ptr<ReadBytestream> bytestream, + IQRouter* router); ~IBBSendSession(); @@ -36,10 +42,10 @@ namespace Swift { } - void setBlockSize(int blockSize) { + void setBlockSize(unsigned int blockSize) { this->blockSize = blockSize; } boost::signal<void (boost::optional<FileTransferError>)> onFinished; - boost::signal<void (int)> onBytesSent; + boost::signal<void (size_t)> onBytesSent; private: @@ -55,5 +61,5 @@ namespace Swift { boost::shared_ptr<ReadBytestream> bytestream; IQRouter* router; - int blockSize; + unsigned int blockSize; int sequenceNumber; bool active; diff --git a/Swiften/FileTransfer/IncomingFileTransfer.h b/Swiften/FileTransfer/IncomingFileTransfer.h index 5b53d54..698a588 100644 --- a/Swiften/FileTransfer/IncomingFileTransfer.h +++ b/Swiften/FileTransfer/IncomingFileTransfer.h @@ -10,9 +10,11 @@ #include <Swiften/Base/boost_bsignals.h> -#include <Swiften/JID/JID.h> #include <Swiften/FileTransfer/FileTransfer.h> -#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> namespace Swift { + class WriteBytestream; + class JID; + class IncomingFileTransfer : public FileTransfer { public: @@ -21,5 +23,7 @@ namespace Swift { virtual ~IncomingFileTransfer(); - virtual void accept(WriteBytestream::ref) = 0; + virtual void accept( + boost::shared_ptr<WriteBytestream>, + const FileTransferOptions& = FileTransferOptions()) = 0; virtual const JID& getSender() const = 0; diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp index 22e8bf9..d8c4f89 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp +++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,4 +9,5 @@ #include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Base/Log.h> #include <Swiften/Elements/JingleDescription.h> #include <Swiften/Elements/JingleFileTransferDescription.h> @@ -19,7 +20,15 @@ namespace Swift { -IncomingFileTransferManager::IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, - RemoteJingleTransportCandidateSelectorFactory* remoteFactory, - LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, TimerFactory* timerFactory) : jingleSessionManager(jingleSessionManager), router(router), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), timerFactory(timerFactory) { +IncomingFileTransferManager::IncomingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + TimerFactory* timerFactory, + CryptoProvider* crypto) : + jingleSessionManager(jingleSessionManager), + router(router), + transporterFactory(transporterFactory), + timerFactory(timerFactory), + crypto(crypto) { jingleSessionManager->addIncomingSessionHandler(this); } @@ -29,15 +38,18 @@ IncomingFileTransferManager::~IncomingFileTransferManager() { } -bool IncomingFileTransferManager::handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents, const JID& recipient) { +bool IncomingFileTransferManager::handleIncomingJingleSession( + JingleSession::ref session, + const std::vector<JingleContentPayload::ref>& contents, + const JID& recipient) { if (JingleContentPayload::ref content = Jingle::getContentWithDescription<JingleFileTransferDescription>(contents)) { - if (content->getTransport<JingleIBBTransportPayload>() || content->getTransport<JingleS5BTransportPayload>()) { - + if (content->getTransport<JingleS5BTransportPayload>()) { JingleFileTransferDescription::ref description = content->getDescription<JingleFileTransferDescription>(); - if (description && description->getOffers().size() == 1) { - IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(recipient, session, content, remoteFactory, localFactory, router, bytestreamRegistry, bytestreamProxy, timerFactory); + IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>( + recipient, session, content, transporterFactory, timerFactory, crypto); onIncomingFileTransfer(transfer); - } else { - std::cerr << "Received a file-transfer request with no description or more than one file!" << std::endl; + } + else { + SWIFT_LOG(warning) << "Received a file-transfer request with no description or more than one file."; session->sendTerminate(JinglePayload::Reason::FailedApplication); } diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.h b/Swiften/FileTransfer/IncomingFileTransferManager.h index 2d1c07f..9570def 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.h +++ b/Swiften/FileTransfer/IncomingFileTransferManager.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,13 +16,16 @@ namespace Swift { class IQRouter; class JingleSessionManager; - class RemoteJingleTransportCandidateSelectorFactory; - class LocalJingleTransportCandidateGeneratorFactory; - class SOCKS5BytestreamRegistry; - class SOCKS5BytestreamProxy; + class FileTransferTransporterFactory; class TimerFactory; + class CryptoProvider; class IncomingFileTransferManager : public IncomingJingleSessionHandler { public: - IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, TimerFactory* timerFactory); + IncomingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + TimerFactory* timerFactory, + CryptoProvider* crypto); ~IncomingFileTransferManager(); @@ -30,14 +33,15 @@ namespace Swift { private: - bool handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents, const JID& recipient); + bool handleIncomingJingleSession( + JingleSession::ref session, + const std::vector<JingleContentPayload::ref>& contents, + const JID& recipient); private: JingleSessionManager* jingleSessionManager; IQRouter* router; - RemoteJingleTransportCandidateSelectorFactory* remoteFactory; - LocalJingleTransportCandidateGeneratorFactory* localFactory; - SOCKS5BytestreamRegistry* bytestreamRegistry; - SOCKS5BytestreamProxy* bytestreamProxy; + FileTransferTransporterFactory* transporterFactory; TimerFactory* timerFactory; + CryptoProvider* crypto; }; } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp index 35f6bea..b64e333 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,510 +12,383 @@ #include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> +#include <Swiften/Jingle/JingleSession.h> #include <Swiften/Elements/JingleIBBTransportPayload.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> #include <Swiften/Elements/JingleFileTransferHash.h> -#include <Swiften/Elements/S5BProxyRequest.h> #include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h> -#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/FileTransfer/FileTransferTransporter.h> +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> +#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> #include <Swiften/Network/TimerFactory.h> #include <Swiften/Queries/GenericRequest.h> +#include <Swiften/FileTransfer/TransportSession.h> -namespace Swift { +using namespace Swift; + +// TODO: ALlow terminate when already terminated. IncomingJingleFileTransfer::IncomingJingleFileTransfer( - const JID& ourJID, + const JID& toJID, JingleSession::ref session, JingleContentPayload::ref content, - RemoteJingleTransportCandidateSelectorFactory* candidateSelectorFactory, - LocalJingleTransportCandidateGeneratorFactory* candidateGeneratorFactory, - IQRouter* router, - SOCKS5BytestreamRegistry* registry, - SOCKS5BytestreamProxy* proxy, - TimerFactory* timerFactory) : - ourJID(ourJID), - session(session), - router(router), - timerFactory(timerFactory), + FileTransferTransporterFactory* transporterFactory, + TimerFactory* timerFactory, + CryptoProvider* crypto) : + JingleFileTransfer(session, toJID, transporterFactory), initialContent(content), + crypto(crypto), state(Initial), receivedBytes(0), - s5bRegistry(registry), - s5bProxy(proxy), - remoteTransportCandidateSelectFinished(false), - localTransportCandidateSelectFinished(false), - serverSession(0) { - - candidateSelector = candidateSelectorFactory->createCandidateSelector(); - candidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1)); - - candidateGenerator = candidateGeneratorFactory->createCandidateGenerator(); - candidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1)); - - session->onTransportInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2)); - session->onTransportReplaceReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2)); - session->onSessionTerminateReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this, _1)); - session->onSessionInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionInfoReceived, this, _1)); - + hashCalculator(NULL) { description = initialContent->getDescription<JingleFileTransferDescription>(); assert(description); assert(description->getOffers().size() == 1); StreamInitiationFileInfo fileInfo = description->getOffers().front(); - fileSizeInBytes = fileInfo.getSize(); - filename = fileInfo.getName(); + setFileInfo(fileInfo.getName(), fileInfo.getSize()); hash = fileInfo.getHash(); - algo = fileInfo.getAlgo(); + hashAlgorithm = fileInfo.getAlgo(); waitOnHashTimer = timerFactory->createTimer(5000); - waitOnHashTimer->onTick.connect(boost::bind(&IncomingJingleFileTransfer::finishOffTransfer, this)); + waitOnHashTimerTickedConnection = waitOnHashTimer->onTick.connect( + boost::bind(&IncomingJingleFileTransfer::handleWaitOnHashTimerTicked, this)); } IncomingJingleFileTransfer::~IncomingJingleFileTransfer() { - stream->onWrite.disconnect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); - delete hashCalculator; - - session->onSessionTerminateReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this, _1)); - session->onTransportReplaceReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2)); - session->onTransportInfoReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2)); - - candidateGenerator->onLocalTransportCandidatesGenerated.disconnect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1)); - delete candidateGenerator; - - candidateSelector->onRemoteTransportCandidateSelectFinished.disconnect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1)); - delete candidateSelector; } -void IncomingJingleFileTransfer::accept(WriteBytestream::ref stream) { +void IncomingJingleFileTransfer::accept( + boost::shared_ptr<WriteBytestream> stream, + const FileTransferOptions& options) { + SWIFT_LOG(debug) << std::endl; + if (state != Initial) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + assert(!this->stream); this->stream = stream; + this->options = options; - hashCalculator = new IncrementalBytestreamHashCalculator( algo == "md5" || hash.empty() , algo == "sha-1" || hash.empty() ); - stream->onWrite.connect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); - stream->onWrite.connect(boost::bind(&IncomingJingleFileTransfer::handleWriteStreamDataReceived, this, _1)); - onStateChange(FileTransfer::State(FileTransfer::State::Negotiating)); - if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) { - SWIFT_LOG(debug) << "Got IBB transport payload!" << std::endl; - setActiveTransport(createIBBTransport(ibbTransport)); - session->sendAccept(getContentID(), initialContent->getDescriptions()[0], ibbTransport); - } - else if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) { + assert(!hashCalculator); + hashCalculator = new IncrementalBytestreamHashCalculator( + hashAlgorithm == "md5" || hash.empty(), hashAlgorithm == "sha-1" || hash.empty(), crypto); + + writeStreamDataReceivedConnection = stream->onWrite.connect( + boost::bind(&IncomingJingleFileTransfer::handleWriteStreamDataReceived, this, _1)); + + if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) { SWIFT_LOG(debug) << "Got S5B transport payload!" << std::endl; - state = CreatingInitialTransports; - s5bSessionID = s5bTransport->getSessionID().empty() ? idGenerator.generateID() : s5bTransport->getSessionID(); - s5bDestination = SOCKS5BytestreamRegistry::getHostname(s5bSessionID, ourJID, session->getInitiator()); - s5bRegistry->addWriteBytestream(s5bDestination, stream); - fillCandidateMap(theirCandidates, s5bTransport); - candidateSelector->addRemoteTransportCandidates(s5bTransport); - candidateSelector->setRequesterTargtet(session->getInitiator(), ourJID); - s5bTransport->setSessionID(s5bSessionID); - candidateGenerator->generateLocalTransportCandidates(s5bTransport); + setTransporter(transporterFactory->createResponderTransporter( + getInitiator(), getResponder(), s5bTransport->getSessionID())); + transporter->addRemoteCandidates(s5bTransport->getCandidates()); + setState(GeneratingInitialLocalCandidates); + transporter->startGeneratingLocalCandidates(); } else { + // Can't happen, because the transfer would have been rejected automatically assert(false); } } -const JID& IncomingJingleFileTransfer::getSender() const { - return session->getInitiator(); +void IncomingJingleFileTransfer::cancel() { + SWIFT_LOG(debug) << std::endl; + terminate(state == Initial ? JinglePayload::Reason::Decline : JinglePayload::Reason::Cancel); } -const JID& IncomingJingleFileTransfer::getRecipient() const { - return ourJID; -} +void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, + const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + SWIFT_LOG(debug) << std::endl; + if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } -void IncomingJingleFileTransfer::cancel() { - session->sendTerminate(JinglePayload::Reason::Cancel); + fillCandidateMap(localCandidates, candidates); - if (activeTransport) activeTransport->stop(); - if (serverSession) serverSession->stop(); - if (clientSession) clientSession->stop(); - onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); + JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); + transport->setSessionID(s5bSessionID); + transport->setMode(JingleS5BTransportPayload::TCPMode); + foreach(JingleS5BTransportPayload::Candidate candidate, candidates) { + transport->addCandidate(candidate); } + session->sendAccept(getContentID(), initialContent->getDescriptions()[0], transport); -void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates) { - if (state == CreatingInitialTransports) { - if (JingleS5BTransportPayload::ref s5bCandidates = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(candidates)) { - //localTransportCandidateSelectFinished = true; - //JingleS5BTransportPayload::ref emptyCandidates = boost::make_shared<JingleS5BTransportPayload>(); - //emptyCandidates->setSessionID(s5bCandidates->getSessionID()); - fillCandidateMap(ourCandidates, s5bCandidates); - session->sendAccept(getContentID(), initialContent->getDescriptions()[0], s5bCandidates); - - state = NegotiatingTransport; - candidateSelector->selectCandidate(); - } - } - else { - SWIFT_LOG(debug) << "Unhandled state!" << std::endl; - } + setState(TryingCandidates); + transporter->startTryingRemoteCandidates(); } -void IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref transport) { +void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref jinglePayload) { SWIFT_LOG(debug) << std::endl; - if (state == Terminated) { - return; - } - if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { - //remoteTransportCandidateSelectFinished = true; - //selectedRemoteTransportCandidate = transport; - ourCandidate = s5bPayload; - //checkCandidateSelected(); - decideOnUsedTransport(); - session->sendTransportInfo(getContentID(), s5bPayload); - } - else { - SWIFT_LOG(debug) << "Expected something different here." << std::endl; - } -} -void IncomingJingleFileTransfer::checkCandidateSelected() { - assert(false); - if (localTransportCandidateSelectFinished && remoteTransportCandidateSelectFinished) { - if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate) && candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) { - if (candidateGenerator->getPriority(selectedLocalTransportCandidate) > candidateSelector->getPriority(selectedRemoteTransportCandidate)) { - setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate)); - } - else { - setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate)); - } - } - else if (candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) { - setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate)); - } - else if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate)) { - setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate)); - } - else { - state = WaitingForFallbackOrTerminate; - } - } + JingleFileTransferHash::ref transferHash = jinglePayload->getPayload<JingleFileTransferHash>(); + if (transferHash) { + SWIFT_LOG(debug) << "Received hash information." << std::endl; + waitOnHashTimer->stop(); + if (transferHash->getHashes().find("sha-1") != transferHash->getHashes().end()) { + hashAlgorithm = "sha-1"; + hash = transferHash->getHashes().find("sha-1")->second; } - -void IncomingJingleFileTransfer::setActiveTransport(JingleTransport::ref transport) { - state = Transferring; - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - activeTransport = transport; - activeTransport->onDataReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1)); - activeTransport->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); - activeTransport->start(); + else if (transferHash->getHashes().find("md5") != transferHash->getHashes().end()) { + hashAlgorithm = "md5"; + hash = transferHash->getHashes().find("md5")->second; } - -bool IncomingJingleFileTransfer::verifyReceviedData() { - if (algo.empty() || hash.empty()) { - SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; - return true; - } else { - if (algo == "sha-1") { - SWIFT_LOG(debug) << "verify data via SHA-1 hash: " << (hash == hashCalculator->getSHA1String()) << std::endl; - return hash == hashCalculator->getSHA1String(); + if (state == WaitingForHash) { + checkHashAndTerminate(); } - else if (algo == "md5") { - SWIFT_LOG(debug) << "verify data via MD5 hash: " << (hash == hashCalculator->getMD5String()) << std::endl; - return hash == hashCalculator->getMD5String(); } else { - SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; - return true; - } + SWIFT_LOG(debug) << "Ignoring unknown session info" << std::endl; } } -void IncomingJingleFileTransfer::finishOffTransfer() { - if (verifyReceviedData()) { - onStateChange(FileTransfer::State(FileTransfer::State::Finished)); - session->sendTerminate(JinglePayload::Reason::Success); - } else { - onStateChange(FileTransfer::State(FileTransfer::State::Failed, "Verification failed.")); - session->sendTerminate(JinglePayload::Reason::MediaError); - } - state = Terminated; - waitOnHashTimer->stop(); -} +void IncomingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { + SWIFT_LOG(debug) << std::endl; + if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } -void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref jinglePayload) { - if (state == Terminated) { + if (state == Finished) { + SWIFT_LOG(debug) << "Already terminated" << std::endl; return; } - JingleFileTransferHash::ref transferHash = jinglePayload->getPayload<JingleFileTransferHash>(); - if (transferHash) { - SWIFT_LOG(debug) << "Recevied hash information." << std::endl; - if (transferHash->getHashes().find("sha-1") != transferHash->getHashes().end()) { - algo = "sha-1"; - hash = transferHash->getHashes().find("sha-1")->second; + + stopAll(); + if (reason && reason->type == JinglePayload::Reason::Cancel) { + setFinishedState(FileTransfer::State::Canceled, FileTransferError(FileTransferError::PeerError)); } - else if (transferHash->getHashes().find("md5") != transferHash->getHashes().end()) { - algo = "md5"; - hash = transferHash->getHashes().find("md5")->second; + else if (reason && reason->type == JinglePayload::Reason::Success) { + setFinishedState(FileTransfer::State::Finished, boost::optional<FileTransferError>()); } - checkIfAllDataReceived(); + else { + setFinishedState(FileTransfer::State::Failed, FileTransferError(FileTransferError::PeerError)); } } -void IncomingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { - SWIFT_LOG(debug) << "session terminate received" << std::endl; - if (activeTransport) activeTransport->stop(); - if (reason && reason.get().type == JinglePayload::Reason::Cancel) { - onStateChange(FileTransfer::State(FileTransfer::State::Canceled, "Other user canceled the transfer.")); +void IncomingJingleFileTransfer::checkHashAndTerminate() { + if (verifyData()) { + terminate(JinglePayload::Reason::Success); } - else if (reason && reason.get().type == JinglePayload::Reason::Success) { - /*if (verifyReceviedData()) { - onStateChange(FileTransfer::State(FileTransfer::State::Finished)); - } else { - onStateChange(FileTransfer::State(FileTransfer::State::Failed, "Verification failed.")); - }*/ + else { + SWIFT_LOG(warning) << "Hash verification failed" << std::endl; + terminate(JinglePayload::Reason::MediaError); } - state = Terminated; } void IncomingJingleFileTransfer::checkIfAllDataReceived() { - if (receivedBytes == fileSizeInBytes) { + if (receivedBytes == getFileSizeInBytes()) { SWIFT_LOG(debug) << "All data received." << std::endl; if (hash.empty()) { - SWIFT_LOG(debug) << "No hash information yet. Waiting 5 seconds on hash info." << std::endl; + SWIFT_LOG(debug) << "No hash information yet. Waiting a while on hash info." << std::endl; + setState(WaitingForHash); waitOnHashTimer->start(); - } else { - SWIFT_LOG(debug) << "We already have hash info using " << algo << " algorithm. Finishing off transfer." << std::endl; - finishOffTransfer(); + } + else { + checkHashAndTerminate(); } } - else if (receivedBytes > fileSizeInBytes) { + else if (receivedBytes > getFileSizeInBytes()) { SWIFT_LOG(debug) << "We got more than we could handle!" << std::endl; + terminate(JinglePayload::Reason::MediaError); } } -void IncomingJingleFileTransfer::handleTransportDataReceived(const std::vector<unsigned char>& data) { - SWIFT_LOG(debug) << data.size() << " bytes received" << std::endl; - onProcessedBytes(data.size()); - stream->write(data); +void IncomingJingleFileTransfer::handleWriteStreamDataReceived( + const std::vector<unsigned char>& data) { + hashCalculator->feedData(data); receivedBytes += data.size(); checkIfAllDataReceived(); } -void IncomingJingleFileTransfer::handleWriteStreamDataReceived(const std::vector<unsigned char>& data) { - receivedBytes += data.size(); - checkIfAllDataReceived(); +void IncomingJingleFileTransfer::handleTransportReplaceReceived( + const JingleContentID& content, JingleTransportPayload::ref transport) { + SWIFT_LOG(debug) << std::endl; + if (state != WaitingForFallbackOrTerminate) { + SWIFT_LOG(warning) << "Incorrect state" << std::endl; + return; } -void IncomingJingleFileTransfer::useOurCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) { - SWIFT_LOG(debug) << std::endl; - if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - // get proxy client session from remoteCandidateSelector - clientSession = candidateSelector->getS5BSession(); + if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { + SWIFT_LOG(debug) << "transport replaced with IBB" << std::endl; - // wait on <activated/> transport-info - } else { - // ask s5b client - clientSession = candidateSelector->getS5BSession(); - if (clientSession) { - state = Transferring; - SWIFT_LOG(debug) << clientSession->getAddressPort().toString() << std::endl; - clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startReceiving(stream); - } else { - SWIFT_LOG(debug) << "No S5B client session found!!!" << std::endl; + startTransferring(transporter->createIBBReceiveSession( + ibbTransport->getSessionID(), + description->getOffers()[0].getSize(), + stream)); + session->sendTransportAccept(content, ibbTransport); } + else { + SWIFT_LOG(debug) << "Unknown replace transport" << std::endl; + session->sendTransportReject(content, transport); } } -void IncomingJingleFileTransfer::useTheirCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) { - SWIFT_LOG(debug) << std::endl; - - if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - // get proxy client session from s5bRegistry - clientSession = s5bProxy->createSOCKS5BytestreamClientSession(candidate.hostPort, SOCKS5BytestreamRegistry::getHostname(s5bSessionID, ourJID, session->getInitiator())); - clientSession->onSessionReady.connect(boost::bind(&IncomingJingleFileTransfer::proxySessionReady, this, candidate.jid, _1)); - clientSession->start(); +JingleContentID IncomingJingleFileTransfer::getContentID() const { + return JingleContentID(initialContent->getName(), initialContent->getCreator()); +} - // on reply send activate - } else { - // ask s5b server - serverSession = s5bRegistry->getConnectedSession(s5bDestination); - if (serverSession) { - state = Transferring; - serverSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - serverSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); - serverSession->startTransfer(); - } else { - SWIFT_LOG(debug) << "No S5B server session found!!!" << std::endl; +bool IncomingJingleFileTransfer::verifyData() { + if (hashAlgorithm.empty() || hash.empty()) { + SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; + return true; } + if (hashAlgorithm == "sha-1") { + SWIFT_LOG(debug) << "Verify SHA-1 hash: " << (hash == hashCalculator->getSHA1String()) << std::endl; + return hash == hashCalculator->getSHA1String(); } + else if (hashAlgorithm == "md5") { + SWIFT_LOG(debug) << "Verify MD5 hash: " << (hash == hashCalculator->getMD5String()) << std::endl; + return hash == hashCalculator->getMD5String(); } - -void IncomingJingleFileTransfer::fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload) { - map.clear(); - foreach (JingleS5BTransportPayload::Candidate candidate, s5bPayload->getCandidates()) { - map[candidate.cid] = candidate; + else { + SWIFT_LOG(debug) << "Unknown hash, skipping" << std::endl; + return true; } } +void IncomingJingleFileTransfer::handleWaitOnHashTimerTicked() { + SWIFT_LOG(debug) << std::endl; + waitOnHashTimer->stop(); + terminate(JinglePayload::Reason::Success); +} -void IncomingJingleFileTransfer::decideOnUsedTransport() { - if (ourCandidate && theirCandidate) { - if (ourCandidate->hasCandidateError() && theirCandidate->hasCandidateError()) { - state = WaitingForFallbackOrTerminate; - return; +const JID& IncomingJingleFileTransfer::getSender() const { + return getInitiator(); } - std::string our_cid = ourCandidate->getCandidateUsed(); - std::string their_cid = theirCandidate->getCandidateUsed(); - if (ourCandidate->hasCandidateError() && !their_cid.empty()) { - useTheirCandidateChoiceForTransfer(ourCandidates[their_cid]); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } - else if (theirCandidate->hasCandidateError() && !our_cid.empty()) { - useOurCandidateChoiceForTransfer(theirCandidates[our_cid]); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } - else if (!our_cid.empty() && !their_cid.empty()) { - // compare priorites, if same they win - if (ourCandidates.find(their_cid) == ourCandidates.end() || theirCandidates.find(our_cid) == theirCandidates.end()) { - SWIFT_LOG(debug) << "Didn't recognize candidate IDs!" << std::endl; - session->sendTerminate(JinglePayload::Reason::FailedTransport); - onStateChange(FileTransfer::State(FileTransfer::State::Canceled, "Failed to negotiate candidate.")); - onFinished(FileTransferError(FileTransferError::PeerError)); - return; + +const JID& IncomingJingleFileTransfer::getRecipient() const { + return getResponder(); } - JingleS5BTransportPayload::Candidate our_candidate = theirCandidates[our_cid]; - JingleS5BTransportPayload::Candidate their_candidate = ourCandidates[their_cid]; - if (our_candidate.priority > their_candidate.priority) { - useOurCandidateChoiceForTransfer(our_candidate); +void IncomingJingleFileTransfer::setState(State state) { + SWIFT_LOG(debug) << state << std::endl; + this->state = state; + onStateChanged(FileTransfer::State(getExternalState(state))); } - else if (our_candidate.priority < their_candidate.priority) { - useTheirCandidateChoiceForTransfer(their_candidate); + +void IncomingJingleFileTransfer::setFinishedState( + FileTransfer::State::Type type, const boost::optional<FileTransferError>& error) { + SWIFT_LOG(debug) << std::endl; + this->state = Finished; + onStateChanged(type); + onFinished(error); } - else { - useTheirCandidateChoiceForTransfer(their_candidate); + +void IncomingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { + if (error && state != WaitingForHash) { + terminate(JinglePayload::Reason::MediaError); } - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); } - else { + +FileTransfer::State::Type IncomingJingleFileTransfer::getExternalState(State state) { + switch (state) { + case Initial: return FileTransfer::State::Initial; + case GeneratingInitialLocalCandidates: return FileTransfer::State::WaitingForStart; + case TryingCandidates: return FileTransfer::State::Negotiating; + case WaitingForPeerProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForLocalProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForFallbackOrTerminate: return FileTransfer::State::Negotiating; + case Transferring: return FileTransfer::State::Transferring; + case WaitingForHash: return FileTransfer::State::Transferring; + case Finished: return FileTransfer::State::Finished; + } assert(false); + return FileTransfer::State::Initial; } - } else { - SWIFT_LOG(debug) << "Can't make a transport decision yet." << std::endl; + +void IncomingJingleFileTransfer::stopAll() { + if (state != Initial) { + writeStreamDataReceivedConnection.disconnect(); + delete hashCalculator; } + switch (state) { + case Initial: break; + case GeneratingInitialLocalCandidates: transporter->stopGeneratingLocalCandidates(); break; + case TryingCandidates: transporter->stopTryingRemoteCandidates(); break; + case WaitingForFallbackOrTerminate: break; + case WaitingForPeerProxyActivate: break; + case WaitingForLocalProxyActivate: transporter->stopActivatingProxy(); break; + case WaitingForHash: // Fallthrough + case Transferring: + assert(transportSession); + transferFinishedConnection.disconnect(); + transportSession->stop(); + transportSession.reset(); + break; + case Finished: SWIFT_LOG(warning) << "Already finished" << std::endl; break; } - -void IncomingJingleFileTransfer::proxySessionReady(const JID& proxy, bool error) { - if (error) { - // indicate proxy error - } else { - // activate proxy - activateProxySession(proxy); + if (state != Initial) { + delete transporter; } } -void IncomingJingleFileTransfer::activateProxySession(const JID &proxy) { - S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); - proxyRequest->setSID(s5bSessionID); - proxyRequest->setActivate(session->getInitiator()); - - boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxy, proxyRequest, router); - request->onResponse.connect(boost::bind(&IncomingJingleFileTransfer::handleActivateProxySessionResult, this, _1, _2)); - request->send(); +bool IncomingJingleFileTransfer::hasPriorityOnCandidateTie() const { + return false; } -void IncomingJingleFileTransfer::handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> /*request*/, ErrorPayload::ref error) { - SWIFT_LOG(debug) << std::endl; - if (error) { - SWIFT_LOG(debug) << "ERROR" << std::endl; - } else { - // send activated to other jingle party - JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>(); - proxyActivate->setActivated(theirCandidate->getCandidateUsed()); - session->sendTransportInfo(getContentID(), proxyActivate); - - // start transferring - clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startReceiving(stream); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); +void IncomingJingleFileTransfer::fallback() { + if (options.isInBandAllowed()) { + setState(WaitingForFallbackOrTerminate); } + else { + terminate(JinglePayload::Reason::ConnectivityError); } - -void IncomingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref transport) { - SWIFT_LOG(debug) << "transport info received" << std::endl; - if (state == Terminated) { - return; - } - if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { - if (!s5bPayload->getActivated().empty()) { - if (ourCandidate->getCandidateUsed() == s5bPayload->getActivated()) { - clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startReceiving(stream); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } else { - SWIFT_LOG(debug) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl; - JingleS5BTransportPayload::ref proxyError = boost::make_shared<JingleS5BTransportPayload>(); - proxyError->setProxyError(true); - proxyError->setSessionID(s5bSessionID); - session->sendTransportInfo(getContentID(), proxyError); - } - } else { - theirCandidate = s5bPayload; - decideOnUsedTransport(); } + +void IncomingJingleFileTransfer::startTransferViaRemoteCandidate() { + SWIFT_LOG(debug) << std::endl; + + if (ourCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForPeerProxyActivate); } else { - SWIFT_LOG(debug) << "Expected something different here." << std::endl; + startTransferring(createRemoteCandidateSession()); } - /*localTransportCandidateSelectFinished = true; - selectedLocalTransportCandidate = transport; - if (candidateGenerator->isActualCandidate(transport)) { - candidateSelector->setMinimumPriority(candidateGenerator->getPriority(transport)); - }*/ - //checkCandidateSelected(); } -void IncomingJingleFileTransfer::handleTransportReplaceReceived(const JingleContentID& content, JingleTransportPayload::ref transport) { - if (state == Terminated) { - return; +void IncomingJingleFileTransfer::startTransferViaLocalCandidate() { + SWIFT_LOG(debug) << std::endl; + + if (theirCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForLocalProxyActivate); + transporter->startActivatingProxy(theirCandidateChoice->jid); } - if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { - SWIFT_LOG(debug) << "transport replaced with IBB" << std::endl; - setActiveTransport(createIBBTransport(ibbTransport)); - session->sendTransportAccept(content, ibbTransport); - } else { - SWIFT_LOG(debug) << "transport replaced failed" << std::endl; - session->sendTransportReject(content, transport); + else { + startTransferring(createLocalCandidateSession()); } } -void IncomingJingleFileTransfer::stopActiveTransport() { - if (activeTransport) { - activeTransport->stop(); - activeTransport->onDataReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1)); - } + +void IncomingJingleFileTransfer::startTransferring(boost::shared_ptr<TransportSession> transportSession) { + SWIFT_LOG(debug) << std::endl; + + this->transportSession = transportSession; + transferFinishedConnection = transportSession->onFinished.connect( + boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); + setState(Transferring); + transportSession->start(); } -JingleIncomingIBBTransport::ref IncomingJingleFileTransfer::createIBBTransport(JingleIBBTransportPayload::ref ibbTransport) { - // TODO: getOffer() -> getOffers correction - return boost::make_shared<JingleIncomingIBBTransport>(session->getInitiator(), getRecipient(), ibbTransport->getSessionID(), description->getOffers()[0].getSize(), router); +bool IncomingJingleFileTransfer::isWaitingForPeerProxyActivate() const { + return state == WaitingForPeerProxyActivate; } -JingleContentID IncomingJingleFileTransfer::getContentID() const { - return JingleContentID(initialContent->getName(), initialContent->getCreator()); +bool IncomingJingleFileTransfer::isWaitingForLocalProxyActivate() const { + return state == WaitingForLocalProxyActivate; } -void IncomingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { - if (state == Terminated) { - return; +bool IncomingJingleFileTransfer::isTryingCandidates() const { + return state == TryingCandidates; } - if (error) { - session->sendTerminate(JinglePayload::Reason::ConnectivityError); - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - onFinished(error); +boost::shared_ptr<TransportSession> IncomingJingleFileTransfer::createLocalCandidateSession() { + return transporter->createLocalCandidateSession(stream); } - // + +boost::shared_ptr<TransportSession> IncomingJingleFileTransfer::createRemoteCandidateSession() { + return transporter->createRemoteCandidateSession(stream); } +void IncomingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) { + SWIFT_LOG(debug) << reason << std::endl; + + if (state != Finished) { + session->sendTerminate(reason); + } + stopAll(); + setFinishedState(getExternalFinishedState(reason), getFileTransferError(reason)); } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h index 4ae0bfb..a691d5b 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,126 +9,111 @@ #include <boost/shared_ptr.hpp> #include <boost/cstdint.hpp> +#include <string> -#include <Swiften/Base/IDGenerator.h> -#include <Swiften/Network/Timer.h> -#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> #include <Swiften/Jingle/JingleContentID.h> #include <Swiften/FileTransfer/IncomingFileTransfer.h> -#include <Swiften/FileTransfer/JingleTransport.h> -#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> -#include <Swiften/Elements/JingleContentPayload.h> -#include <Swiften/Elements/JingleFileTransferDescription.h> -#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/FileTransfer/JingleFileTransfer.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> namespace Swift { - class IQRouter; - class RemoteJingleTransportCandidateSelectorFactory; - class LocalJingleTransportCandidateGeneratorFactory; - class RemoteJingleTransportCandidateSelector; - class LocalJingleTransportCandidateGenerator; - class SOCKS5BytestreamRegistry; - class SOCKS5BytestreamProxy; + class JID; + class JingleSession; + class JingleContentPayload; + class FileTransferTransporter; + class FileTransferTransporterFactory; + class TimerFactory; + class Timer; + class CryptoProvider; class IncrementalBytestreamHashCalculator; + class JingleFileTransferDescription; - class IncomingJingleFileTransfer : public IncomingFileTransfer { + class SWIFTEN_API IncomingJingleFileTransfer : public IncomingFileTransfer, public JingleFileTransfer { public: typedef boost::shared_ptr<IncomingJingleFileTransfer> ref; - enum State { - Initial, - CreatingInitialTransports, - NegotiatingTransport, - Transferring, - WaitingForFallbackOrTerminate, - Terminated - }; IncomingJingleFileTransfer( const JID& recipient, - JingleSession::ref, - JingleContentPayload::ref content, - RemoteJingleTransportCandidateSelectorFactory*, - LocalJingleTransportCandidateGeneratorFactory*, - IQRouter* router, - SOCKS5BytestreamRegistry* bytestreamRegistry, - SOCKS5BytestreamProxy* bytestreamProxy, - TimerFactory*); + boost::shared_ptr<JingleSession>, + boost::shared_ptr<JingleContentPayload> content, + FileTransferTransporterFactory*, + TimerFactory*, + CryptoProvider*); ~IncomingJingleFileTransfer(); - virtual void accept(WriteBytestream::ref); - virtual const JID& getSender() const; - virtual const JID& getRecipient() const; + virtual void accept(boost::shared_ptr<WriteBytestream>, const FileTransferOptions&) SWIFTEN_OVERRIDE; void cancel(); private: - void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason>); - void handleSessionInfoReceived(JinglePayload::ref); - void handleTransportReplaceReceived(const JingleContentID&, JingleTransportPayload::ref); - void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); - void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates); - void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref candidate); - void setActiveTransport(JingleTransport::ref transport); - void handleTransportDataReceived(const std::vector<unsigned char>& data); + enum State { + Initial, + GeneratingInitialLocalCandidates, + TryingCandidates, + WaitingForPeerProxyActivate, + WaitingForLocalProxyActivate, + WaitingForFallbackOrTerminate, + Transferring, + WaitingForHash, + Finished + }; + + virtual void handleSessionTerminateReceived( + boost::optional<JinglePayload::Reason> reason) SWIFTEN_OVERRIDE; + virtual void handleSessionInfoReceived(boost::shared_ptr<JinglePayload>) SWIFTEN_OVERRIDE; + virtual void handleTransportReplaceReceived( + const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + + virtual void handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, + const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE; + void handleWriteStreamDataReceived(const std::vector<unsigned char>& data); void stopActiveTransport(); void checkCandidateSelected(); - JingleIncomingIBBTransport::ref createIBBTransport(JingleIBBTransportPayload::ref ibbTransport); - JingleContentID getContentID() const; + virtual JingleContentID getContentID() const SWIFTEN_OVERRIDE; void checkIfAllDataReceived(); - bool verifyReceviedData(); - void finishOffTransfer(); + bool verifyData(); + void handleWaitOnHashTimerTicked(); void handleTransferFinished(boost::optional<FileTransferError>); private: - typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; + void startTransferViaRemoteCandidate(); + void startTransferViaLocalCandidate(); + void checkHashAndTerminate(); + void stopAll(); + void setState(State state); + void setFinishedState(FileTransfer::State::Type, const boost::optional<FileTransferError>& error); + const JID& getSender() const SWIFTEN_OVERRIDE; + const JID& getRecipient() const SWIFTEN_OVERRIDE; + static FileTransfer::State::Type getExternalState(State state); + virtual bool hasPriorityOnCandidateTie() const SWIFTEN_OVERRIDE; + virtual void fallback() SWIFTEN_OVERRIDE; + virtual void startTransferring(boost::shared_ptr<TransportSession>) SWIFTEN_OVERRIDE; + virtual bool isWaitingForPeerProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isWaitingForLocalProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isTryingCandidates() const SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession() SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession() SWIFTEN_OVERRIDE; + virtual void terminate(JinglePayload::Reason::Type reason) SWIFTEN_OVERRIDE; - private: - void activateProxySession(const JID &proxy); - void handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error); - void proxySessionReady(const JID& proxy, bool error); private: - void useOurCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate); - void useTheirCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate); - void decideOnUsedTransport(); - void fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload); - - private: - JID ourJID; - JingleSession::ref session; - IQRouter* router; - TimerFactory* timerFactory; - JingleContentPayload::ref initialContent; + boost::shared_ptr<JingleContentPayload> initialContent; + CryptoProvider* crypto; State state; - JingleFileTransferDescription::ref description; - WriteBytestream::ref stream; + boost::shared_ptr<JingleFileTransferDescription> description; + boost::shared_ptr<WriteBytestream> stream; boost::uintmax_t receivedBytes; IncrementalBytestreamHashCalculator* hashCalculator; - Timer::ref waitOnHashTimer; - IDGenerator idGenerator; - - RemoteJingleTransportCandidateSelector* candidateSelector; - LocalJingleTransportCandidateGenerator* candidateGenerator; - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - bool remoteTransportCandidateSelectFinished; - JingleTransportPayload::ref selectedRemoteTransportCandidate; - bool localTransportCandidateSelectFinished; - JingleTransportPayload::ref selectedLocalTransportCandidate; - - JingleS5BTransportPayload::ref ourCandidate; - JingleS5BTransportPayload::ref theirCandidate; - CandidateMap ourCandidates; - CandidateMap theirCandidates; - SOCKS5BytestreamClientSession::ref clientSession; - std::string s5bDestination; - std::string s5bSessionID; - SOCKS5BytestreamServerSession* serverSession; + boost::shared_ptr<Timer> waitOnHashTimer; + std::string hashAlgorithm; + std::string hash; + FileTransferOptions options; - JingleTransport::ref activeTransport; + boost::bsignals::scoped_connection writeStreamDataReceivedConnection; + boost::bsignals::scoped_connection waitOnHashTimerTickedConnection; + boost::bsignals::connection transferFinishedConnection; }; } diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp index 6b53a1b..601a97f 100644 --- a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp @@ -5,15 +5,21 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + + #include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h> #include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/MD5.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> namespace Swift { -IncrementalBytestreamHashCalculator::IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1) { - md5Hasher = doMD5 ? new MD5() : NULL; - sha1Hasher = doSHA1 ? new SHA1() : NULL; +IncrementalBytestreamHashCalculator::IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1, CryptoProvider* crypto) { + md5Hasher = doMD5 ? crypto->createMD5() : NULL; + sha1Hasher = doSHA1 ? crypto->createSHA1() : NULL; } @@ -42,19 +48,17 @@ void IncrementalBytestreamHashCalculator::feedData(const SafeByteArray& data) { std::string IncrementalBytestreamHashCalculator::getSHA1String() { - if (sha1Hasher) { - ByteArray result = sha1Hasher->getHash(); - return Hexify::hexify(result); - } else { - return std::string(); + assert(sha1Hasher); + if (!sha1Hash) { + sha1Hash = Hexify::hexify(sha1Hasher->getHash()); } + return *sha1Hash; } std::string IncrementalBytestreamHashCalculator::getMD5String() { - if (md5Hasher) { - ByteArray result = md5Hasher->getHash(); - return Hexify::hexify(result); - } else { - return std::string(); + assert(md5Hasher); + if (!md5Hash) { + md5Hash = Hexify::hexify(md5Hasher->getHash()); } + return *md5Hash; } diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h index 64f4b5f..7b4e124 100644 --- a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h @@ -5,17 +5,25 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once +#include <string> + #include <Swiften/Base/ByteArray.h> #include <Swiften/Base/SafeByteArray.h> +#include <boost/optional.hpp> namespace Swift { - -class MD5; -class SHA1; + class Hash; + class CryptoProvider; class IncrementalBytestreamHashCalculator { public: - IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1); + IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1, CryptoProvider* crypto); ~IncrementalBytestreamHashCalculator(); @@ -27,6 +35,8 @@ public: private: - MD5* md5Hasher; - SHA1* sha1Hasher; + Hash* md5Hasher; + Hash* sha1Hasher; + boost::optional<std::string> md5Hash; + boost::optional<std::string> sha1Hash; }; diff --git a/Swiften/FileTransfer/JingleFileTransfer.cpp b/Swiften/FileTransfer/JingleFileTransfer.cpp new file mode 100644 index 0000000..6eecaa2 --- /dev/null +++ b/Swiften/FileTransfer/JingleFileTransfer.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/JingleFileTransfer.h> + +#include <boost/typeof/typeof.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/FileTransfer/FileTransferTransporter.h> +#include <Swiften/Base/Log.h> + +using namespace Swift; + +JingleFileTransfer::JingleFileTransfer( + boost::shared_ptr<JingleSession> session, + const JID& target, + FileTransferTransporterFactory* transporterFactory) : + session(session), + target(target), + transporterFactory(transporterFactory), + transporter(NULL), + ourCandidateSelectFinished(false), + theirCandidateSelectFinished(false) { + + session->addListener(this); + +} + +JingleFileTransfer::~JingleFileTransfer() { + session->removeListener(this); +} + +void JingleFileTransfer::fillCandidateMap(CandidateMap& map, const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + map.clear(); + foreach (JingleS5BTransportPayload::Candidate candidate, candidates) { + map[candidate.cid] = candidate; + } +} + +/* +std::string JingleFileTransfer::getS5BDstAddr(const JID& requester, const JID& target) const { + return Hexify::hexify(crypto->getSHA1Hash( + createSafeByteArray(s5bSessionID + requester.toString() + target.toString()))); +} +*/ + +const JID& JingleFileTransfer::getInitiator() const { + return session->getInitiator(); +} + +const JID& JingleFileTransfer::getResponder() const { + return target; +} + +FileTransfer::State::Type JingleFileTransfer::getExternalFinishedState(JinglePayload::Reason::Type reason) { + if (reason == JinglePayload::Reason::Cancel || reason == JinglePayload::Reason::Decline) { + return FileTransfer::State::Canceled; + } + else if (reason == JinglePayload::Reason::Success) { + return FileTransfer::State::Finished; + } + else { + return FileTransfer::State::Failed; + } +} + +boost::optional<FileTransferError> JingleFileTransfer::getFileTransferError(JinglePayload::Reason::Type reason) { + if (reason == JinglePayload::Reason::Success) { + return boost::optional<FileTransferError>(); + } + else { + return boost::optional<FileTransferError>(FileTransferError::UnknownError); + } +} + +void JingleFileTransfer::handleRemoteTransportCandidateSelectFinished( + const std::string& s5bSessionID, const boost::optional<JingleS5BTransportPayload::Candidate>& candidate) { + SWIFT_LOG(debug) << std::endl; + + ourCandidateChoice = candidate; + ourCandidateSelectFinished = true; + + JingleS5BTransportPayload::ref s5bPayload = boost::make_shared<JingleS5BTransportPayload>(); + s5bPayload->setSessionID(s5bSessionID); + if (candidate) { + s5bPayload->setCandidateUsed(candidate->cid); + } + else { + s5bPayload->setCandidateError(true); + } + candidateSelectRequestID = session->sendTransportInfo(getContentID(), s5bPayload); + + decideOnCandidates(); +} + +// decide on candidates according to http://xmpp.org/extensions/xep-0260.html#complete +void JingleFileTransfer::decideOnCandidates() { + SWIFT_LOG(debug) << std::endl; + if (!ourCandidateSelectFinished || !theirCandidateSelectFinished) { + SWIFT_LOG(debug) << "Can't make a decision yet!" << std::endl; + return; + } + if (!ourCandidateChoice && !theirCandidateChoice) { + SWIFT_LOG(debug) << "No candidates succeeded." << std::endl; + fallback(); + } + else if (ourCandidateChoice && !theirCandidateChoice) { + startTransferViaRemoteCandidate(); + } + else if (theirCandidateChoice && !ourCandidateChoice) { + startTransferViaLocalCandidate(); + } + else { + SWIFT_LOG(debug) << "Choosing between candidates " + << ourCandidateChoice->cid << "(" << ourCandidateChoice->priority << ")" << " and " + << theirCandidateChoice->cid << "(" << theirCandidateChoice->priority << ")" << std::endl; + if (ourCandidateChoice->priority > theirCandidateChoice->priority) { + startTransferViaRemoteCandidate(); + } + else if (ourCandidateChoice->priority < theirCandidateChoice->priority) { + startTransferViaLocalCandidate(); + } + else { + if (hasPriorityOnCandidateTie()) { + startTransferViaRemoteCandidate(); + } + else { + startTransferViaLocalCandidate(); + } + } + } +} + +void JingleFileTransfer::handleProxyActivateFinished( + const std::string& s5bSessionID, ErrorPayload::ref error) { + SWIFT_LOG(debug) << std::endl; + if (!isWaitingForLocalProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + if (error) { + SWIFT_LOG(debug) << "Error activating proxy" << std::endl; + JingleS5BTransportPayload::ref proxyError = boost::make_shared<JingleS5BTransportPayload>(); + proxyError->setSessionID(s5bSessionID); + proxyError->setProxyError(true); + session->sendTransportInfo(getContentID(), proxyError); + fallback(); + } + else { + JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>(); + proxyActivate->setSessionID(s5bSessionID); + proxyActivate->setActivated(theirCandidateChoice->cid); + session->sendTransportInfo(getContentID(), proxyActivate); + startTransferring(createRemoteCandidateSession()); + } +} + +void JingleFileTransfer::handleTransportInfoReceived( + const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { + SWIFT_LOG(debug) << std::endl; + + if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { + if (s5bPayload->hasCandidateError() || !s5bPayload->getCandidateUsed().empty()) { + SWIFT_LOG(debug) << "Received candidate decision from peer" << std::endl; + if (!isTryingCandidates()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + theirCandidateSelectFinished = true; + if (!s5bPayload->hasCandidateError()) { + BOOST_AUTO(theirCandidate, localCandidates.find(s5bPayload->getCandidateUsed())); + if (theirCandidate == localCandidates.end()) { + SWIFT_LOG(warning) << "Got invalid candidate" << std::endl; + terminate(JinglePayload::Reason::GeneralError); + return; + } + theirCandidateChoice = theirCandidate->second; + } + decideOnCandidates(); + } + else if (!s5bPayload->getActivated().empty()) { + SWIFT_LOG(debug) << "Received peer activate from peer" << std::endl; + if (!isWaitingForPeerProxyActivate()) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + if (ourCandidateChoice->cid == s5bPayload->getActivated()) { + startTransferring(createRemoteCandidateSession()); + } + else { + SWIFT_LOG(warning) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl; + terminate(JinglePayload::Reason::GeneralError); + } + } + else { + SWIFT_LOG(debug) << "Ignoring unknown info" << std::endl; + } + } + else { + SWIFT_LOG(debug) << "Ignoring unknown info" << std::endl; + } +} + +void JingleFileTransfer::setTransporter(FileTransferTransporter* transporter) { + this->transporter = transporter; + localTransportCandidatesGeneratedConnection = transporter->onLocalCandidatesGenerated.connect( + boost::bind(&JingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1, _2)); + remoteTransportCandidateSelectFinishedConnection = transporter->onRemoteCandidateSelectFinished.connect( + boost::bind(&JingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1, _2)); + proxyActivatedConnection = transporter->onProxyActivated.connect( + boost::bind(&JingleFileTransfer::handleProxyActivateFinished, this, _1, _2)); +} + diff --git a/Swiften/FileTransfer/JingleFileTransfer.h b/Swiften/FileTransfer/JingleFileTransfer.h new file mode 100644 index 0000000..ee646c1 --- /dev/null +++ b/Swiften/FileTransfer/JingleFileTransfer.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> + +#include <boost/shared_ptr.hpp> +#include <vector> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/FileTransfer/FileTransfer.h> +#include <Swiften/Jingle/AbstractJingleSessionListener.h> +#include <Swiften/Jingle/JingleContentID.h> + +namespace Swift { + class CryptoProvider; + class IQRouter; + class RemoteJingleTransportCandidateSelector; + class LocalJingleTransportCandidateGenerator; + class JingleSession; + class FileTransferTransporter; + class FileTransferTransporterFactory; + class TransportSession; + + class SWIFTEN_API JingleFileTransfer : public AbstractJingleSessionListener { + public: + JingleFileTransfer( + boost::shared_ptr<JingleSession>, + const JID& target, + FileTransferTransporterFactory*); + virtual ~JingleFileTransfer(); + + protected: + virtual void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); + virtual void handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, + const std::vector<JingleS5BTransportPayload::Candidate>&) = 0; + virtual void handleProxyActivateFinished( + const std::string& s5bSessionID, + ErrorPayload::ref error); + virtual void decideOnCandidates(); + void handleRemoteTransportCandidateSelectFinished( + const std::string& s5bSessionID, const boost::optional<JingleS5BTransportPayload::Candidate>&); + virtual JingleContentID getContentID() const = 0; + virtual void startTransferring(boost::shared_ptr<TransportSession>) = 0; + virtual void terminate(JinglePayload::Reason::Type reason) = 0; + virtual void fallback() = 0; + virtual bool hasPriorityOnCandidateTie() const = 0; + virtual bool isWaitingForPeerProxyActivate() const = 0; + virtual bool isWaitingForLocalProxyActivate() const = 0; + virtual bool isTryingCandidates() const = 0; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession() = 0; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession() = 0; + virtual void startTransferViaLocalCandidate() = 0; + virtual void startTransferViaRemoteCandidate() = 0; + + protected: + typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; + + void setTransporter(FileTransferTransporter* transporter); + void fillCandidateMap( + CandidateMap& map, + const std::vector<JingleS5BTransportPayload::Candidate>&); + const JID& getInitiator() const; + const JID& getResponder() const; + + static FileTransfer::State::Type getExternalFinishedState(JinglePayload::Reason::Type); + static boost::optional<FileTransferError> getFileTransferError(JinglePayload::Reason::Type); + + boost::shared_ptr<JingleSession> session; + JID target; + FileTransferTransporterFactory* transporterFactory; + FileTransferTransporter* transporter; + + std::string candidateSelectRequestID; + bool ourCandidateSelectFinished; + boost::optional<JingleS5BTransportPayload::Candidate> ourCandidateChoice; + bool theirCandidateSelectFinished; + boost::optional<JingleS5BTransportPayload::Candidate> theirCandidateChoice; + CandidateMap localCandidates; + + boost::shared_ptr<TransportSession> transportSession; + + boost::bsignals::scoped_connection localTransportCandidatesGeneratedConnection; + boost::bsignals::scoped_connection remoteTransportCandidateSelectFinishedConnection; + boost::bsignals::scoped_connection proxyActivatedConnection; + }; +} diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp deleted file mode 100644 index ccca641..0000000 --- a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> - -namespace Swift { - -JingleIncomingIBBTransport::JingleIncomingIBBTransport(const JID& from, const JID& to, const std::string& id, size_t size, IQRouter* router) : ibbSession(id, from, to, size, router) { - ibbSession.onDataReceived.connect(boost::ref(onDataReceived)); - ibbSession.onFinished.connect(boost::ref(onFinished)); -} - -void JingleIncomingIBBTransport::start() { - ibbSession.start(); -} - -void JingleIncomingIBBTransport::stop() { - ibbSession.stop(); -} - -} diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.h b/Swiften/FileTransfer/JingleIncomingIBBTransport.h deleted file mode 100644 index be18a2d..0000000 --- a/Swiften/FileTransfer/JingleIncomingIBBTransport.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <boost/shared_ptr.hpp> - -#include <Swiften/FileTransfer/JingleTransport.h> -#include <Swiften/FileTransfer/IBBReceiveSession.h> - -namespace Swift { - class JingleIncomingIBBTransport : public JingleTransport { - public: - typedef boost::shared_ptr<JingleIncomingIBBTransport> ref; - - JingleIncomingIBBTransport(const JID& from, const JID& to, const std::string& id, size_t size, IQRouter* router); - - virtual void start(); - virtual void stop(); - - private: - IBBReceiveSession ibbSession; - }; -} diff --git a/Swiften/FileTransfer/JingleTransport.h b/Swiften/FileTransfer/JingleTransport.h deleted file mode 100644 index fa296e8..0000000 --- a/Swiften/FileTransfer/JingleTransport.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <boost/shared_ptr.hpp> - -#include <Swiften/Base/boost_bsignals.h> -#include <Swiften/FileTransfer/FileTransfer.h> - -namespace Swift { - class JingleTransport { - public: - typedef boost::shared_ptr<JingleTransport> ref; - - virtual ~JingleTransport(); - - virtual void start() = 0; - virtual void stop() = 0; - - boost::signal<void (const std::vector<unsigned char>&)> onDataReceived; - boost::signal<void (boost::optional<FileTransferError>)> onFinished; - }; -} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp index 852902b..53ad53a 100644 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp @@ -1,14 +1,120 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ #include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <vector> + +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h> + +static const unsigned int LOCAL_PREFERENCE = 0; + namespace Swift { +LocalJingleTransportCandidateGenerator::LocalJingleTransportCandidateGenerator( + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + const JID& ownJID, + IDGenerator* idGenerator) : + s5bServerManager(s5bServerManager), + s5bProxy(s5bProxy), + ownJID(ownJID), + idGenerator(idGenerator) { +} + LocalJingleTransportCandidateGenerator::~LocalJingleTransportCandidateGenerator() { + SWIFT_LOG_ASSERT(!s5bServerInitializeRequest, warning) << std::endl; +} + +void LocalJingleTransportCandidateGenerator::start() { + assert(!s5bServerInitializeRequest); + s5bServerInitializeRequest = s5bServerManager->createInitializeRequest(); + s5bServerInitializeRequest->onFinished.connect( + boost::bind(&LocalJingleTransportCandidateGenerator::handleS5BServerInitialized, this, _1)); + + s5bServerInitializeRequest->start(); +} + +void LocalJingleTransportCandidateGenerator::stop() { + if (s5bServerInitializeRequest) { + s5bServerInitializeRequest->stop(); + s5bServerInitializeRequest.reset(); + } } +void LocalJingleTransportCandidateGenerator::handleS5BServerInitialized(bool success) { + std::vector<JingleS5BTransportPayload::Candidate> candidates; + if (success) { + // get direct candidates + std::vector<HostAddressPort> directCandidates = s5bServerManager->getHostAddressPorts(); + foreach(HostAddressPort addressPort, directCandidates) { + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::DirectType; + candidate.jid = ownJID; + candidate.hostPort = addressPort; + candidate.priority = 65536 * 126 + LOCAL_PREFERENCE; + candidate.cid = idGenerator->generateID(); + candidates.push_back(candidate); + } + + // get assissted candidates + std::vector<HostAddressPort> assisstedCandidates = s5bServerManager->getAssistedHostAddressPorts(); + foreach(HostAddressPort addressPort, assisstedCandidates) { + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::AssistedType; + candidate.jid = ownJID; + candidate.hostPort = addressPort; + candidate.priority = 65536 * 120 + LOCAL_PREFERENCE; + candidate.cid = idGenerator->generateID(); + candidates.push_back(candidate); + } + } + else { + SWIFT_LOG(warning) << "Unable to start SOCKS5 server" << std::endl; + } + + s5bServerInitializeRequest->stop(); + s5bServerInitializeRequest.reset(); + + onLocalTransportCandidatesGenerated(candidates); +} + +/*void LocalJingleTransportCandidateGenerator::handleS5BProxiesDiscovered() { + foreach(S5BProxyRequest::ref proxy, s5bProxiesDiscoverRequest->getS5BProxies()) { + if (proxy->getStreamHost()) { // FIXME: Added this test, because there were cases where this wasn't initialized. Investigate this. (Remko) + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::ProxyType; + candidate.jid = (*proxy->getStreamHost()).jid; + candidate.hostPort = (*proxy->getStreamHost()).addressPort; + candidate.priority = 65536 * 10 + LOCAL_PREFERENCE; + candidate.cid = idGenerator.generateID(); + s5bCandidatesPayload->addCandidate(candidate); + } + } + + haveS5BProxyCandidates = true; + s5bProxiesDiscoverRequest->stop(); + s5bProxiesDiscoverRequest.reset(); + + checkS5BCandidatesReady(); +}*/ + } diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h index 041afe3..02dfef5 100644 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h @@ -1,6 +1,12 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ @@ -8,22 +14,41 @@ #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> -#include <Swiften/Elements/JingleTransportPayload.h> -#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Base/Override.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> namespace Swift { + class SOCKS5BytestreamServerManager; + class SOCKS5BytestreamProxiesManager; + class SOCKS5BytestreamServerInitializeRequest; + class JingleS5BTransportPayload; + class LocalJingleTransportCandidateGenerator { public: + LocalJingleTransportCandidateGenerator( + SOCKS5BytestreamServerManager* s5bServerManager, + SOCKS5BytestreamProxiesManager* s5bProxy, + const JID& ownJID, + IDGenerator* idGenerator); virtual ~LocalJingleTransportCandidateGenerator(); - /** - * Should call onLocalTransportCandidatesGenerated if it has finished discovering local candidates. - */ - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref) = 0; - virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; - virtual int getPriority(JingleTransportPayload::ref) = 0; - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + virtual void start(); + virtual void stop(); + + boost::signal<void (const std::vector<JingleS5BTransportPayload::Candidate>&)> onLocalTransportCandidatesGenerated; + + private: + void handleS5BServerInitialized(bool success); + void checkS5BCandidatesReady(); - boost::signal<void (JingleTransportPayload::ref)> onLocalTransportCandidatesGenerated; + private: + SOCKS5BytestreamServerManager* s5bServerManager; + SOCKS5BytestreamProxiesManager* s5bProxy; + JID ownJID; + IDGenerator* idGenerator; + boost::shared_ptr<SOCKS5BytestreamServerInitializeRequest> s5bServerInitializeRequest; }; } diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp deleted file mode 100644 index a1e3874..0000000 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> - -namespace Swift { - -LocalJingleTransportCandidateGeneratorFactory::~LocalJingleTransportCandidateGeneratorFactory() { -} - -} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h deleted file mode 100644 index c969fc7..0000000 --- a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -namespace Swift { - class LocalJingleTransportCandidateGenerator; - - class LocalJingleTransportCandidateGeneratorFactory { - public: - virtual ~LocalJingleTransportCandidateGeneratorFactory(); - - virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() = 0; - }; -} diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.h b/Swiften/FileTransfer/OutgoingFileTransfer.h index 1ec1ae3..59dc718 100644 --- a/Swiften/FileTransfer/OutgoingFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingFileTransfer.h @@ -19,5 +19,4 @@ namespace Swift { virtual void start() = 0; - virtual void stop() = 0; }; } diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp index 6f23bb7..4b3c6b5 100644 --- a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp @@ -5,5 +5,11 @@ */ -#include "OutgoingFileTransferManager.h" +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/OutgoingFileTransferManager.h> #include <boost/smart_ptr/make_shared.hpp> @@ -18,5 +24,13 @@ namespace Swift { -OutgoingFileTransferManager::OutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy) { +OutgoingFileTransferManager::OutgoingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + CryptoProvider* crypto) : + jingleSessionManager(jingleSessionManager), + iqRouter(router), + transporterFactory(transporterFactory), + crypto(crypto) { idGenerator = new IDGenerator(); } @@ -26,20 +40,22 @@ OutgoingFileTransferManager::~OutgoingFileTransferManager() { } -boost::shared_ptr<OutgoingFileTransfer> OutgoingFileTransferManager::createOutgoingFileTransfer(const JID& from, const JID& receipient, boost::shared_ptr<ReadBytestream> readBytestream, const StreamInitiationFileInfo& fileInfo) { - // check if receipient support Jingle FT - - - JingleSessionImpl::ref jingleSession = boost::make_shared<JingleSessionImpl>(from, receipient, idGenerator->generateID(), iqRouter); - - //jsManager->getSession(receipient, idGenerator->generateID()); - assert(jingleSession); - jsManager->registerOutgoingSession(from, jingleSession); - boost::shared_ptr<OutgoingJingleFileTransfer> jingleFT = boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(jingleSession, remoteFactory, localFactory, iqRouter, idGenerator, from, receipient, readBytestream, fileInfo, bytestreamRegistry, bytestreamProxy)); - - // otherwise try SI - - // else fail - - return jingleFT; +boost::shared_ptr<OutgoingFileTransfer> OutgoingFileTransferManager::createOutgoingFileTransfer( + const JID& from, + const JID& recipient, + boost::shared_ptr<ReadBytestream> readBytestream, + const StreamInitiationFileInfo& fileInfo, + const FileTransferOptions& config) { + JingleSessionImpl::ref jingleSession = boost::make_shared<JingleSessionImpl>( + from, recipient, idGenerator->generateID(), iqRouter); + jingleSessionManager->registerOutgoingSession(from, jingleSession); + return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer( + recipient, + jingleSession, + readBytestream, + transporterFactory, + idGenerator, + fileInfo, + config, + crypto)); } diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.h b/Swiften/FileTransfer/OutgoingFileTransferManager.h index c686001..17a489d 100644 --- a/Swiften/FileTransfer/OutgoingFileTransferManager.h +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.h @@ -5,17 +5,18 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <boost/shared_ptr.hpp> -#include <Swiften/JID/JID.h> - namespace Swift { - class JingleSessionManager; class IQRouter; -class EntityCapsProvider; -class RemoteJingleTransportCandidateSelectorFactory; -class LocalJingleTransportCandidateGeneratorFactory; + class FileTransferTransporterFactory; class OutgoingFileTransfer; class JID; @@ -23,24 +24,29 @@ class IDGenerator; class ReadBytestream; class StreamInitiationFileInfo; -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; + class CryptoProvider; + class FileTransferOptions; class OutgoingFileTransferManager { public: - OutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy); + OutgoingFileTransferManager( + JingleSessionManager* jingleSessionManager, + IQRouter* router, + FileTransferTransporterFactory* transporterFactory, + CryptoProvider* crypto); ~OutgoingFileTransferManager(); - boost::shared_ptr<OutgoingFileTransfer> createOutgoingFileTransfer(const JID& from, const JID& to, boost::shared_ptr<ReadBytestream>, const StreamInitiationFileInfo&); + boost::shared_ptr<OutgoingFileTransfer> createOutgoingFileTransfer( + const JID& from, + const JID& to, + boost::shared_ptr<ReadBytestream>, + const StreamInitiationFileInfo&, + const FileTransferOptions&); private: - JingleSessionManager* jsManager; + JingleSessionManager* jingleSessionManager; IQRouter* iqRouter; - EntityCapsProvider* capsProvider; - RemoteJingleTransportCandidateSelectorFactory* remoteFactory; - LocalJingleTransportCandidateGeneratorFactory* localFactory; + FileTransferTransporterFactory* transporterFactory; IDGenerator* idGenerator; - SOCKS5BytestreamRegistry* bytestreamRegistry; - SOCKS5BytestreamProxy* bytestreamProxy; + CryptoProvider* crypto; }; - } diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp index 5e2a1c3..7bcee4b 100644 --- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp @@ -5,13 +5,25 @@ */ -#include "OutgoingJingleFileTransfer.h" +/* + * Copyright (C) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +// TODO: +// - We should handle incoming terminates after we have terminated, so the other +// side can warn that he didn't receive all bytes correctly. +// - Should the proby stuff also wait for candidate used acknowledgement? + +#include <Swiften/FileTransfer/OutgoingJingleFileTransfer.h> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/typeof/typeof.hpp> -#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/foreach.h> #include <Swiften/Base/IDGenerator.h> #include <Swiften/Jingle/JingleContentID.h> +#include <Swiften/Jingle/JingleSession.h> #include <Swiften/Elements/JingleFileTransferDescription.h> #include <Swiften/Elements/JingleFileTransferHash.h> @@ -19,384 +31,313 @@ #include <Swiften/Elements/JingleIBBTransportPayload.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> -#include <Swiften/Queries/GenericRequest.h> -#include <Swiften/FileTransfer/IBBSendSession.h> #include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> -#include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/FileTransfer/FileTransferTransporter.h> +#include <Swiften/FileTransfer/FileTransferTransporterFactory.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/FileTransfer/TransportSession.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Base/Log.h> -namespace Swift { +using namespace Swift; -OutgoingJingleFileTransfer::OutgoingJingleFileTransfer(JingleSession::ref session, - RemoteJingleTransportCandidateSelectorFactory* remoteFactory, - LocalJingleTransportCandidateGeneratorFactory* localFactory, - IQRouter* router, - IDGenerator *idGenerator, - const JID& fromJID, +static const int DEFAULT_BLOCK_SIZE = 4096; + +OutgoingJingleFileTransfer::OutgoingJingleFileTransfer( const JID& toJID, - boost::shared_ptr<ReadBytestream> readStream, + JingleSession::ref session, + boost::shared_ptr<ReadBytestream> stream, + FileTransferTransporterFactory* transporterFactory, + IDGenerator* idGenerator, const StreamInitiationFileInfo& fileInfo, - SOCKS5BytestreamRegistry* bytestreamRegistry, - SOCKS5BytestreamProxy* bytestreamProxy) : - session(session), remoteFactory(remoteFactory), localFactory(localFactory), router(router), idGenerator(idGenerator), fromJID(fromJID), toJID(toJID), readStream(readStream), fileInfo(fileInfo), s5bRegistry(bytestreamRegistry), s5bProxy(bytestreamProxy), serverSession(NULL), contentID(JingleContentID(idGenerator->generateID(), JingleContentPayload::InitiatorCreator)), canceled(false) { - session->onSessionAcceptReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleSessionAcceptReceived, this, _1, _2, _3)); - session->onSessionTerminateReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleSessionTerminateReceived, this, _1)); - session->onTransportInfoReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2)); - session->onTransportAcceptReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransportAcceptReceived, this, _1, _2)); - fileSizeInBytes = fileInfo.getSize(); - filename = fileInfo.getName(); - - localCandidateGenerator = localFactory->createCandidateGenerator(); - localCandidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1)); - - remoteCandidateSelector = remoteFactory->createCandidateSelector(); - remoteCandidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1)); + const FileTransferOptions& options, + CryptoProvider* crypto) : + JingleFileTransfer(session, toJID, transporterFactory), + idGenerator(idGenerator), + stream(stream), + fileInfo(fileInfo), + options(options), + contentID(idGenerator->generateID(), JingleContentPayload::InitiatorCreator), + state(Initial), + candidateAcknowledged(false) { + + setFileInfo(fileInfo.getName(), fileInfo.getSize()); + // calculate both, MD5 and SHA-1 since we don't know which one the other side supports - hashCalculator = new IncrementalBytestreamHashCalculator(true, true); - this->readStream->onRead.connect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); + hashCalculator = new IncrementalBytestreamHashCalculator(true, true, crypto); + stream->onRead.connect( + boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); } OutgoingJingleFileTransfer::~OutgoingJingleFileTransfer() { - readStream->onRead.disconnect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); + stream->onRead.disconnect( + boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); delete hashCalculator; } void OutgoingJingleFileTransfer::start() { - onStateChange(FileTransfer::State(FileTransfer::State::WaitingForStart)); - - s5bSessionID = s5bRegistry->generateSessionID(); - SWIFT_LOG(debug) << "S5B SessionID: " << s5bSessionID << std::endl; - - //s5bProxy->connectToProxies(s5bSessionID); + SWIFT_LOG(debug) << std::endl; + if (state != Initial) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } - JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); - localCandidateGenerator->generateLocalTransportCandidates(transport); + setTransporter(transporterFactory->createInitiatorTransporter(getInitiator(), getResponder())); + setState(GeneratingInitialLocalCandidates); + transporter->startGeneratingLocalCandidates(); } -void OutgoingJingleFileTransfer::stop() { - +void OutgoingJingleFileTransfer::cancel() { + terminate(JinglePayload::Reason::Cancel); } -void OutgoingJingleFileTransfer::cancel() { - canceled = true; - session->sendTerminate(JinglePayload::Reason::Cancel); +void OutgoingJingleFileTransfer::terminate(JinglePayload::Reason::Type reason) { + SWIFT_LOG(debug) << reason << std::endl; - if (ibbSession) { - ibbSession->stop(); + if (state != Initial && state != GeneratingInitialLocalCandidates && state != Finished) { + session->sendTerminate(reason); } - SOCKS5BytestreamServerSession *serverSession = s5bRegistry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); - if (serverSession) { - serverSession->stop(); - } - if (clientSession) { - clientSession->stop(); - } - onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); + stopAll(); + setFinishedState(getExternalFinishedState(reason), getFileTransferError(reason)); } -void OutgoingJingleFileTransfer::handleSessionAcceptReceived(const JingleContentID& id, JingleDescription::ref /* decription */, JingleTransportPayload::ref transportPayload) { - if (canceled) { - return; - } - onStateChange(FileTransfer::State(FileTransfer::State::Negotiating)); +void OutgoingJingleFileTransfer::handleSessionAcceptReceived( + const JingleContentID&, + JingleDescription::ref, + JingleTransportPayload::ref transportPayload) { + SWIFT_LOG(debug) << std::endl; + if (state != WaitingForAccept) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } - JingleIBBTransportPayload::ref ibbPayload; - JingleS5BTransportPayload::ref s5bPayload; - if ((ibbPayload = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transportPayload))) { - ibbSession = boost::make_shared<IBBSendSession>(ibbPayload->getSessionID(), fromJID, toJID, readStream, router); - ibbSession->setBlockSize(ibbPayload->getBlockSize()); - ibbSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - ibbSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - ibbSession->start(); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } - else if ((s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload))) { - fillCandidateMap(theirCandidates, s5bPayload); - remoteCandidateSelector->setRequesterTargtet(toJID, session->getInitiator()); - remoteCandidateSelector->addRemoteTransportCandidates(s5bPayload); - remoteCandidateSelector->selectCandidate(); + if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload)) { + transporter->addRemoteCandidates(s5bPayload->getCandidates()); + setState(TryingCandidates); + transporter->startTryingRemoteCandidates(); } else { - // TODO: error handling - SWIFT_LOG(debug) << "Unknown transport payload! Try replaceing with IBB." << std::endl; - replaceTransportWithIBB(id); + SWIFT_LOG(debug) << "Unknown transport payload. Falling back." << std::endl; + fallback(); } } void OutgoingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { - if (canceled) { - return; - } + SWIFT_LOG(debug) << std::endl; + if (state == Finished) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } - if (ibbSession) { - ibbSession->stop(); - } - if (clientSession) { - clientSession->stop(); + stopAll(); + if (reason && reason->type == JinglePayload::Reason::Cancel) { + setFinishedState(FileTransfer::State::Canceled, FileTransferError(FileTransferError::PeerError)); } - if (serverSession) { - serverSession->stop(); + else if (reason && reason->type == JinglePayload::Reason::Success) { + setFinishedState(FileTransfer::State::Finished, boost::optional<FileTransferError>()); } - - if (reason.is_initialized() && reason.get().type == JinglePayload::Reason::Cancel) { - onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); - onFinished(FileTransferError(FileTransferError::PeerError)); - } else if (reason.is_initialized() && reason.get().type == JinglePayload::Reason::Success) { - onStateChange(FileTransfer::State(FileTransfer::State::Finished)); - onFinished(boost::optional<FileTransferError>()); - } else { - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - onFinished(FileTransferError(FileTransferError::PeerError)); + else { + setFinishedState(FileTransfer::State::Failed, FileTransferError(FileTransferError::PeerError)); } - canceled = true; } -void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { - if (canceled) { - return; - } +void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleContentID&, JingleTransportPayload::ref transport) { + SWIFT_LOG(debug) << std::endl; + if (state != FallbackRequested) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } if (JingleIBBTransportPayload::ref ibbPayload = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { - ibbSession = boost::make_shared<IBBSendSession>(ibbPayload->getSessionID(), fromJID, toJID, readStream, router); - ibbSession->setBlockSize(ibbPayload->getBlockSize()); - ibbSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - ibbSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - ibbSession->start(); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } else { - // error handling - SWIFT_LOG(debug) << "Replacing with anything other than IBB isn't supported yet." << std::endl; - session->sendTerminate(JinglePayload::Reason::FailedTransport); - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - } -} - -void OutgoingJingleFileTransfer::startTransferViaOurCandidateChoice(JingleS5BTransportPayload::Candidate candidate) { - SWIFT_LOG(debug) << "Transferring data using our candidate." << std::endl; - if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - // get proxy client session from remoteCandidateSelector - clientSession = remoteCandidateSelector->getS5BSession(); - - // wait on <activated/> transport-info - } else { - clientSession = remoteCandidateSelector->getS5BSession(); - clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startSending(readStream); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } - assert(clientSession); -} - -void OutgoingJingleFileTransfer::startTransferViaTheirCandidateChoice(JingleS5BTransportPayload::Candidate candidate) { - SWIFT_LOG(debug) << "Transferring data using their candidate." << std::endl; - if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { - // connect to proxy - clientSession = s5bProxy->createSOCKS5BytestreamClientSession(candidate.hostPort, SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); - clientSession->onSessionReady.connect(boost::bind(&OutgoingJingleFileTransfer::proxySessionReady, this, candidate.jid, _1)); - clientSession->start(); - - // on reply send activate - - } else { - serverSession = s5bRegistry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); - serverSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - serverSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - serverSession->startTransfer(); - } - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); -} - -// decide on candidates according to http://xmpp.org/extensions/xep-0260.html#complete -void OutgoingJingleFileTransfer::decideOnCandidates() { - if (ourCandidateChoice && theirCandidateChoice) { - std::string our_cid = ourCandidateChoice->getCandidateUsed(); - std::string their_cid = theirCandidateChoice->getCandidateUsed(); - if (ourCandidateChoice->hasCandidateError() && theirCandidateChoice->hasCandidateError()) { - replaceTransportWithIBB(contentID); - } - else if (!our_cid.empty() && theirCandidateChoice->hasCandidateError()) { - // use our candidate - startTransferViaOurCandidateChoice(theirCandidates[our_cid]); - } - else if (!their_cid.empty() && ourCandidateChoice->hasCandidateError()) { - // use their candidate - startTransferViaTheirCandidateChoice(ourCandidates[their_cid]); - } - else if (!our_cid.empty() && !their_cid.empty()) { - // compare priorites, if same we win - if (ourCandidates.find(their_cid) == ourCandidates.end() || theirCandidates.find(our_cid) == theirCandidates.end()) { - SWIFT_LOG(debug) << "Didn't recognize candidate IDs!" << std::endl; - session->sendTerminate(JinglePayload::Reason::FailedTransport); - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - onFinished(FileTransferError(FileTransferError::PeerError)); - return; - } - - JingleS5BTransportPayload::Candidate ourCandidate = theirCandidates[our_cid]; - JingleS5BTransportPayload::Candidate theirCandidate = ourCandidates[their_cid]; - if (ourCandidate.priority > theirCandidate.priority) { - startTransferViaOurCandidateChoice(ourCandidate); - } - else if (ourCandidate.priority < theirCandidate.priority) { - startTransferViaTheirCandidateChoice(theirCandidate); + startTransferring(transporter->createIBBSendSession(ibbPayload->getSessionID(), ibbPayload->getBlockSize().get_value_or(DEFAULT_BLOCK_SIZE), stream)); } else { - startTransferViaOurCandidateChoice(ourCandidate); + SWIFT_LOG(debug) << "Unknown transport replacement" << std::endl; + terminate(JinglePayload::Reason::FailedTransport); } } - } else { - SWIFT_LOG(debug) << "Can't make a decision yet!" << std::endl; + +void OutgoingJingleFileTransfer::sendSessionInfoHash() { + SWIFT_LOG(debug) << std::endl; + + JingleFileTransferHash::ref hashElement = boost::make_shared<JingleFileTransferHash>(); + hashElement->setHash("sha-1", hashCalculator->getSHA1String()); + hashElement->setHash("md5", hashCalculator->getMD5String()); + session->sendInfo(hashElement); } + +void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated( + const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + SWIFT_LOG(debug) << std::endl; + if (state != GeneratingInitialLocalCandidates) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + + fillCandidateMap(localCandidates, candidates); + + JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); + description->addOffer(fileInfo); + + JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); + transport->setSessionID(s5bSessionID); + transport->setMode(JingleS5BTransportPayload::TCPMode); + foreach(JingleS5BTransportPayload::Candidate candidate, candidates) { + transport->addCandidate(candidate); + } + setState(WaitingForAccept); + session->sendInitiate(contentID, description, transport); } -void OutgoingJingleFileTransfer::fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload) { - map.clear(); - foreach (JingleS5BTransportPayload::Candidate candidate, s5bPayload->getCandidates()) { - map[candidate.cid] = candidate; +void OutgoingJingleFileTransfer::fallback() { + SWIFT_LOG(debug) << std::endl; + if (options.isInBandAllowed()) { + JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>(); + ibbTransport->setBlockSize(DEFAULT_BLOCK_SIZE); + ibbTransport->setSessionID(idGenerator->generateID()); + setState(FallbackRequested); + session->sendTransportReplace(contentID, ibbTransport); + } + else { + terminate(JinglePayload::Reason::ConnectivityError); } } -void OutgoingJingleFileTransfer::proxySessionReady(const JID& proxy, bool error) { +void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { + SWIFT_LOG(debug) << std::endl; + if (state != Transferring) { SWIFT_LOG(warning) << "Incorrect state" << std::endl; return; } + if (error) { - // indicate proxy error - } else { - // activate proxy - activateProxySession(proxy); + terminate(JinglePayload::Reason::ConnectivityError); + } + else { + sendSessionInfoHash(); + terminate(JinglePayload::Reason::Success); } } -void OutgoingJingleFileTransfer::activateProxySession(const JID& proxy) { - S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); - proxyRequest->setSID(s5bSessionID); - proxyRequest->setActivate(toJID); +void OutgoingJingleFileTransfer::startTransferring(boost::shared_ptr<TransportSession> transportSession) { + SWIFT_LOG(debug) << std::endl; - boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxy, proxyRequest, router); - request->onResponse.connect(boost::bind(&OutgoingJingleFileTransfer::handleActivateProxySessionResult, this, _1, _2)); - request->send(); + this->transportSession = transportSession; + processedBytesConnection = transportSession->onBytesSent.connect( + boost::bind(boost::ref(onProcessedBytes), _1)); + transferFinishedConnection = transportSession->onFinished.connect( + boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + setState(Transferring); + transportSession->start(); } -void OutgoingJingleFileTransfer::handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> /*request*/, ErrorPayload::ref error) { - if (error) { - SWIFT_LOG(debug) << "ERROR" << std::endl; - } else { - // send activated to other jingle party - JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>(); - proxyActivate->setActivated(theirCandidateChoice->getCandidateUsed()); - session->sendTransportInfo(contentID, proxyActivate); - // start transferring - clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startSending(readStream); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } +void OutgoingJingleFileTransfer::setState(State state) { + SWIFT_LOG(debug) << state << std::endl; + this->state = state; + onStateChanged(FileTransfer::State(getExternalState(state))); } -void OutgoingJingleFileTransfer::sendSessionInfoHash() { +void OutgoingJingleFileTransfer::setFinishedState( + FileTransfer::State::Type type, const boost::optional<FileTransferError>& error) { SWIFT_LOG(debug) << std::endl; - JingleFileTransferHash::ref hashElement = boost::make_shared<JingleFileTransferHash>(); - hashElement->setHash("sha-1", hashCalculator->getSHA1String()); - hashElement->setHash("md5", hashCalculator->getMD5String()); - session->sendInfo(hashElement); + this->state = Finished; + onStateChanged(type); + onFinished(error); } -void OutgoingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { - if (canceled) { - return; +FileTransfer::State::Type OutgoingJingleFileTransfer::getExternalState(State state) { + switch (state) { + case Initial: return FileTransfer::State::Initial; + case GeneratingInitialLocalCandidates: return FileTransfer::State::WaitingForStart; + case WaitingForAccept: return FileTransfer::State::WaitingForAccept; + case TryingCandidates: return FileTransfer::State::Negotiating; + case WaitingForPeerProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForLocalProxyActivate: return FileTransfer::State::Negotiating; + case WaitingForCandidateAcknowledge: return FileTransfer::State::Negotiating; + case FallbackRequested: return FileTransfer::State::Negotiating; + case Transferring: return FileTransfer::State::Transferring; + case Finished: return FileTransfer::State::Finished; + } + assert(false); + return FileTransfer::State::Initial; +} + +void OutgoingJingleFileTransfer::stopAll() { + SWIFT_LOG(debug) << state << std::endl; + switch (state) { + case Initial: SWIFT_LOG(warning) << "Not yet started" << std::endl; break; + case GeneratingInitialLocalCandidates: transporter->stopGeneratingLocalCandidates(); break; + case WaitingForAccept: break; + case TryingCandidates: transporter->stopTryingRemoteCandidates(); break; + case FallbackRequested: break; + case WaitingForPeerProxyActivate: break; + case WaitingForLocalProxyActivate: transporter->stopActivatingProxy(); break; + case WaitingForCandidateAcknowledge: // Fallthrough + case Transferring: + assert(transportSession); + processedBytesConnection.disconnect(); + transferFinishedConnection.disconnect(); + transportSession->stop(); + transportSession.reset(); + break; + case Finished: SWIFT_LOG(warning) << "Already finished" << std::endl; break; + } + if (state != Initial) { + delete transporter; + } +} + +void OutgoingJingleFileTransfer::startTransferViaRemoteCandidate() { + SWIFT_LOG(debug) << std::endl; + + if (ourCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForPeerProxyActivate); } - if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { - if (s5bPayload->hasCandidateError() || !s5bPayload->getCandidateUsed().empty()) { - theirCandidateChoice = s5bPayload; - decideOnCandidates(); - } else if(!s5bPayload->getActivated().empty()) { - if (ourCandidateChoice->getCandidateUsed() == s5bPayload->getActivated()) { - clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); - clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - clientSession->startSending(readStream); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); - } else { - SWIFT_LOG(debug) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl; - JingleS5BTransportPayload::ref proxyError = boost::make_shared<JingleS5BTransportPayload>(); - proxyError->setProxyError(true); - proxyError->setSessionID(s5bSessionID); - session->sendTransportInfo(contentID, proxyError); + else { + transportSession = createRemoteCandidateSession(); + startTransferringIfCandidateAcknowledged(); } } + +void OutgoingJingleFileTransfer::startTransferViaLocalCandidate() { + SWIFT_LOG(debug) << std::endl; + + if (theirCandidateChoice->type == JingleS5BTransportPayload::Candidate::ProxyType) { + setState(WaitingForLocalProxyActivate); + transporter->startActivatingProxy(theirCandidateChoice->jid); } + else { + transportSession = createLocalCandidateSession(); + startTransferringIfCandidateAcknowledged(); } - -void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { - if (canceled) { - return; } - JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); - description->addOffer(fileInfo); - JingleTransportPayload::ref transport; - if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(payload)) { - ibbTransport->setBlockSize(4096); - ibbTransport->setSessionID(idGenerator->generateID()); - transport = ibbTransport; +void OutgoingJingleFileTransfer::startTransferringIfCandidateAcknowledged() { + if (candidateAcknowledged) { + startTransferring(transportSession); + } + else { + setState(WaitingForCandidateAcknowledge); + } } - else if (JingleS5BTransportPayload::ref s5bTransport = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(payload)) { - //fillCandidateMap(ourCandidates, s5bTransport); - //s5bTransport->setSessionID(s5bSessionID); - - JingleS5BTransportPayload::ref emptyCandidates = boost::make_shared<JingleS5BTransportPayload>(); - emptyCandidates->setSessionID(s5bTransport->getSessionID()); - fillCandidateMap(ourCandidates, emptyCandidates); - transport = emptyCandidates; - s5bRegistry->addReadBytestream(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID), readStream); +void OutgoingJingleFileTransfer::handleTransportInfoAcknowledged(const std::string& id) { + if (id == candidateSelectRequestID) { + candidateAcknowledged = true; } - else { - SWIFT_LOG(debug) << "Unknown tranport payload: " << typeid(*payload).name() << std::endl; - return; + if (state == WaitingForCandidateAcknowledge) { + startTransferring(transportSession); } - session->sendInitiate(contentID, description, transport); - onStateChange(FileTransfer::State(FileTransfer::State::WaitingForAccept)); } -void OutgoingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref payload) { - if (canceled) { - return; +JingleContentID OutgoingJingleFileTransfer::getContentID() const { + return contentID; } - if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(payload)) { - ourCandidateChoice = s5bPayload; - session->sendTransportInfo(contentID, s5bPayload); - decideOnCandidates(); + +bool OutgoingJingleFileTransfer::hasPriorityOnCandidateTie() const { + return true; } + +bool OutgoingJingleFileTransfer::isWaitingForPeerProxyActivate() const { + return state == WaitingForPeerProxyActivate; } -void OutgoingJingleFileTransfer::replaceTransportWithIBB(const JingleContentID& id) { - SWIFT_LOG(debug) << "Both parties failed. Replace transport with IBB." << std::endl; - JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>(); - ibbTransport->setBlockSize(4096); - ibbTransport->setSessionID(idGenerator->generateID()); - session->sendTransportReplace(id, ibbTransport); +bool OutgoingJingleFileTransfer::isWaitingForLocalProxyActivate() const { + return state == WaitingForLocalProxyActivate; } -void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { - if (error) { - session->sendTerminate(JinglePayload::Reason::ConnectivityError); - onStateChange(FileTransfer::State(FileTransfer::State::Failed)); - onFinished(error); - } else { - sendSessionInfoHash(); - /* - session->terminate(JinglePayload::Reason::Success); - onStateChange(FileTransfer::State(FileTransfer::State::Finished)); - */ +bool OutgoingJingleFileTransfer::isTryingCandidates() const { + return state == TryingCandidates; } - // + +boost::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createLocalCandidateSession() { + return transporter->createLocalCandidateSession(stream); } +boost::shared_ptr<TransportSession> OutgoingJingleFileTransfer::createRemoteCandidateSession() { + return transporter->createRemoteCandidateSession(stream); } + diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h index ff7bfc7..d1f4dc4 100644 --- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h @@ -5,112 +5,108 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once #include <boost/shared_ptr.hpp> +#include <boost/optional/optional.hpp> -#include <Swiften/Elements/JingleContentPayload.h> -#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> +#include <Swiften/Jingle/JingleContentID.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/Elements/ErrorPayload.h> #include <Swiften/FileTransfer/OutgoingFileTransfer.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> -#include <Swiften/Jingle/JingleContentID.h> -#include <Swiften/Jingle/JingleSession.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/FileTransfer/JingleFileTransfer.h> +#include <Swiften/FileTransfer/FileTransferOptions.h> namespace Swift { - -class RemoteJingleTransportCandidateSelectorFactory; -class RemoteJingleTransportCandidateSelector; -class LocalJingleTransportCandidateGeneratorFactory; -class LocalJingleTransportCandidateGenerator; -class IQRouter; class ReadBytestream; -class IBBSendSession; class IDGenerator; class IncrementalBytestreamHashCalculator; -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; + class CryptoProvider; + class FileTransferTransporter; + class FileTransferTransporterFactory; + class TransportSession; -class OutgoingJingleFileTransfer : public OutgoingFileTransfer { + class SWIFTEN_API OutgoingJingleFileTransfer : public OutgoingFileTransfer, public JingleFileTransfer { public: - OutgoingJingleFileTransfer(JingleSession::ref, - RemoteJingleTransportCandidateSelectorFactory*, - LocalJingleTransportCandidateGeneratorFactory*, - IQRouter*, - IDGenerator*, - const JID& from, + OutgoingJingleFileTransfer( const JID& to, + boost::shared_ptr<JingleSession>, boost::shared_ptr<ReadBytestream>, + FileTransferTransporterFactory*, + IDGenerator*, const StreamInitiationFileInfo&, - SOCKS5BytestreamRegistry*, - SOCKS5BytestreamProxy*); + const FileTransferOptions&, + CryptoProvider*); virtual ~OutgoingJingleFileTransfer(); void start(); - void stop(); - void cancel(); private: - void handleSessionAcceptReceived(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); - void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason); - void handleTransportAcceptReceived(const JingleContentID&, JingleTransportPayload::ref); - void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); + enum State { + Initial, + GeneratingInitialLocalCandidates, + WaitingForAccept, + TryingCandidates, + WaitingForPeerProxyActivate, + WaitingForLocalProxyActivate, + WaitingForCandidateAcknowledge, + FallbackRequested, + Transferring, + Finished + }; - void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref); - void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref); + virtual void handleSessionAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleDescription>, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + virtual void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) SWIFTEN_OVERRIDE; + virtual void handleTransportAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + void startTransferViaRemoteCandidate(); + void startTransferViaLocalCandidate(); + void startTransferringIfCandidateAcknowledged(); -private: - void replaceTransportWithIBB(const JingleContentID&); - void handleTransferFinished(boost::optional<FileTransferError>); - void activateProxySession(const JID &proxy); - void handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error); - void proxySessionReady(const JID& proxy, bool error); + virtual void handleLocalTransportCandidatesGenerated(const std::string& s5bSessionID, const std::vector<JingleS5BTransportPayload::Candidate>&) SWIFTEN_OVERRIDE; + virtual void handleTransportInfoAcknowledged(const std::string& id) SWIFTEN_OVERRIDE; -private: - typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; + virtual JingleContentID getContentID() const SWIFTEN_OVERRIDE; -private: - void startTransferViaOurCandidateChoice(JingleS5BTransportPayload::Candidate); - void startTransferViaTheirCandidateChoice(JingleS5BTransportPayload::Candidate); - void decideOnCandidates(); - void fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload); + virtual void terminate(JinglePayload::Reason::Type reason) SWIFTEN_OVERRIDE; + + virtual void fallback() SWIFTEN_OVERRIDE; + void handleTransferFinished(boost::optional<FileTransferError>); -private: void sendSessionInfoHash(); -private: - JingleSession::ref session; - RemoteJingleTransportCandidateSelector* remoteCandidateSelector; - RemoteJingleTransportCandidateSelectorFactory* remoteFactory; - LocalJingleTransportCandidateGenerator* localCandidateGenerator; - LocalJingleTransportCandidateGeneratorFactory* localFactory; + virtual void startTransferring(boost::shared_ptr<TransportSession>) SWIFTEN_OVERRIDE; - IQRouter* router; - IDGenerator* idGenerator; - JID fromJID; - JID toJID; - boost::shared_ptr<ReadBytestream> readStream; - StreamInitiationFileInfo fileInfo; - IncrementalBytestreamHashCalculator *hashCalculator; + virtual bool hasPriorityOnCandidateTie() const SWIFTEN_OVERRIDE; + virtual bool isWaitingForPeerProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isWaitingForLocalProxyActivate() const SWIFTEN_OVERRIDE; + virtual bool isTryingCandidates() const SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createLocalCandidateSession() SWIFTEN_OVERRIDE; + virtual boost::shared_ptr<TransportSession> createRemoteCandidateSession() SWIFTEN_OVERRIDE; - boost::shared_ptr<IBBSendSession> ibbSession; + void stopAll(); + void setState(State state); + void setFinishedState(FileTransfer::State::Type, const boost::optional<FileTransferError>& error); - JingleS5BTransportPayload::ref ourCandidateChoice; - JingleS5BTransportPayload::ref theirCandidateChoice; - CandidateMap ourCandidates; - CandidateMap theirCandidates; + static FileTransfer::State::Type getExternalState(State state); - SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; - SOCKS5BytestreamClientSession::ref clientSession; - SOCKS5BytestreamServerSession* serverSession; + private: + IDGenerator* idGenerator; + boost::shared_ptr<ReadBytestream> stream; + StreamInitiationFileInfo fileInfo; + FileTransferOptions options; JingleContentID contentID; - std::string s5bSessionID; + IncrementalBytestreamHashCalculator* hashCalculator; + State state; + bool candidateAcknowledged; - bool canceled; + boost::bsignals::connection processedBytesConnection; + boost::bsignals::connection transferFinishedConnection; }; diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp index fc0a551..1c60469 100644 --- a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,8 +17,9 @@ namespace Swift { -OutgoingSIFileTransfer::OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) { +OutgoingSIFileTransfer::OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, unsigned long long size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) { } void OutgoingSIFileTransfer::start() { + /* StreamInitiation::ref streamInitiation(new StreamInitiation()); streamInitiation->setID(id); @@ -29,4 +30,5 @@ void OutgoingSIFileTransfer::start() { request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); request->send(); + */ } @@ -34,5 +36,6 @@ void OutgoingSIFileTransfer::stop() { } -void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { +void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref) { + /* if (error) { finish(FileTransferError()); @@ -55,14 +58,18 @@ void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiat } } + */ } -void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { +void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref) { + /* if (error) { finish(FileTransferError()); } + */ //socksServer->onTransferFinished.connect(); } -void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError> error) { +void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError>) { + /* if (ibbSession) { ibbSession->onFinished.disconnect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); @@ -71,8 +78,9 @@ void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError> error) { socksServer->removeReadBytestream(id, from, to); onFinished(error); + */ } -void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) { - finish(error); +void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError>) { + //finish(error); } diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.h b/Swiften/FileTransfer/OutgoingSIFileTransfer.h index 584eb60..79da339 100644 --- a/Swiften/FileTransfer/OutgoingSIFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -26,5 +26,5 @@ namespace Swift { class OutgoingSIFileTransfer : public OutgoingFileTransfer { public: - OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer); + OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, unsigned long long size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer); virtual void start(); @@ -44,5 +44,5 @@ namespace Swift { JID to; std::string name; - int size; + unsigned long long size; std::string description; boost::shared_ptr<ReadBytestream> bytestream; diff --git a/Swiften/FileTransfer/ReadBytestream.h b/Swiften/FileTransfer/ReadBytestream.h index c94e4d3..b0663ab 100644 --- a/Swiften/FileTransfer/ReadBytestream.h +++ b/Swiften/FileTransfer/ReadBytestream.h @@ -10,8 +10,9 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> namespace Swift { - class ReadBytestream { + class SWIFTEN_API ReadBytestream { public: virtual ~ReadBytestream(); diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp index 338f221..1e96b22 100644 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp @@ -1,14 +1,95 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ #include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -namespace Swift { +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> + +using namespace Swift; + +RemoteJingleTransportCandidateSelector::RemoteJingleTransportCandidateSelector( + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory) : + connectionFactory(connectionFactory), + timerFactory(timerFactory) { +} RemoteJingleTransportCandidateSelector::~RemoteJingleTransportCandidateSelector() { } +void RemoteJingleTransportCandidateSelector::addCandidates( + const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + foreach(JingleS5BTransportPayload::Candidate c, candidates) { + this->candidates.push(c); + } +} + +void RemoteJingleTransportCandidateSelector::startSelectingCandidate() { + tryNextCandidate(); +} + +void RemoteJingleTransportCandidateSelector::stopSelectingCandidate() { + if (s5bSession) { + sessionReadyConnection.disconnect(); + s5bSession->stop(); + } +} + +void RemoteJingleTransportCandidateSelector::tryNextCandidate() { + if (candidates.empty()) { + SWIFT_LOG(debug) << "No more candidates" << std::endl; + onCandidateSelectFinished( + boost::optional<JingleS5BTransportPayload::Candidate>(), boost::shared_ptr<SOCKS5BytestreamClientSession>()); + } + else { + lastCandidate = candidates.top(); + candidates.pop(); + SWIFT_LOG(debug) << "Trying candidate " << lastCandidate.cid << std::endl; + if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType + || lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType + || lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType ) { + boost::shared_ptr<Connection> connection = connectionFactory->createConnection(); + s5bSession = boost::make_shared<SOCKS5BytestreamClientSession>( + connection, lastCandidate.hostPort, socks5DstAddr, timerFactory); + sessionReadyConnection = s5bSession->onSessionReady.connect( + boost::bind(&RemoteJingleTransportCandidateSelector::handleSessionReady, this, _1)); + s5bSession->start(); + } + else { + SWIFT_LOG(debug) << "Can't handle this type of candidate" << std::endl; + tryNextCandidate(); + } + } +} + +void RemoteJingleTransportCandidateSelector::handleSessionReady(bool error) { + sessionReadyConnection.disconnect(); + if (error) { + s5bSession.reset(); + tryNextCandidate(); + } + else { + onCandidateSelectFinished(lastCandidate, s5bSession); + } +} + +void RemoteJingleTransportCandidateSelector::setSOCKS5DstAddr(const std::string& socks5DstAddr) { + this->socks5DstAddr = socks5DstAddr; } diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h index f8df8f9..66ab4b2 100644 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h @@ -1,33 +1,61 @@ /* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. */ #pragma once -#include <Swiften/Base/boost_bsignals.h> +#include <queue> +#include <vector> + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> #include <Swiften/JID/JID.h> -#include <Swiften/Elements/JingleTransportPayload.h> -#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/Network/Connection.h> #include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> + namespace Swift { + class ConnectionFactory; + class TimerFactory; + class RemoteJingleTransportCandidateSelector { public: + RemoteJingleTransportCandidateSelector(ConnectionFactory*, TimerFactory*); virtual ~RemoteJingleTransportCandidateSelector(); - virtual void addRemoteTransportCandidates(JingleTransportPayload::ref) = 0; - virtual void selectCandidate() = 0; - virtual void setMinimumPriority(int) = 0; - virtual void setRequesterTargtet(const JID&, const JID&) {} - virtual SOCKS5BytestreamClientSession::ref getS5BSession() { return SOCKS5BytestreamClientSession::ref(); } + virtual void addCandidates(const std::vector<JingleS5BTransportPayload::Candidate>&); + virtual void setSOCKS5DstAddr(const std::string&); + virtual void startSelectingCandidate(); + virtual void stopSelectingCandidate(); + + boost::signal<void (const boost::optional<JingleS5BTransportPayload::Candidate>&, boost::shared_ptr<SOCKS5BytestreamClientSession>)> onCandidateSelectFinished; + + private: + void tryNextCandidate(); + void handleSessionReady(bool error); - virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; - virtual int getPriority(JingleTransportPayload::ref) = 0; - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + private: + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; - boost::signal<void (JingleTransportPayload::ref)> onRemoteTransportCandidateSelectFinished; + std::priority_queue< + JingleS5BTransportPayload::Candidate, + std::vector<JingleS5BTransportPayload::Candidate>, + JingleS5BTransportPayload::CompareCandidate> candidates; + boost::shared_ptr<SOCKS5BytestreamClientSession> s5bSession; + boost::bsignals::connection sessionReadyConnection; + JingleS5BTransportPayload::Candidate lastCandidate; + std::string socks5DstAddr; }; } diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp deleted file mode 100644 index 36b7cba..0000000 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> - -namespace Swift { - -RemoteJingleTransportCandidateSelectorFactory::~RemoteJingleTransportCandidateSelectorFactory() { -} - -} diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h deleted file mode 100644 index caa3097..0000000 --- a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -namespace Swift { - class RemoteJingleTransportCandidateSelector; - - class RemoteJingleTransportCandidateSelectorFactory { - public: - virtual ~RemoteJingleTransportCandidateSelectorFactory(); - - virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() = 0; - }; -} diff --git a/Swiften/FileTransfer/SConscript b/Swiften/FileTransfer/SConscript index 4e79992..6c29ea6 100644 --- a/Swiften/FileTransfer/SConscript +++ b/Swiften/FileTransfer/SConscript @@ -2,4 +2,5 @@ Import("swiften_env", "env") sources = [ + "ByteArrayReadBytestream.cpp", "OutgoingFileTransfer.cpp", "OutgoingSIFileTransfer.cpp", @@ -9,23 +10,25 @@ sources = [ "IncomingJingleFileTransfer.cpp", "IncomingFileTransferManager.cpp", + "JingleFileTransfer.cpp", + "FileTransferOptions.cpp", + "FileTransferTransporter.cpp", + "FileTransferTransporterFactory.cpp", + "DefaultFileTransferTransporter.cpp", + "DefaultFileTransferTransporterFactory.cpp", "RemoteJingleTransportCandidateSelector.cpp", - "RemoteJingleTransportCandidateSelectorFactory.cpp", "LocalJingleTransportCandidateGenerator.cpp", - "LocalJingleTransportCandidateGeneratorFactory.cpp", - "DefaultRemoteJingleTransportCandidateSelectorFactory.cpp", - "DefaultLocalJingleTransportCandidateGeneratorFactory.cpp", - "DefaultRemoteJingleTransportCandidateSelector.cpp", - "DefaultLocalJingleTransportCandidateGenerator.cpp", - "JingleTransport.cpp", - "JingleIncomingIBBTransport.cpp", "ReadBytestream.cpp", "WriteBytestream.cpp", "FileReadBytestream.cpp", "FileWriteBytestream.cpp", + "FileTransfer.cpp", + "TransportSession.cpp", "SOCKS5BytestreamClientSession.cpp", + "SOCKS5BytestreamServerInitializeRequest.cpp", + "SOCKS5BytestreamServerManager.cpp", "SOCKS5BytestreamServer.cpp", "SOCKS5BytestreamServerSession.cpp", "SOCKS5BytestreamRegistry.cpp", - "SOCKS5BytestreamProxy.cpp", + "SOCKS5BytestreamProxiesManager.cpp", "SOCKS5BytestreamProxyFinder.cpp", "IBBSendSession.cpp", @@ -34,5 +37,4 @@ sources = [ "FileTransferManagerImpl.cpp", "IncrementalBytestreamHashCalculator.cpp", - "ConnectivityManager.cpp", ] diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp index cd555e5..0a05293 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp @@ -5,7 +5,14 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include "SOCKS5BytestreamClientSession.h" #include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Algorithm.h> @@ -13,5 +20,4 @@ #include <Swiften/Base/Concat.h> #include <Swiften/Base/Log.h> -#include <Swiften/StringCodecs/SHA1.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/FileTransfer/BytestreamException.h> @@ -21,10 +27,20 @@ namespace Swift { -SOCKS5BytestreamClientSession::SOCKS5BytestreamClientSession(boost::shared_ptr<Connection> connection, const HostAddressPort& addressPort, const std::string& destination, TimerFactory* timerFactory) : - connection(connection), addressPort(addressPort), destination(destination), state(Initial), chunkSize(131072) { - connection->onConnectFinished.connect(boost::bind(&SOCKS5BytestreamClientSession::handleConnectFinished, this, _1)); - connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamClientSession::handleDisconnected, this, _1)); +SOCKS5BytestreamClientSession::SOCKS5BytestreamClientSession( + boost::shared_ptr<Connection> connection, + const HostAddressPort& addressPort, + const std::string& destination, + TimerFactory* timerFactory) : + connection(connection), + addressPort(addressPort), + destination(destination), + state(Initial), + chunkSize(131072) { weFailedTimeout = timerFactory->createTimer(2000); - weFailedTimeout->onTick.connect(boost::bind(&SOCKS5BytestreamClientSession::handleWeFailedTimeout, this)); + weFailedTimeout->onTick.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleWeFailedTimeout, this)); +} + +SOCKS5BytestreamClientSession::~SOCKS5BytestreamClientSession() { } @@ -33,11 +49,15 @@ void SOCKS5BytestreamClientSession::start() { SWIFT_LOG(debug) << "Trying to connect via TCP to " << addressPort.toString() << "." << std::endl; weFailedTimeout->start(); + connectFinishedConnection = connection->onConnectFinished.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleConnectFinished, this, _1)); connection->connect(addressPort); } void SOCKS5BytestreamClientSession::stop() { - connection->disconnect(); - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); + SWIFT_LOG(debug) << std::endl; + if (state == Finished) { + return; + } + closeConnection(); readBytestream.reset(); state = Finished; @@ -128,5 +148,5 @@ void SOCKS5BytestreamClientSession::authenticate() { SafeByteArray header = createSafeByteArray("\x05\x01\x00\x03", 4); SafeByteArray message = header; - append(message, createSafeByteArray(destination.size())); + append(message, createSafeByteArray(boost::numeric_cast<char>(destination.size()))); authenticateAddress = createByteArray(destination); append(message, authenticateAddress); @@ -141,5 +161,5 @@ void SOCKS5BytestreamClientSession::startReceiving(boost::shared_ptr<WriteBytest writeBytestream = writeStream; writeBytestream->write(unprocessedData); - onBytesReceived(unprocessedData.size()); + //onBytesReceived(unprocessedData.size()); unprocessedData.clear(); } else { @@ -152,5 +172,6 @@ void SOCKS5BytestreamClientSession::startSending(boost::shared_ptr<ReadBytestrea state = Writing; readBytestream = readStream; - connection->onDataWritten.connect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); + dataWrittenConnection = connection->onDataWritten.connect( + boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); sendData(); } else { @@ -166,5 +187,5 @@ void SOCKS5BytestreamClientSession::sendData() { if (!readBytestream->isFinished()) { try { - boost::shared_ptr<ByteArray> dataToSend = readBytestream->read(chunkSize); + boost::shared_ptr<ByteArray> dataToSend = readBytestream->read(boost::numeric_cast<size_t>(chunkSize)); connection->write(createSafeByteArray(*dataToSend)); onBytesSent(dataToSend->size()); @@ -180,8 +201,7 @@ void SOCKS5BytestreamClientSession::sendData() { void SOCKS5BytestreamClientSession::finish(bool error) { + SWIFT_LOG(debug) << std::endl; weFailedTimeout->stop(); - connection->disconnect(); - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); + closeConnection(); readBytestream.reset(); if (state == Initial || state == Hello || state == Authenticating) { @@ -199,4 +219,5 @@ void SOCKS5BytestreamClientSession::finish(bool error) { void SOCKS5BytestreamClientSession::handleConnectFinished(bool error) { + connectFinishedConnection.disconnect(); if (error) { SWIFT_LOG(debug) << "Failed to connect via TCP to " << addressPort.toString() << "." << std::endl; @@ -204,6 +225,9 @@ void SOCKS5BytestreamClientSession::handleConnectFinished(bool error) { } else { SWIFT_LOG(debug) << "Successfully connected via TCP" << addressPort.toString() << "." << std::endl; + disconnectedConnection = connection->onDisconnected.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleDisconnected, this, _1)); + dataReadConnection = connection->onDataRead.connect( + boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); weFailedTimeout->start(); - connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); process(); } @@ -218,5 +242,5 @@ void SOCKS5BytestreamClientSession::handleDataRead(boost::shared_ptr<SafeByteArr else { writeBytestream->write(createByteArray(vecptr(*data), data->size())); - onBytesReceived(data->size()); + //onBytesReceived(data->size()); } } @@ -234,3 +258,11 @@ void SOCKS5BytestreamClientSession::handleWeFailedTimeout() { } +void SOCKS5BytestreamClientSession::closeConnection() { + connectFinishedConnection.disconnect(); + dataWrittenConnection.disconnect(); + dataReadConnection.disconnect(); + disconnectedConnection.disconnect(); + connection->disconnect(); +} + } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h index ea45955..cf731c1 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h @@ -10,4 +10,5 @@ #include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> #include <Swiften/FileTransfer/FileTransferError.h> @@ -29,5 +30,5 @@ class TimerFactory; * */ -class SOCKS5BytestreamClientSession { +class SWIFTEN_API SOCKS5BytestreamClientSession { public: enum State { @@ -38,5 +39,5 @@ public: Writing, Reading, - Finished, + Finished }; @@ -45,5 +46,10 @@ public: public: - SOCKS5BytestreamClientSession(boost::shared_ptr<Connection> connection, const HostAddressPort&, const std::string&, TimerFactory*); + SOCKS5BytestreamClientSession( + boost::shared_ptr<Connection> connection, + const HostAddressPort&, + const std::string&, + TimerFactory*); + ~SOCKS5BytestreamClientSession(); void start(); @@ -58,6 +64,6 @@ public: boost::signal<void (boost::optional<FileTransferError>)> onFinished; - boost::signal<void (int)> onBytesSent; - boost::signal<void (int)> onBytesReceived; + boost::signal<void (size_t)> onBytesSent; + // boost::signal<void (size_t)> onBytesReceived; private: @@ -73,4 +79,5 @@ private: void finish(bool error); void sendData(); + void closeConnection(); private: @@ -80,5 +87,4 @@ private: State state; - int destinationPort; ByteArray unprocessedData; @@ -90,4 +96,9 @@ private: Timer::ref weFailedTimeout; + + boost::bsignals::connection connectFinishedConnection; + boost::bsignals::connection dataWrittenConnection; + boost::bsignals::connection dataReadConnection; + boost::bsignals::connection disconnectedConnection; }; diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxy.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp index 9599fd1..0b94763 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxy.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp @@ -5,5 +5,5 @@ */ -#include "SOCKS5BytestreamProxy.h" +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <boost/smart_ptr/make_shared.hpp> @@ -15,17 +15,17 @@ namespace Swift { -SOCKS5BytestreamProxy::SOCKS5BytestreamProxy(ConnectionFactory *connFactory, TimerFactory *timeFactory) : connectionFactory(connFactory), timerFactory(timeFactory) { +SOCKS5BytestreamProxiesManager::SOCKS5BytestreamProxiesManager(ConnectionFactory *connFactory, TimerFactory *timeFactory) : connectionFactory(connFactory), timerFactory(timeFactory) { } -void SOCKS5BytestreamProxy::addS5BProxy(S5BProxyRequest::ref proxy) { +void SOCKS5BytestreamProxiesManager::addS5BProxy(S5BProxyRequest::ref proxy) { localS5BProxies.push_back(proxy); } -const std::vector<S5BProxyRequest::ref>& SOCKS5BytestreamProxy::getS5BProxies() const { +const std::vector<S5BProxyRequest::ref>& SOCKS5BytestreamProxiesManager::getS5BProxies() const { return localS5BProxies; } -void SOCKS5BytestreamProxy::connectToProxies(const std::string& sessionID) { +void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& sessionID) { SWIFT_LOG(debug) << "session ID: " << sessionID << std::endl; ProxyJIDClientSessionMap clientSessions; @@ -42,5 +42,5 @@ void SOCKS5BytestreamProxy::connectToProxies(const std::string& sessionID) { } -boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { +boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { // checking parameters if (proxySessions.find(sessionID) == proxySessions.end()) { @@ -65,5 +65,5 @@ boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::getProxy } -boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { +boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { SOCKS5BytestreamClientSession::ref connection = boost::make_shared<SOCKS5BytestreamClientSession>(connectionFactory->createConnection(), addressPort, destAddr, timerFactory); return connection; diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h new file mode 100644 index 0000000..f3fed80 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> +#include <vector> + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/TimerFactory.h> + +namespace Swift { + class SOCKS5BytestreamProxiesDiscoverRequest; + + /** + * - manages list of working S5B proxies + * - creates initial connections (for the candidates you provide) + */ + class SWIFTEN_API SOCKS5BytestreamProxiesManager { + public: + SOCKS5BytestreamProxiesManager(ConnectionFactory*, TimerFactory*); + + boost::shared_ptr<SOCKS5BytestreamProxiesDiscoverRequest> createDiscoverProxiesRequest(); + + void addS5BProxy(S5BProxyRequest::ref); + const std::vector<S5BProxyRequest::ref>& getS5BProxies() const; + + void connectToProxies(const std::string& sessionID); + boost::shared_ptr<SOCKS5BytestreamClientSession> getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID); + + boost::shared_ptr<SOCKS5BytestreamClientSession> createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr); + + private: + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; + + typedef std::map<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > ProxyJIDClientSessionMap; + std::map<std::string, ProxyJIDClientSessionMap> proxySessions; + + std::vector<S5BProxyRequest::ref> localS5BProxies; + }; + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxy.h b/Swiften/FileTransfer/SOCKS5BytestreamProxy.h deleted file mode 100644 index 8f80cea..0000000 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxy.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include <string> -#include <vector> - -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/JID/JID.h> -#include <Swiften/Network/ConnectionFactory.h> -#include <Swiften/Network/TimerFactory.h> - -namespace Swift { - -/** - * - manages list of working S5B proxies - * - creates initial connections (for the candidates you provide) - */ -class SOCKS5BytestreamProxy { -public: - SOCKS5BytestreamProxy(ConnectionFactory*, TimerFactory*); - - void addS5BProxy(S5BProxyRequest::ref); - const std::vector<S5BProxyRequest::ref>& getS5BProxies() const; - - void connectToProxies(const std::string& sessionID); - boost::shared_ptr<SOCKS5BytestreamClientSession> getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID); - - boost::shared_ptr<SOCKS5BytestreamClientSession> createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr); - -private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; - - typedef std::map<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > ProxyJIDClientSessionMap; - std::map<std::string, ProxyJIDClientSessionMap> proxySessions; - - std::vector<S5BProxyRequest::ref> localS5BProxies; -}; - -} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h index 071e03a..8265157 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h diff --git a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp index ffc4298..cf4794c 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,6 +12,4 @@ #include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> -#include <Swiften/StringCodecs/SHA1.h> -#include <Swiften/StringCodecs/Hexify.h> namespace Swift { @@ -20,34 +18,15 @@ SOCKS5BytestreamRegistry::SOCKS5BytestreamRegistry() { } -void SOCKS5BytestreamRegistry::addReadBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream) { - readBytestreams[destination] = byteStream; +void SOCKS5BytestreamRegistry::setHasBytestream(const std::string& destination, bool b) { + if (b) { + availableBytestreams.insert(destination); } - -void SOCKS5BytestreamRegistry::removeReadBytestream(const std::string& destination) { - readBytestreams.erase(destination); -} - -boost::shared_ptr<ReadBytestream> SOCKS5BytestreamRegistry::getReadBytestream(const std::string& destination) const { - ReadBytestreamMap::const_iterator i = readBytestreams.find(destination); - if (i != readBytestreams.end()) { - return i->second; + else { + availableBytestreams.erase(destination); } - return boost::shared_ptr<ReadBytestream>(); } -void SOCKS5BytestreamRegistry::addWriteBytestream(const std::string& destination, boost::shared_ptr<WriteBytestream> byteStream) { - writeBytestreams[destination] = byteStream; -} - -void SOCKS5BytestreamRegistry::removeWriteBytestream(const std::string& destination) { - writeBytestreams.erase(destination); -} - -boost::shared_ptr<WriteBytestream> SOCKS5BytestreamRegistry::getWriteBytestream(const std::string& destination) const { - WriteBytestreamMap::const_iterator i = writeBytestreams.find(destination); - if (i != writeBytestreams.end()) { - return i->second; - } - return boost::shared_ptr<WriteBytestream>(); +bool SOCKS5BytestreamRegistry::hasBytestream(const std::string& destination) const { + return availableBytestreams.find(destination) != availableBytestreams.end(); } @@ -56,17 +35,4 @@ std::string SOCKS5BytestreamRegistry::generateSessionID() { } -SOCKS5BytestreamServerSession* SOCKS5BytestreamRegistry::getConnectedSession(const std::string& destination) { - if (serverSessions.find(destination) != serverSessions.end()) { - return serverSessions[destination]; - } else { - SWIFT_LOG(debug) << "No active connction for stream ID " << destination << " found!" << std::endl; - return NULL; - } -} - -std::string SOCKS5BytestreamRegistry::getHostname(const std::string& sessionID, const JID& requester, const JID& target) { - return Hexify::hexify(SHA1::getHash(createSafeByteArray(sessionID + requester.toString() + target.toString()))); -} - } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h index 779aabb..4c05e47 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,32 +7,20 @@ #pragma once -#include <boost/shared_ptr.hpp> - #include <map> #include <string> -#include <vector> #include <set> +#include <Swiften/Base/API.h> #include <Swiften/Base/IDGenerator.h> -#include <Swiften/JID/JID.h> -#include <Swiften/Elements/S5BProxyRequest.h> -#include <Swiften/FileTransfer/ReadBytestream.h> -#include <Swiften/FileTransfer/WriteBytestream.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> -#include <Swiften/Network/HostAddressPort.h> namespace Swift { - class SOCKS5BytestreamRegistry { + class SOCKS5BytestreamServerSession; + + class SWIFTEN_API SOCKS5BytestreamRegistry { public: SOCKS5BytestreamRegistry(); - boost::shared_ptr<ReadBytestream> getReadBytestream(const std::string& destination) const; - void addReadBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream); - void removeReadBytestream(const std::string& destination); - - boost::shared_ptr<WriteBytestream> getWriteBytestream(const std::string& destination) const; - void addWriteBytestream(const std::string& destination, boost::shared_ptr<WriteBytestream> byteStream); - void removeWriteBytestream(const std::string& destination); + void setHasBytestream(const std::string& destination, bool); + bool hasBytestream(const std::string& destination) const; /** @@ -41,23 +29,6 @@ namespace Swift { std::string generateSessionID(); - /** - * Start an actual transfer. - */ - SOCKS5BytestreamServerSession* getConnectedSession(const std::string& destination); - - public: - static std::string getHostname(const std::string& sessionID, const JID& requester, const JID& target); - private: - friend class SOCKS5BytestreamServerSession; - - typedef std::map<std::string, boost::shared_ptr<ReadBytestream> > ReadBytestreamMap; - ReadBytestreamMap readBytestreams; - - typedef std::map<std::string, boost::shared_ptr<WriteBytestream> > WriteBytestreamMap; - WriteBytestreamMap writeBytestreams; - - std::map<std::string, SOCKS5BytestreamServerSession*> serverSessions; - + std::set<std::string> availableBytestreams; IDGenerator idGenerator; }; diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp index 90fed7a..f491918 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,6 +10,7 @@ #include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> #include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> @@ -17,5 +18,9 @@ namespace Swift { -SOCKS5BytestreamServer::SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer, SOCKS5BytestreamRegistry* registry) : connectionServer(connectionServer), registry(registry) { +SOCKS5BytestreamServer::SOCKS5BytestreamServer( + boost::shared_ptr<ConnectionServer> connectionServer, + SOCKS5BytestreamRegistry* registry) : + connectionServer(connectionServer), + registry(registry) { } @@ -26,20 +31,15 @@ void SOCKS5BytestreamServer::start() { void SOCKS5BytestreamServer::stop() { connectionServer->onNewConnection.disconnect(boost::bind(&SOCKS5BytestreamServer::handleNewConnection, this, _1)); + foreach (boost::shared_ptr<SOCKS5BytestreamServerSession> session, sessions) { + session->onFinished.disconnect(boost::bind(&SOCKS5BytestreamServer::handleSessionFinished, this, session)); + session->stop(); } - -void SOCKS5BytestreamServer::addReadBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream) { - registry->addReadBytestream(getSOCKSDestinationAddress(id, from, to), byteStream); -} - -void SOCKS5BytestreamServer::removeReadBytestream(const std::string& id, const JID& from, const JID& to) { - registry->removeReadBytestream(getSOCKSDestinationAddress(id, from, to)); -} - -std::string SOCKS5BytestreamServer::getSOCKSDestinationAddress(const std::string& id, const JID& from, const JID& to) { - return Hexify::hexify(SHA1::getHash(createByteArray(id + from.toString() + to.toString()))); + sessions.clear(); } void SOCKS5BytestreamServer::handleNewConnection(boost::shared_ptr<Connection> connection) { - boost::shared_ptr<SOCKS5BytestreamServerSession> session(new SOCKS5BytestreamServerSession(connection, registry)); + boost::shared_ptr<SOCKS5BytestreamServerSession> session = + boost::make_shared<SOCKS5BytestreamServerSession>(connection, registry); + session->onFinished.connect(boost::bind(&SOCKS5BytestreamServer::handleSessionFinished, this, session)); sessions.push_back(session); session->start(); @@ -50,4 +50,20 @@ HostAddressPort SOCKS5BytestreamServer::getAddressPort() const { } +std::vector< boost::shared_ptr<SOCKS5BytestreamServerSession> > SOCKS5BytestreamServer::getSessions( + const std::string& streamID) const { + std::vector< boost::shared_ptr<SOCKS5BytestreamServerSession> > result; + foreach (boost::shared_ptr<SOCKS5BytestreamServerSession> session, sessions) { + if (session->getStreamID() == streamID) { + result.push_back(session); + } + } + return result; +} + +void SOCKS5BytestreamServer::handleSessionFinished(boost::shared_ptr<SOCKS5BytestreamServerSession> session) { + sessions.erase(std::remove(sessions.begin(), sessions.end(), session), sessions.end()); + session->onFinished.disconnect(boost::bind(&SOCKS5BytestreamServer::handleSessionFinished, this, session)); +} + } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServer.h b/Swiften/FileTransfer/SOCKS5BytestreamServer.h index 6bb598e..71605c4 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServer.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,8 +18,11 @@ namespace Swift { class SOCKS5BytestreamServerSession; + class CryptoProvider; class SOCKS5BytestreamServer { public: - SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer, SOCKS5BytestreamRegistry* registry); + SOCKS5BytestreamServer( + boost::shared_ptr<ConnectionServer> connectionServer, + SOCKS5BytestreamRegistry* registry); HostAddressPort getAddressPort() const; @@ -28,14 +31,9 @@ namespace Swift { void stop(); - void addReadBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream); - void removeReadBytestream(const std::string& id, const JID& from, const JID& to); - - /*protected: - boost::shared_ptr<ReadBytestream> getBytestream(const std::string& dest);*/ + std::vector< boost::shared_ptr<SOCKS5BytestreamServerSession> > getSessions(const std::string& id) const; private: void handleNewConnection(boost::shared_ptr<Connection> connection); - - static std::string getSOCKSDestinationAddress(const std::string& id, const JID& from, const JID& to); + void handleSessionFinished(boost::shared_ptr<SOCKS5BytestreamServerSession>); private: diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.cpp new file mode 100644 index 0000000..38735de --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h> + +#include <boost/bind.hpp> + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> + +using namespace Swift; + +SOCKS5BytestreamServerInitializeRequest::SOCKS5BytestreamServerInitializeRequest(SOCKS5BytestreamServerManager* manager) : manager(manager) { +} + +SOCKS5BytestreamServerInitializeRequest::~SOCKS5BytestreamServerInitializeRequest() { +} + +void SOCKS5BytestreamServerInitializeRequest::start() { + if (manager->isInitialized()) { + handleInitialized(true); + } + else { + manager->onInitialized.connect( + boost::bind(&SOCKS5BytestreamServerInitializeRequest::handleInitialized, this, _1)); + manager->initialize(); + } +} + +void SOCKS5BytestreamServerInitializeRequest::stop() { + manager->onInitialized.disconnect( + boost::bind(&SOCKS5BytestreamServerInitializeRequest::handleInitialized, this, _1)); +} + +void SOCKS5BytestreamServerInitializeRequest::handleInitialized(bool success) { + onFinished(success); +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h new file mode 100644 index 0000000..aa073fc --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class SOCKS5BytestreamServerManager; + + class SWIFTEN_API SOCKS5BytestreamServerInitializeRequest { + public: + SOCKS5BytestreamServerInitializeRequest(SOCKS5BytestreamServerManager* manager); + ~SOCKS5BytestreamServerInitializeRequest(); + + void start(); + void stop(); + + public: + boost::signal<void (bool /* success */)> onFinished; + + private: + void handleInitialized(bool success); + + private: + SOCKS5BytestreamServerManager* manager; + }; +} + diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp new file mode 100644 index 0000000..1d65d27 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> + +#include <Swiften/FileTransfer/SOCKS5BytestreamServerInitializeRequest.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/Network/ConnectionServer.h> +#include <Swiften/Network/ConnectionServerFactory.h> +#include <Swiften/Network/NetworkEnvironment.h> +#include <Swiften/Network/NATTraverser.h> +#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> +#include <Swiften/Network/NATTraversalForwardPortRequest.h> + +using namespace Swift; + +static const int LISTEN_PORTS_BEGIN = 10000; +static const int LISTEN_PORTS_END = 11000; + +SOCKS5BytestreamServerManager::SOCKS5BytestreamServerManager( + SOCKS5BytestreamRegistry* bytestreamRegistry, + ConnectionServerFactory* connectionServerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser) : + bytestreamRegistry(bytestreamRegistry), + connectionServerFactory(connectionServerFactory), + networkEnvironment(networkEnvironment), + natTraverser(natTraverser), + state(Start), + server(NULL) { +} + +SOCKS5BytestreamServerManager::~SOCKS5BytestreamServerManager() { + SWIFT_LOG_ASSERT(!connectionServer, warning) << std::endl; + SWIFT_LOG_ASSERT(!getPublicIPRequest, warning) << std::endl; + SWIFT_LOG_ASSERT(!forwardPortRequest, warning) << std::endl; + SWIFT_LOG_ASSERT(state == Start, warning) << std::endl; +} + + +boost::shared_ptr<SOCKS5BytestreamServerInitializeRequest> SOCKS5BytestreamServerManager::createInitializeRequest() { + return boost::make_shared<SOCKS5BytestreamServerInitializeRequest>(this); +} + +void SOCKS5BytestreamServerManager::stop() { + if (getPublicIPRequest) { + getPublicIPRequest->stop(); + getPublicIPRequest.reset(); + } + if (forwardPortRequest) { + forwardPortRequest->stop(); + forwardPortRequest.reset(); + } + if (connectionServer) { + connectionServer->stop(); + connectionServer.reset(); + } + // TODO: Remove port forwards + + state = Start; +} + +std::vector<HostAddressPort> SOCKS5BytestreamServerManager::getHostAddressPorts() const { + std::vector<HostAddressPort> result; + if (connectionServer) { + std::vector<NetworkInterface> networkInterfaces = networkEnvironment->getNetworkInterfaces(); + foreach (const NetworkInterface& networkInterface, networkInterfaces) { + foreach (const HostAddress& address, networkInterface.getAddresses()) { + result.push_back(HostAddressPort(address, connectionServerPort)); + } + } + } + return result; +} + +std::vector<HostAddressPort> SOCKS5BytestreamServerManager::getAssistedHostAddressPorts() const { + std::vector<HostAddressPort> result; + if (publicAddress && portMapping) { + result.push_back(HostAddressPort(*publicAddress, portMapping->getPublicPort())); + } + return result; +} + +bool SOCKS5BytestreamServerManager::isInitialized() const { + return state == Initialized; +} + +void SOCKS5BytestreamServerManager::initialize() { + if (state == Start) { + state = Initializing; + + // Find a port to listen on + assert(!connectionServer); + int port; + for (port = LISTEN_PORTS_BEGIN; port < LISTEN_PORTS_END; ++port) { + SWIFT_LOG(debug) << "Trying to start server on port " << port << std::endl; + connectionServer = connectionServerFactory->createConnectionServer(HostAddress("0.0.0.0"), port); + boost::optional<ConnectionServer::Error> error = connectionServer->tryStart(); + if (!error) { + break; + } + else if (*error != ConnectionServer::Conflict) { + SWIFT_LOG(debug) << "Error starting server" << std::endl; + onInitialized(false); + return; + } + connectionServer.reset(); + } + if (!connectionServer) { + SWIFT_LOG(debug) << "Unable to find an open port" << std::endl; + onInitialized(false); + return; + } + SWIFT_LOG(debug) << "Server started succesfully" << std::endl; + connectionServerPort = port; + + // Start bytestream server. Should actually happen before the connectionserver is started + // but that doesn't really matter here. + assert(!server); + server = new SOCKS5BytestreamServer(connectionServer, bytestreamRegistry); + server->start(); + + // Retrieve public addresses + assert(!getPublicIPRequest); + publicAddress = boost::optional<HostAddress>(); + if ((getPublicIPRequest = natTraverser->createGetPublicIPRequest())) { + getPublicIPRequest->onResult.connect( + boost::bind(&SOCKS5BytestreamServerManager::handleGetPublicIPResult, this, _1)); + getPublicIPRequest->start(); + } + + // Forward ports + assert(!forwardPortRequest); + portMapping = boost::optional<NATPortMapping>(); + if ((forwardPortRequest = natTraverser->createForwardPortRequest(port, port))) { + forwardPortRequest->onResult.connect( + boost::bind(&SOCKS5BytestreamServerManager::handleForwardPortResult, this, _1)); + forwardPortRequest->start(); + } + } +} + +void SOCKS5BytestreamServerManager::handleGetPublicIPResult(boost::optional<HostAddress> address) { + if (address) { + SWIFT_LOG(debug) << "Public IP discovered as " << address.get().toString() << "." << std::endl; + } + else { + SWIFT_LOG(debug) << "No public IP discoverable." << std::endl; + } + + publicAddress = address; + + getPublicIPRequest->stop(); + getPublicIPRequest.reset(); + + checkInitializeFinished(); +} + +void SOCKS5BytestreamServerManager::handleForwardPortResult(boost::optional<NATPortMapping> mapping) { + if (mapping) { + SWIFT_LOG(debug) << "Mapping port was successful." << std::endl; + } + else { + SWIFT_LOG(debug) << "Mapping port has failed." << std::endl; + } + + portMapping = mapping; + + forwardPortRequest->stop(); + forwardPortRequest.reset(); + + checkInitializeFinished(); +} + +void SOCKS5BytestreamServerManager::checkInitializeFinished() { + assert(state == Initializing); + if (!getPublicIPRequest && !forwardPortRequest) { + state = Initialized; + onInitialized(true); + } +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h new file mode 100644 index 0000000..248a9b9 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerManager.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/NATPortMapping.h> + +namespace Swift { + class NetworkEnvironment; + class NATTraverser; + class NATTraversalGetPublicIPRequest; + class NATTraversalForwardPortRequest; + class SOCKS5BytestreamRegistry; + class ConnectionServerFactory; + class ConnectionServer; + class SOCKS5BytestreamServerInitializeRequest; + class SOCKS5BytestreamServer; + + class SOCKS5BytestreamServerManager { + public: + SOCKS5BytestreamServerManager( + SOCKS5BytestreamRegistry* bytestreamRegistry, + ConnectionServerFactory* connectionServerFactory, + NetworkEnvironment* networkEnvironment, + NATTraverser* natTraverser); + ~SOCKS5BytestreamServerManager(); + + boost::shared_ptr<SOCKS5BytestreamServerInitializeRequest> createInitializeRequest(); + void stop(); + + std::vector<HostAddressPort> getHostAddressPorts() const; + std::vector<HostAddressPort> getAssistedHostAddressPorts() const; + + SOCKS5BytestreamServer* getServer() const { + return server; + } + + private: + bool isInitialized() const; + void initialize(); + void checkInitializeFinished(); + + void handleGetPublicIPResult(boost::optional<HostAddress> address); + void handleForwardPortResult(boost::optional<NATPortMapping> mapping); + + boost::signal<void (bool /* success */)> onInitialized; + + + private: + friend class SOCKS5BytestreamServerInitializeRequest; + SOCKS5BytestreamRegistry* bytestreamRegistry; + ConnectionServerFactory* connectionServerFactory; + NetworkEnvironment* networkEnvironment; + NATTraverser* natTraverser; + enum { Start, Initializing, Initialized } state; + SOCKS5BytestreamServer* server; + boost::shared_ptr<ConnectionServer> connectionServer; + int connectionServerPort; + boost::shared_ptr<NATTraversalGetPublicIPRequest> getPublicIPRequest; + boost::shared_ptr<NATTraversalForwardPortRequest> forwardPortRequest; + boost::optional<HostAddress> publicAddress; + boost::optional<NATPortMapping> portMapping; + }; +} + diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp index 2260fc20..cb34c58 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <boost/bind.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <iostream> @@ -15,4 +16,5 @@ #include <Swiften/Base/Concat.h> #include <Swiften/Base/Log.h> +#include <Swiften/Network/HostAddressPort.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> #include <Swiften/FileTransfer/BytestreamException.h> @@ -20,11 +22,18 @@ namespace Swift { -SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession(boost::shared_ptr<Connection> connection, SOCKS5BytestreamRegistry* bytestreams) : connection(connection), bytestreams(bytestreams), state(Initial), chunkSize(131072) { - connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); +SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession( + boost::shared_ptr<Connection> connection, + SOCKS5BytestreamRegistry* bytestreams) : + connection(connection), + bytestreams(bytestreams), + state(Initial), + chunkSize(131072), + waitingForData(false) { + disconnectedConnection = connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); } SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() { if (state != Finished && state != Initial) { - std::cerr << "Warning: SOCKS5BytestremServerSession unfinished" << std::endl; + std::cerr << "Warning: SOCKS5BytestreamServerSession unfinished" << std::endl; finish(false); } @@ -33,32 +42,34 @@ SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() { void SOCKS5BytestreamServerSession::start() { SWIFT_LOG(debug) << std::endl; - connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); + dataReadConnection = connection->onDataRead.connect( + boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); state = WaitingForAuthentication; } void SOCKS5BytestreamServerSession::stop() { - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); - connection->disconnect(); - state = Finished; + finish(false); } -void SOCKS5BytestreamServerSession::startTransfer() { - if (state == ReadyForTransfer) { - if (readBytestream) { +void SOCKS5BytestreamServerSession::startSending(boost::shared_ptr<ReadBytestream> stream) { + if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } + + readBytestream = stream; state = WritingData; - connection->onDataWritten.connect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); + dataAvailableConnection = readBytestream->onDataAvailable.connect( + boost::bind(&SOCKS5BytestreamServerSession::handleDataAvailable, this)); + dataWrittenConnection = connection->onDataWritten.connect( + boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); sendData(); } - else if(writeBytestream) { + +void SOCKS5BytestreamServerSession::startReceiving(boost::shared_ptr<WriteBytestream> stream) { + if (state != ReadyForTransfer) { SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; return; } + + writeBytestream = stream; state = ReadingData; writeBytestream->write(unprocessedData); - onBytesReceived(unprocessedData.size()); + // onBytesReceived(unprocessedData.size()); unprocessedData.clear(); } - } else { - SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; - } -} HostAddressPort SOCKS5BytestreamServerSession::getAddressPort() const { @@ -72,5 +83,11 @@ void SOCKS5BytestreamServerSession::handleDataRead(boost::shared_ptr<SafeByteArr } else { writeBytestream->write(createByteArray(vecptr(*data), data->size())); - onBytesReceived(data->size()); + // onBytesReceived(data->size()); + } +} + +void SOCKS5BytestreamServerSession::handleDataAvailable() { + if (waitingForData) { + sendData(); } } @@ -78,7 +95,5 @@ void SOCKS5BytestreamServerSession::handleDataRead(boost::shared_ptr<SafeByteArr void SOCKS5BytestreamServerSession::handleDisconnected(const boost::optional<Connection::Error>& error) { SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; - if (error) { - finish(true); - } + finish(error ? true : false); } @@ -119,13 +134,12 @@ void SOCKS5BytestreamServerSession::process() { } unprocessedData.clear(); - std::string streamID = byteArrayToString(requestID); - readBytestream = bytestreams->getReadBytestream(streamID); - writeBytestream = bytestreams->getWriteBytestream(streamID); + streamID = byteArrayToString(requestID); + bool hasBytestream = bytestreams->hasBytestream(streamID); SafeByteArray result = createSafeByteArray("\x05", 1); - result.push_back((readBytestream || writeBytestream) ? 0x0 : 0x4); + result.push_back(hasBytestream ? 0x0 : 0x4); append(result, createByteArray("\x00\x03", 2)); - result.push_back(static_cast<char>(requestID.size())); + result.push_back(boost::numeric_cast<unsigned char>(requestID.size())); append(result, concat(requestID, createByteArray("\x00\x00", 2))); - if (!readBytestream && !writeBytestream) { + if (!hasBytestream) { SWIFT_LOG(debug) << "Readstream or Wrtiestream with ID " << streamID << " not found!" << std::endl; connection->write(result); @@ -133,7 +147,6 @@ void SOCKS5BytestreamServerSession::process() { } else { - SWIFT_LOG(debug) << "Found " << (readBytestream ? "Readstream" : "Writestream") << ". Sent OK." << std::endl; + SWIFT_LOG(debug) << "Found stream. Sent OK." << std::endl; connection->write(result); - bytestreams->serverSessions[streamID] = this; state = ReadyForTransfer; } @@ -146,7 +159,13 @@ void SOCKS5BytestreamServerSession::sendData() { if (!readBytestream->isFinished()) { try { - SafeByteArray dataToSend = createSafeByteArray(*readBytestream->read(chunkSize)); + SafeByteArray dataToSend = createSafeByteArray(*readBytestream->read(boost::numeric_cast<size_t>(chunkSize))); + if (!dataToSend.empty()) { connection->write(dataToSend); onBytesSent(dataToSend.size()); + waitingForData = false; + } + else { + waitingForData = true; + } } catch (const BytestreamException&) { @@ -160,7 +179,13 @@ void SOCKS5BytestreamServerSession::sendData() { void SOCKS5BytestreamServerSession::finish(bool error) { - connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); - connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); - connection->onDisconnected.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); + SWIFT_LOG(debug) << error << " " << state << std::endl; + if (state == Finished) { + return; + } + + disconnectedConnection.disconnect(); + dataReadConnection.disconnect(); + dataWrittenConnection.disconnect(); + dataAvailableConnection.disconnect(); readBytestream.reset(); state = Finished; diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h index 4557a36..0b35e4a 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h @@ -9,4 +9,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/Connection.h> @@ -18,5 +19,5 @@ namespace Swift { class SOCKS5BytestreamRegistry; - class SOCKS5BytestreamServerSession { + class SWIFTEN_API SOCKS5BytestreamServerSession { public: typedef boost::shared_ptr<SOCKS5BytestreamServerSession> ref; @@ -30,5 +31,5 @@ namespace Swift { ReadingData, WritingData, - Finished, + Finished }; @@ -43,10 +44,16 @@ namespace Swift { void stop(); - void startTransfer(); + void startSending(boost::shared_ptr<ReadBytestream>); + void startReceiving(boost::shared_ptr<WriteBytestream>); + HostAddressPort getAddressPort() const; boost::signal<void (boost::optional<FileTransferError>)> onFinished; - boost::signal<void (int)> onBytesSent; - boost::signal<void (int)> onBytesReceived; + boost::signal<void (unsigned long long)> onBytesSent; + // boost::signal<void (unsigned long long)> onBytesReceived; + + const std::string& getStreamID() const { + return streamID; + } private: @@ -55,4 +62,5 @@ namespace Swift { void handleDataRead(boost::shared_ptr<SafeByteArray>); void handleDisconnected(const boost::optional<Connection::Error>&); + void handleDataAvailable(); void sendData(); @@ -63,6 +71,14 @@ namespace Swift { State state; int chunkSize; + std::string streamID; boost::shared_ptr<ReadBytestream> readBytestream; boost::shared_ptr<WriteBytestream> writeBytestream; + bool waitingForData; + + boost::bsignals::connection disconnectedConnection; + boost::bsignals::connection dataReadConnection; + boost::bsignals::connection dataWrittenConnection; + boost::bsignals::connection dataAvailableConnection; + }; } diff --git a/Swiften/FileTransfer/TransportSession.cpp b/Swiften/FileTransfer/TransportSession.cpp new file mode 100644 index 0000000..154cb89 --- /dev/null +++ b/Swiften/FileTransfer/TransportSession.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/FileTransfer/TransportSession.h> + +using namespace Swift; + +TransportSession::~TransportSession() { +} diff --git a/Swiften/FileTransfer/TransportSession.h b/Swiften/FileTransfer/TransportSession.h new file mode 100644 index 0000000..e5a90db --- /dev/null +++ b/Swiften/FileTransfer/TransportSession.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/FileTransfer/FileTransferError.h> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class SWIFTEN_API TransportSession { + public: + virtual ~TransportSession(); + + virtual void start() = 0; + virtual void stop() = 0; + + boost::signal<void (size_t)> onBytesSent; + boost::signal<void (boost::optional<FileTransferError>)> onFinished; + }; +} diff --git a/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h index ae06cd3..26adb05 100644 --- a/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h +++ b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h @@ -8,10 +8,14 @@ #include <string> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/date_time/posix_time/posix_time.hpp> +#include <Swiften/Base/Override.h> #include <Swiften/FileTransfer/FileTransferManager.h> namespace Swift { + class S5BProxyRequest; + class FileTransferOptions; + class DummyFileTransferManager : public FileTransferManager { public: @@ -19,15 +23,24 @@ namespace Swift { } - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID&, const boost::filesystem::path&, const std::string&, boost::shared_ptr<ReadBytestream>) { + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID&, + const boost::filesystem::path&, + const std::string&, + boost::shared_ptr<ReadBytestream>, + const FileTransferOptions&) SWIFTEN_OVERRIDE { return OutgoingFileTransfer::ref(); } - virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID&, const std::string&, const std::string&, const boost::uintmax_t, const boost::posix_time::ptime&, boost::shared_ptr<ReadBytestream>) { + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer( + const JID&, + const std::string&, + const std::string&, + const boost::uintmax_t, + const boost::posix_time::ptime&, + boost::shared_ptr<ReadBytestream>, + const FileTransferOptions&) SWIFTEN_OVERRIDE { return OutgoingFileTransfer::ref(); } - virtual void startListeningOnPort(int) { - } - virtual void addS5BProxy(boost::shared_ptr<S5BProxyRequest>) { } diff --git a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp index c62636d..339e245 100644 --- a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp @@ -14,4 +14,5 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/FileTransfer/IBBReceiveSession.h> +#include <Swiften/FileTransfer/ByteArrayWriteBytestream.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> @@ -36,4 +37,5 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { iqRouter = new IQRouter(stanzaChannel); finished = false; + bytestream = boost::make_shared<ByteArrayWriteBytestream>(); } @@ -62,5 +64,5 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(1, "id-a")); - CPPUNIT_ASSERT(createByteArray("abc") == receivedData); + CPPUNIT_ASSERT(createByteArray("abc") == bytestream->getData()); CPPUNIT_ASSERT(!finished); @@ -77,5 +79,5 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); - CPPUNIT_ASSERT(createByteArray("abcdef") == receivedData); + CPPUNIT_ASSERT(createByteArray("abcdef") == bytestream->getData()); CPPUNIT_ASSERT(!finished); @@ -119,5 +121,5 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); - CPPUNIT_ASSERT(createByteArray("abcdef") == receivedData); + CPPUNIT_ASSERT(createByteArray("abcdef") == bytestream->getData()); CPPUNIT_ASSERT(finished); CPPUNIT_ASSERT(!error); @@ -162,6 +164,5 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { IBBReceiveSession* createSession(const std::string& from, const std::string& id, size_t size = 0x1000) { - IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), JID(), size, iqRouter); - session->onDataReceived.connect(boost::bind(&IBBReceiveSessionTest::handleDataReceived, this, _1)); + IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), JID(), size, bytestream, iqRouter); session->onFinished.connect(boost::bind(&IBBReceiveSessionTest::handleFinished, this, _1)); return session; @@ -174,8 +175,4 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { } - void handleDataReceived(const std::vector<unsigned char>& data) { - receivedData.insert(receivedData.end(), data.begin(), data.end()); - } - private: DummyStanzaChannel* stanzaChannel; @@ -183,5 +180,5 @@ class IBBReceiveSessionTest : public CppUnit::TestFixture { bool finished; boost::optional<FileTransferError> error; - std::vector<unsigned char> receivedData; + boost::shared_ptr<ByteArrayWriteBytestream> bytestream; }; diff --git a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp index 4c6ae72..669ed80 100644 --- a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -11,4 +17,5 @@ #include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Override.h> #include <Swiften/Base/Log.h> #include <Swiften/Client/DummyStanzaChannel.h> @@ -18,10 +25,6 @@ #include <Swiften/FileTransfer/ByteArrayWriteBytestream.h> #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <Swiften/Jingle/FakeJingleSession.h> #include <Swiften/Network/DummyTimerFactory.h> @@ -30,4 +33,6 @@ #include <Swiften/Network/PlatformNATTraversalWorker.h> #include <Swiften/Queries/IQRouter.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> #include <iostream> @@ -36,122 +41,49 @@ using namespace Swift; using namespace boost; -class FakeRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { - void addRemoteTransportCandidates(JingleTransportPayload::ref cand) { - candidate = cand; - } - - void selectCandidate() { - boost::shared_ptr<JingleS5BTransportPayload> payload = make_shared<JingleS5BTransportPayload>(); - payload->setCandidateError(true); - payload->setSessionID(candidate->getSessionID()); - onRemoteTransportCandidateSelectFinished(payload); - } - - void setMinimumPriority(int) { - - } - - bool isActualCandidate(JingleTransportPayload::ref) { - return false; - } - - int getPriority(JingleTransportPayload::ref) { - return 0; - } - - JingleTransport::ref selectTransport(JingleTransportPayload::ref) { - return JingleTransport::ref(); - } - -private: - JingleTransportPayload::ref candidate; -}; - -class FakeRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory { -public: - virtual ~FakeRemoteJingleTransportCandidateSelectorFactory() { - - } - - virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() { - return new FakeRemoteJingleTransportCandidateSelector(); - } -}; - -class FakeLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { -public: - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref payload) { - JingleS5BTransportPayload::ref payL = make_shared<JingleS5BTransportPayload>(); - payL->setSessionID(payload->getSessionID()); - onLocalTransportCandidatesGenerated(payL); - } - - void emitonLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { - onLocalTransportCandidatesGenerated(payload); - } - - virtual bool isActualCandidate(JingleTransportPayload::ref) { - return false; - } - - virtual int getPriority(JingleTransportPayload::ref) { - return 0; - } - - virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) { - return JingleTransport::ref(); - } -}; - -class FakeLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory { -public: - virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() { - return new FakeLocalJingleTransportCandidateGenerator(); - } -}; - class IncomingJingleFileTransferTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(IncomingJingleFileTransferTest); - CPPUNIT_TEST(test_AcceptOnyIBBSendsSessionAccept); - CPPUNIT_TEST(test_OnlyIBBTransferReceiveWorks); - CPPUNIT_TEST(test_AcceptFailingS5BFallsBackToIBB); + //CPPUNIT_TEST(test_AcceptOnyIBBSendsSessionAccept); + //CPPUNIT_TEST(test_OnlyIBBTransferReceiveWorks); + //CPPUNIT_TEST(test_AcceptFailingS5BFallsBackToIBB); CPPUNIT_TEST_SUITE_END(); public: - shared_ptr<IncomingJingleFileTransfer> createTestling() { - JID ourJID("our@jid.org/full"); - return make_shared<IncomingJingleFileTransfer>(ourJID, shared_ptr<JingleSession>(fakeJingleSession), jingleContentPayload, fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, bytestreamRegistry, bytestreamProxy, timerFactory); - } + // shared_ptr<IncomingJingleFileTransfer> createTestling() { + // JID ourJID("our@jid.org/full"); + // return boost::shared_ptr<IncomingJingleFileTransfer>(new IncomingJingleFileTransfer(ourJID, shared_ptr<JingleSession>(session), jingleContentPayload, fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, bytestreamRegistry, bytestreamProxy, timerFactory, crypto.get())); + // } - IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { - IQ::ref request = IQ::createRequest(IQ::Set, JID("foo@bar.com/baz"), id, ibb); - request->setFrom(from); - return request; - } + // IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { + // IQ::ref request = IQ::createRequest(IQ::Set, JID("foo@bar.com/baz"), id, ibb); + // request->setFrom(from); + // return request; + // } void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); eventLoop = new DummyEventLoop(); - fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession"); - jingleContentPayload = make_shared<JingleContentPayload>(); - fakeRJTCSF = make_shared<FakeRemoteJingleTransportCandidateSelectorFactory>(); - fakeLJTCF = make_shared<FakeLocalJingleTransportCandidateGeneratorFactory>(); - stanzaChannel = new DummyStanzaChannel(); - iqRouter = new IQRouter(stanzaChannel); - bytestreamRegistry = new SOCKS5BytestreamRegistry(); - timerFactory = new DummyTimerFactory(); - connectionFactory = new DummyConnectionFactory(eventLoop); - bytestreamProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); + session = boost::make_shared<FakeJingleSession>("foo@bar.com/baz", "mysession"); + // jingleContentPayload = make_shared<JingleContentPayload>(); + // fakeRJTCSF = make_shared<FakeRemoteJingleTransportCandidateSelectorFactory>(); + // fakeLJTCF = make_shared<FakeLocalJingleTransportCandidateGeneratorFactory>(); + // stanzaChannel = new DummyStanzaChannel(); + // iqRouter = new IQRouter(stanzaChannel); + // bytestreamRegistry = new SOCKS5BytestreamRegistry(); + // timerFactory = new DummyTimerFactory(); + // connectionFactory = new DummyConnectionFactory(eventLoop); + // bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); } void tearDown() { - delete bytestreamProxy; - delete connectionFactory; - delete timerFactory; - delete bytestreamRegistry; - delete iqRouter; - delete stanzaChannel; + // delete bytestreamProxy; + // delete connectionFactory; + // delete timerFactory; + // delete bytestreamRegistry; + // delete iqRouter; + // delete stanzaChannel; delete eventLoop; } // Tests whether IncomingJingleFileTransfer would accept a IBB only file transfer. +#if 0 void test_AcceptOnyIBBSendsSessionAccept() { //1. create your test incoming file transfer @@ -218,5 +150,5 @@ public: // indicate transport replace (Romeo) - fakeJingleSession->onTransportReplaceReceived(getContentID(), addJingleIBBPayload()); + session->onTransportReplaceReceived(getContentID(), addJingleIBBPayload()); FakeJingleSession::AcceptTransportCall acceptTransportCall = getCall<FakeJingleSession::AcceptTransportCall>(2); @@ -260,13 +192,16 @@ private: template <typename T> T getCall(int i) const { size_t index = static_cast<size_t>(i); - CPPUNIT_ASSERT(index < fakeJingleSession->calledCommands.size()); - T* cmd = boost::get<T>(&fakeJingleSession->calledCommands[index]); + CPPUNIT_ASSERT(index < session->calledCommands.size()); + T* cmd = boost::get<T>(&session->calledCommands[index]); CPPUNIT_ASSERT(cmd); return *cmd; } +#endif private: EventLoop* eventLoop; - FakeJingleSession* fakeJingleSession; + boost::shared_ptr<CryptoProvider> crypto; + boost::shared_ptr<FakeJingleSession> session; +#if 0 shared_ptr<JingleContentPayload> jingleContentPayload; shared_ptr<FakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF; @@ -276,6 +211,7 @@ private: SOCKS5BytestreamRegistry* bytestreamRegistry; DummyConnectionFactory* connectionFactory; - SOCKS5BytestreamProxy* bytestreamProxy; + SOCKS5BytestreamProxiesManager* bytestreamProxy; DummyTimerFactory* timerFactory; +#endif }; diff --git a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp index 0c324bf..16b1225 100644 --- a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp +++ b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -14,13 +20,9 @@ #include <Swiften/FileTransfer/OutgoingJingleFileTransfer.h> #include <Swiften/Jingle/FakeJingleSession.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> -#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> -#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> #include <Swiften/FileTransfer/ByteArrayReadBytestream.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <Swiften/Elements/JingleIBBTransportPayload.h> @@ -29,4 +31,5 @@ #include <Swiften/Elements/IBB.h> #include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Override.h> #include <Swiften/Base/IDGenerator.h> #include <Swiften/EventLoop/DummyEventLoop.h> @@ -36,4 +39,6 @@ #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/DummyConnectionFactory.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/Base/Log.h> @@ -41,4 +46,5 @@ #include <iostream> +#if 0 using namespace Swift; @@ -88,14 +94,6 @@ public: class OFakeLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { public: - virtual void generateLocalTransportCandidates(JingleTransportPayload::ref /* payload */) { - //JingleTransportPayload::ref payL = make_shared<JingleTransportPayload>(); - //payL->setSessionID(payload->getSessionID()); - JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); - - onLocalTransportCandidatesGenerated(payL); - } - - void emitonLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { - onLocalTransportCandidatesGenerated(payload); + void emitonLocalTransportCandidatesGenerated(const std::vector<JingleS5BTransportPayload::Candidate>& candidates) { + onLocalTransportCandidatesGenerated(candidates); } @@ -111,4 +109,14 @@ public: return JingleTransport::ref(); } + + virtual void start() SWIFTEN_OVERRIDE { + //JingleTransportPayload::ref payL = make_shared<JingleTransportPayload>(); + //payL->setSessionID(payload->getSessionID()); + // JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); + + onLocalTransportCandidatesGenerated(std::vector<JingleS5BTransportPayload::Candidate>()); + } + + virtual void stop() SWIFTEN_OVERRIDE {} }; @@ -145,5 +153,5 @@ public: fileInfo.setHash("asdjasdas"); fileInfo.setSize(1024 * 1024); - return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(boost::shared_ptr<JingleSession>(fakeJingleSession), fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, idGen, JID(), to, stream, fileInfo, s5bRegistry, s5bProxy)); + return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(boost::shared_ptr<JingleSession>(fakeJingleSession), fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, idGen, JID(), to, stream, fileInfo, s5bRegistry, s5bProxy, crypto.get())); } @@ -155,4 +163,5 @@ public: void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession"); jingleContentPayload = boost::make_shared<JingleContentPayload>(); @@ -165,5 +174,5 @@ public: connectionFactory = new DummyConnectionFactory(eventLoop); s5bRegistry = new SOCKS5BytestreamRegistry(); - s5bProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); + s5bProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); data.clear(); @@ -276,8 +285,10 @@ private: EventLoop *eventLoop; SOCKS5BytestreamRegistry* s5bRegistry; - SOCKS5BytestreamProxy* s5bProxy; + SOCKS5BytestreamProxiesManager* s5bProxy; DummyTimerFactory* timerFactory; DummyConnectionFactory* connectionFactory; + boost::shared_ptr<CryptoProvider> crypto; }; CPPUNIT_TEST_SUITE_REGISTRATION(OutgoingJingleFileTransferTest); +#endif diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp index bb0d9b6..78ea8ed 100644 --- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp @@ -31,8 +31,10 @@ #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; -boost::mt19937 randomGen; +static boost::mt19937 randomGen; class SOCKS5BytestreamClientSessionTest : public CppUnit::TestFixture { @@ -45,13 +47,11 @@ class SOCKS5BytestreamClientSessionTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE_END(); - const HostAddressPort destinationAddressPort; - const std::string destination; - public: - SOCKS5BytestreamClientSessionTest() : destinationAddressPort(HostAddressPort(HostAddress("127.0.0.1"), 8888)), - destination(SOCKS5BytestreamRegistry::getHostname("foo", JID("requester@example.com/test"), JID("target@example.com/test"))), eventLoop(NULL), timerFactory(NULL) { } + SOCKS5BytestreamClientSessionTest() : destinationAddressPort(HostAddressPort(HostAddress("127.0.0.1"), 8888)) {} void setUp() { - randomGen.seed(time(NULL)); + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + destination = "092a44d859d19c9eed676b551ee80025903351c2"; + randomGen.seed(static_cast<unsigned int>(time(NULL))); eventLoop = new DummyEventLoop(); timerFactory = new DummyTimerFactory(); @@ -83,5 +83,5 @@ public: eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00\x03", 4), createByteArray(&helper.unprocessedInput[0], 4)); - CPPUNIT_ASSERT_EQUAL(createByteArray(destination.size()), createByteArray(helper.unprocessedInput[4])); + CPPUNIT_ASSERT_EQUAL(createByteArray(static_cast<char>(destination.size())), createByteArray(static_cast<char>(helper.unprocessedInput[4]))); CPPUNIT_ASSERT_EQUAL(createByteArray(destination), createByteArray(&helper.unprocessedInput[5], destination.size())); CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1)); @@ -129,5 +129,5 @@ public: eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00\x03", 4), createByteArray(&helper.unprocessedInput[0], 4)); - CPPUNIT_ASSERT_EQUAL(createByteArray(destination.size()), createByteArray(helper.unprocessedInput[4])); + CPPUNIT_ASSERT_EQUAL(createByteArray(static_cast<char>(destination.size())), createByteArray(static_cast<char>(helper.unprocessedInput[4]))); CPPUNIT_ASSERT_EQUAL(createByteArray(destination), createByteArray(&helper.unprocessedInput[5], destination.size())); CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1)); @@ -165,5 +165,5 @@ public: ByteArray transferData = generateRandomByteArray(1024); - connection->onDataRead(createSafeByteArrayRef(transferData.data(), transferData.size())); + connection->onDataRead(createSafeByteArrayRef(vecptr(transferData), transferData.size())); CPPUNIT_ASSERT_EQUAL(transferData, output->getData()); } @@ -195,5 +195,5 @@ public: eventLoop->processEvents(); - CPPUNIT_ASSERT_EQUAL(createByteArray(transferData.data(), transferData.size()), helper.unprocessedInput); + CPPUNIT_ASSERT_EQUAL(createByteArray(vecptr(transferData), transferData.size()), helper.unprocessedInput); } @@ -206,5 +206,5 @@ private: ByteArray result(len); for (size_t i=0; i < len; ++i ) { - result[i] = randomByte(); + result[i] = static_cast<unsigned char>(randomByte()); } return result; @@ -222,5 +222,5 @@ private: void serverRespondRequestOK() { boost::shared_ptr<SafeByteArray> dataToSend = createSafeByteArrayRef("\x05\x00\x00\x03", 4); - append(*dataToSend, createSafeByteArray(destination.size())); + append(*dataToSend, createSafeByteArray(static_cast<char>(destination.size()))); append(*dataToSend, createSafeByteArray(destination)); append(*dataToSend, createSafeByteArray("\x00", 1)); @@ -230,5 +230,5 @@ private: void serverRespondRequestFail() { boost::shared_ptr<SafeByteArray> correctData = createSafeByteArrayRef("\x05\x00\x00\x03", 4); - append(*correctData, createSafeByteArray(destination.size())); + append(*correctData, createSafeByteArray(static_cast<char>(destination.size()))); append(*correctData, createSafeByteArray(destination)); append(*correctData, createSafeByteArray("\x00", 1)); @@ -240,5 +240,5 @@ private: do { ByteArray rndArray = generateRandomByteArray(correctData->size()); - dataToSend = createSafeByteArrayRef(rndArray.data(), rndArray.size()); + dataToSend = createSafeByteArrayRef(vecptr(rndArray), rndArray.size()); } while (*dataToSend == *correctData); connection->onDataRead(dataToSend); @@ -298,8 +298,11 @@ private: private: + HostAddressPort destinationAddressPort; + std::string destination; DummyEventLoop* eventLoop; DummyTimerFactory* timerFactory; boost::shared_ptr<MockeryConnection> connection; const std::vector<HostAddressPort> failingPorts; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp index e6df862..7af546f 100644 --- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp @@ -29,4 +29,6 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testReceiveData); CPPUNIT_TEST(testReceiveData_Chunked); + CPPUNIT_TEST(testDataStreamPauseStopsSendingData); + CPPUNIT_TEST(testDataStreamResumeAfterPauseSendsData); CPPUNIT_TEST_SUITE_END(); @@ -39,4 +41,5 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1)); stream1 = boost::make_shared<ByteArrayReadBytestream>(createByteArray("abcdefg")); + finished = false; } @@ -70,9 +73,9 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); ByteArray hostname(createByteArray("abcdef")); - receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(static_cast<char>(hostname.size())), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); CPPUNIT_ASSERT(createByteArray("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == createByteArray(&receivedData[0], 13)); } @@ -84,5 +87,5 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { ByteArray hostname(createByteArray("abcdef")); - receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(static_cast<char>(hostname.size())), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); CPPUNIT_ASSERT(createByteArray("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == receivedData); } @@ -91,9 +94,9 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); request("abcdef"); eventLoop->processEvents(); - testling->startTransfer(); + testling->startSending(stream1); skipHeader("abcdef"); eventLoop->processEvents(); @@ -107,9 +110,9 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { testling->setChunkSize(3); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams->addReadBytestream("abcdef", stream1); + bytestreams->setHasBytestream("abcdef", true); authenticate(); request("abcdef"); eventLoop->processEvents(); - testling->startTransfer(); + testling->startSending(stream1); eventLoop->processEvents(); skipHeader("abcdef"); @@ -118,4 +121,44 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { } + void testDataStreamPauseStopsSendingData() { + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + testling->setChunkSize(3); + stream1->setDataComplete(false); + StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); + bytestreams->setHasBytestream("abcdef", true); + authenticate(); + request("abcdef"); + eventLoop->processEvents(); + testling->startSending(stream1); + eventLoop->processEvents(); + skipHeader("abcdef"); + CPPUNIT_ASSERT(createByteArray("abcdefg") == receivedData); + CPPUNIT_ASSERT_EQUAL(4, receivedDataChunks); + + CPPUNIT_ASSERT(!finished); + CPPUNIT_ASSERT(!error); + } + + void testDataStreamResumeAfterPauseSendsData() { + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + testling->setChunkSize(3); + stream1->setDataComplete(false); + StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); + bytestreams->setHasBytestream("abcdef", true); + authenticate(); + request("abcdef"); + eventLoop->processEvents(); + testling->startSending(stream1); + eventLoop->processEvents(); + skipHeader("abcdef"); + + stream1->addData(createByteArray("xyz")); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(createByteArray("abcdefgxyz") == receivedData); + CPPUNIT_ASSERT(!finished); + CPPUNIT_ASSERT(!error); + } + private: void receive(const SafeByteArray& data) { @@ -131,9 +174,9 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { void request(const std::string& hostname) { - receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(static_cast<char>(hostname.size())), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); } void skipHeader(const std::string& hostname) { - int headerSize = 7 + hostname.size(); + size_t headerSize = 7 + hostname.size(); receivedData = createByteArray(&receivedData[headerSize], receivedData.size() - headerSize); } @@ -148,7 +191,13 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { SOCKS5BytestreamServerSession* createSession() { SOCKS5BytestreamServerSession* session = new SOCKS5BytestreamServerSession(connection, bytestreams); + session->onFinished.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleFinished, this, _1)); return session; } + void handleFinished(boost::optional<FileTransferError> error) { + finished = true; + this->error = error; + } + private: DummyEventLoop* eventLoop; @@ -158,4 +207,6 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { int receivedDataChunks; boost::shared_ptr<ByteArrayReadBytestream> stream1; + bool finished; + boost::optional<FileTransferError> error; }; diff --git a/Swiften/FileTransfer/WriteBytestream.h b/Swiften/FileTransfer/WriteBytestream.h index fb6f2f1..6085e78 100644 --- a/Swiften/FileTransfer/WriteBytestream.h +++ b/Swiften/FileTransfer/WriteBytestream.h @@ -10,8 +10,9 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> namespace Swift { - class WriteBytestream { + class SWIFTEN_API WriteBytestream { public: typedef boost::shared_ptr<WriteBytestream> ref; diff --git a/Swiften/History/HistoryManager.h b/Swiften/History/HistoryManager.h deleted file mode 100644 index 7a4324b..0000000 --- a/Swiften/History/HistoryManager.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 <vector> -#include <Swiften/JID/JID.h> -#include <Swiften/History/HistoryMessage.h> - -namespace Swift { - class HistoryManager { - public: - virtual ~HistoryManager(); - - virtual void addMessage(const HistoryMessage& message) = 0; - - virtual std::vector<HistoryMessage> getMessages() const = 0; - }; -} diff --git a/Swiften/History/HistoryMessage.h b/Swiften/History/HistoryMessage.h index 461f5de..b3d977f 100644 --- a/Swiften/History/HistoryMessage.h +++ b/Swiften/History/HistoryMessage.h @@ -13,5 +13,23 @@ namespace Swift { class HistoryMessage { public: - HistoryMessage(const std::string& message, const JID& from, const JID& to, const boost::posix_time::ptime time) : message_(message), from_(from), to_(to), time_(time) { + enum Type { + Chat = 0, + Groupchat = 1, + PrivateMessage = 2 + }; + + HistoryMessage( + const std::string& message, + const JID& fromJID, + const JID& toJID, + Type type, + const boost::posix_time::ptime& time, + int utcOffset = 0) : + message_(message), + fromJID_(fromJID), + toJID_(toJID), + type_(type), + time_(time), + utcOffset_(utcOffset) { } @@ -20,10 +38,14 @@ namespace Swift { } - const JID& getFrom() const { - return from_; + const JID& getFromJID() const { + return fromJID_; + } + + const JID& getToJID() const { + return toJID_; } - const JID& getTo() const { - return to_; + Type getType() const { + return type_; } @@ -32,13 +54,19 @@ namespace Swift { } + int getOffset() const { + return utcOffset_; + } + bool operator==(const HistoryMessage& o) const { - return message_ == o.message_ && from_ == o.from_ && to_ == o.to_ && time_ == o.time_; + return message_ == o.message_ && fromJID_ == o.fromJID_ && toJID_ == o.toJID_ && type_ == o.type_ && time_ == o.time_; } private: std::string message_; - JID from_; - JID to_; + JID fromJID_; + JID toJID_; + Type type_; boost::posix_time::ptime time_; + int utcOffset_; }; } diff --git a/Swiften/History/HistoryStorage.h b/Swiften/History/HistoryStorage.h new file mode 100644 index 0000000..6d24d15 --- /dev/null +++ b/Swiften/History/HistoryStorage.h @@ -0,0 +1,33 @@ +/* + * 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 <set> +#include <map> +#include <vector> +#include <Swiften/JID/JID.h> +#include <Swiften/History/HistoryMessage.h> +#include <boost/date_time/gregorian/gregorian_types.hpp> + +namespace Swift { + typedef std::map<JID, std::set<boost::gregorian::date> > ContactsMap; + + class HistoryStorage { + /** + * Messages are stored using localtime timestamps. + */ + public: + virtual ~HistoryStorage() {} + + virtual void addMessage(const HistoryMessage& message) = 0; + virtual std::vector<HistoryMessage> getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0; + virtual std::vector<HistoryMessage> getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0; + virtual std::vector<HistoryMessage> getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0; + virtual ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const = 0; + virtual boost::posix_time::ptime getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const = 0; + }; +} diff --git a/Swiften/History/SConscript b/Swiften/History/SConscript index 9c2a9d6..ac3cf3b 100644 --- a/Swiften/History/SConscript +++ b/Swiften/History/SConscript @@ -1,11 +1,11 @@ Import("swiften_env") -#myenv = swiften_env.Clone() -#if myenv["target"] == "native": -# myenv.MergeFlags(swiften_env.get("SQLITE_FLAGS", {})) -# -#objects = myenv.SwiftenObject([ -# "HistoryManager.cpp", -# "SQLiteHistoryManager.cpp", -# ]) -#swiften_env.Append(SWIFTEN_OBJECTS = [objects]) +myenv = swiften_env.Clone() +if myenv["target"] == "native": + myenv.MergeFlags(swiften_env.get("SQLITE_FLAGS", {})) + +if myenv["experimental"]: + objects = myenv.SwiftenObject([ + "SQLiteHistoryStorage.cpp", + ]) + swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/History/SQLiteHistoryManager.cpp b/Swiften/History/SQLiteHistoryManager.cpp deleted file mode 100644 index 3b65f62..0000000 --- a/Swiften/History/SQLiteHistoryManager.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <iostream> -#include <boost/lexical_cast.hpp> - -#include <sqlite3.h> -#include <Swiften/History/SQLiteHistoryManager.h> - -namespace { - -inline Swift::std::string getEscapedString(const Swift::std::string& s) { - Swift::std::string result(s); - result.replaceAll('\'', Swift::std::string("\\'")); - return result; -} - -} - - -namespace Swift { - -SQLiteHistoryManager::SQLiteHistoryManager(const std::string& file) : db_(0) { - sqlite3_open(file.c_str(), &db_); - if (!db_) { - std::cerr << "Error opening database " << file << std::endl; // FIXME - } - - char* errorMessage; - int result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS messages('from' INTEGER, 'to' INTEGER, 'message' STRING, 'time' INTEGER)", 0, 0, &errorMessage); - if (result != SQLITE_OK) { - std::cerr << "SQL Error: " << errorMessage << std::endl; - sqlite3_free(errorMessage); - } - - result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS jids('id' INTEGER PRIMARY KEY ASC AUTOINCREMENT, 'jid' STRING UNIQUE NOT NULL)", 0, 0, &errorMessage); - if (result != SQLITE_OK) { - std::cerr << "SQL Error: " << errorMessage << std::endl; - sqlite3_free(errorMessage); - } -} - -SQLiteHistoryManager::~SQLiteHistoryManager() { - sqlite3_close(db_); -} - -void SQLiteHistoryManager::addMessage(const HistoryMessage& message) { - int secondsSinceEpoch = (message.getTime() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds(); - std::string statement = std::string("INSERT INTO messages('from', 'to', 'message', 'time') VALUES(") + boost::lexical_cast<std::string>(getIDForJID(message.getFrom())) + ", " + boost::lexical_cast<std::string>(getIDForJID(message.getTo())) + ", '" + getEscapedString(message.getMessage()) + "', " + boost::lexical_cast<std::string>(secondsSinceEpoch) + ")"; - char* errorMessage; - int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage); - if (result != SQLITE_OK) { - std::cerr << "SQL Error: " << errorMessage << std::endl; - sqlite3_free(errorMessage); - } -} - -std::vector<HistoryMessage> SQLiteHistoryManager::getMessages() const { - std::vector<HistoryMessage> result; - sqlite3_stmt* selectStatement; - std::string selectQuery("SELECT messages.'from', messages.'to', messages.'message', messages.'time' FROM messages"); - int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL); - if (r != SQLITE_OK) { - std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; - } - r = sqlite3_step(selectStatement); - while (r == SQLITE_ROW) { - boost::optional<JID> from(getJIDFromID(sqlite3_column_int(selectStatement, 0))); - boost::optional<JID> to(getJIDFromID(sqlite3_column_int(selectStatement, 1))); - std::string message(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 2))); - int secondsSinceEpoch(sqlite3_column_int(selectStatement, 3)); - boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch)); - - result.push_back(HistoryMessage(message, (from ? *from : JID()), (to ? *to : JID()), time)); - r = sqlite3_step(selectStatement); - } - if (r != SQLITE_DONE) { - std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; - } - sqlite3_finalize(selectStatement); - return result; -} - -int SQLiteHistoryManager::getIDForJID(const JID& jid) { - boost::optional<int> id = getIDFromJID(jid); - if (id) { - return *id; - } - else { - return addJID(jid); - } -} - -int SQLiteHistoryManager::addJID(const JID& jid) { - std::string statement = std::string("INSERT INTO jids('jid') VALUES('") + getEscapedString(jid.toString()) + "')"; - char* errorMessage; - int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage); - if (result != SQLITE_OK) { - std::cerr << "SQL Error: " << errorMessage << std::endl; - sqlite3_free(errorMessage); - } - return sqlite3_last_insert_rowid(db_); -} - -boost::optional<JID> SQLiteHistoryManager::getJIDFromID(int id) const { - boost::optional<JID> result; - sqlite3_stmt* selectStatement; - std::string selectQuery("SELECT jid FROM jids WHERE id=" + boost::lexical_cast<std::string>(id)); - int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL); - if (r != SQLITE_OK) { - std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; - } - r = sqlite3_step(selectStatement); - if (r == SQLITE_ROW) { - result = boost::optional<JID>(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 0))); - } - sqlite3_finalize(selectStatement); - return result; -} - -boost::optional<int> SQLiteHistoryManager::getIDFromJID(const JID& jid) const { - boost::optional<int> result; - sqlite3_stmt* selectStatement; - std::string selectQuery("SELECT id FROM jids WHERE jid='" + jid.toString() + "'"); - int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL); - if (r != SQLITE_OK) { - std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; - } - r = sqlite3_step(selectStatement); - if (r == SQLITE_ROW) { - result = boost::optional<int>(sqlite3_column_int(selectStatement, 0)); - } - sqlite3_finalize(selectStatement); - return result; -} - -} diff --git a/Swiften/History/SQLiteHistoryManager.h b/Swiften/History/SQLiteHistoryManager.h deleted file mode 100644 index ffd9492..0000000 --- a/Swiften/History/SQLiteHistoryManager.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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/History/HistoryManager.h> - -struct sqlite3; - -namespace Swift { - class SQLiteHistoryManager : public HistoryManager { - public: - SQLiteHistoryManager(const std::string& file); - ~SQLiteHistoryManager(); - - virtual void addMessage(const HistoryMessage& message); - virtual std::vector<HistoryMessage> getMessages() const; - - int getIDForJID(const JID&); - int addJID(const JID&); - - boost::optional<JID> getJIDFromID(int id) const; - boost::optional<int> getIDFromJID(const JID& jid) const; - - private: - sqlite3* db_; - }; -} diff --git a/Swiften/History/SQLiteHistoryStorage.cpp b/Swiften/History/SQLiteHistoryStorage.cpp new file mode 100644 index 0000000..dda8766 --- /dev/null +++ b/Swiften/History/SQLiteHistoryStorage.cpp @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2010-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <iostream> +#include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <sqlite3.h> +#include <Swiften/History/SQLiteHistoryStorage.h> +#include <boost/date_time/gregorian/gregorian.hpp> +#include <Swiften/Base/Path.h> + +inline std::string getEscapedString(const std::string& s) { + std::string result(s); + + size_t pos = result.find('\''); + while (pos != std::string::npos) { + result.insert(pos, "'"); + pos = result.find('\'', pos + 2); + } + return result; +} + +namespace Swift { + +SQLiteHistoryStorage::SQLiteHistoryStorage(const boost::filesystem::path& file) : db_(0) { + thread_ = new boost::thread(boost::bind(&SQLiteHistoryStorage::run, this)); + + sqlite3_open(pathToString(file).c_str(), &db_); + if (!db_) { + std::cerr << "Error opening database " << pathToString(file) << std::endl; + } + + char* errorMessage; + int result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS messages('message' STRING, 'fromBare' INTEGER, 'fromResource' STRING, 'toBare' INTEGER, 'toResource' STRING, 'type' INTEGER, 'time' INTEGER, 'offset' INTEGER)", 0, 0, &errorMessage); + if (result != SQLITE_OK) { + std::cerr << "SQL Error: " << errorMessage << std::endl; + sqlite3_free(errorMessage); + } + + result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS jids('id' INTEGER PRIMARY KEY ASC AUTOINCREMENT, 'jid' STRING UNIQUE NOT NULL)", 0, 0, &errorMessage); + if (result != SQLITE_OK) { + std::cerr << "SQL Error: " << errorMessage << std::endl; + sqlite3_free(errorMessage); + } +} + +SQLiteHistoryStorage::~SQLiteHistoryStorage() { + sqlite3_close(db_); + delete thread_; +} + +void SQLiteHistoryStorage::addMessage(const HistoryMessage& message) { + int secondsSinceEpoch = (message.getTime() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds(); + + std::string statement = std::string("INSERT INTO messages('message', 'fromBare', 'fromResource', 'toBare', 'toResource', 'type', 'time', 'offset') VALUES(") + + "'" + getEscapedString(message.getMessage()) + "', " + + boost::lexical_cast<std::string>(getIDForJID(message.getFromJID().toBare())) + ", '" + + getEscapedString(message.getFromJID().getResource()) + "', " + + boost::lexical_cast<std::string>(getIDForJID(message.getToJID().toBare())) + ", '" + + getEscapedString(message.getToJID().getResource()) + "', " + + boost::lexical_cast<std::string>(message.getType()) + ", " + + boost::lexical_cast<std::string>(secondsSinceEpoch) + ", " + + boost::lexical_cast<std::string>(message.getOffset()) + ")"; + char* errorMessage; + int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage); + if (result != SQLITE_OK) { + std::cerr << "SQL Error: " << errorMessage << std::endl; + sqlite3_free(errorMessage); + } +} + +std::vector<HistoryMessage> SQLiteHistoryStorage::getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + sqlite3_stmt* selectStatement; + + boost::optional<long long> selfID = getIDFromJID(selfJID.toBare()); + boost::optional<long long> contactID = getIDFromJID(contactJID.toBare()); + + if (!selfID || !contactID) { + // JIDs missing from the database + return std::vector<HistoryMessage>(); + } + + std::string selectQuery = "SELECT * FROM messages WHERE (type=" + boost::lexical_cast<std::string>(type); + if (contactJID.isBare()) { + // match only bare jid + selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" + + boost::lexical_cast<std::string>(*contactID) + ") OR (fromBare=" + + boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + ")))"; + } + else { + // match resource too + selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND (toBare=" + + boost::lexical_cast<std::string>(*contactID) +" AND toResource='" + + getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" + + boost::lexical_cast<std::string>(*contactID) + " AND fromResource='" + + getEscapedString(contactJID.getResource()) + "') AND toBare=" + + boost::lexical_cast<std::string>(*selfID) + ")))"; + } + + if (!date.is_not_a_date()) { + int lowerBound = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds(); + int upperBound = lowerBound + 86400; + + selectQuery += " AND (time>=" + boost::lexical_cast<std::string>(lowerBound) + + " AND time<" + boost::lexical_cast<std::string>(upperBound) + ")"; + } + + int r = sqlite3_prepare(db_, selectQuery.c_str(), boost::numeric_cast<int>(selectQuery.size()), &selectStatement, NULL); + if (r != SQLITE_OK) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + r = sqlite3_step(selectStatement); + + // Retrieve result + std::vector<HistoryMessage> result; + while (r == SQLITE_ROW) { + std::string message(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 0))); + + // fromJID + boost::optional<JID> fromJID(getJIDFromID(sqlite3_column_int(selectStatement, 1))); + std::string fromResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 2))); + if (fromJID) { + fromJID = boost::optional<JID>(JID(fromJID->getNode(), fromJID->getDomain(), fromResource)); + } + + // toJID + boost::optional<JID> toJID(getJIDFromID(sqlite3_column_int(selectStatement, 3))); + std::string toResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 4))); + if (toJID) { + toJID = boost::optional<JID>(JID(toJID->getNode(), toJID->getDomain(), toResource)); + } + + // message type + HistoryMessage::Type type = static_cast<HistoryMessage::Type>(sqlite3_column_int(selectStatement, 5)); + + // timestamp + int secondsSinceEpoch(sqlite3_column_int(selectStatement, 6)); + boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch)); + + // offset from utc + int offset = sqlite3_column_int(selectStatement, 7); + + result.push_back(HistoryMessage(message, (fromJID ? *fromJID : JID()), (toJID ? *toJID : JID()), type, time, offset)); + r = sqlite3_step(selectStatement); + } + if (r != SQLITE_DONE) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + sqlite3_finalize(selectStatement); + + return result; +} + +long long SQLiteHistoryStorage::getIDForJID(const JID& jid) { + boost::optional<long long> id = getIDFromJID(jid); + if (id) { + return *id; + } + else { + return addJID(jid); + } +} + +long long SQLiteHistoryStorage::addJID(const JID& jid) { + std::string statement = std::string("INSERT INTO jids('jid') VALUES('") + getEscapedString(jid.toString()) + "')"; + char* errorMessage; + int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage); + if (result != SQLITE_OK) { + std::cerr << "SQL Error: " << errorMessage << std::endl; + sqlite3_free(errorMessage); + } + return sqlite3_last_insert_rowid(db_); +} + +boost::optional<JID> SQLiteHistoryStorage::getJIDFromID(long long id) const { + boost::optional<JID> result; + sqlite3_stmt* selectStatement; + std::string selectQuery("SELECT jid FROM jids WHERE id=" + boost::lexical_cast<std::string>(id)); + int r = sqlite3_prepare(db_, selectQuery.c_str(), boost::numeric_cast<int>(selectQuery.size()), &selectStatement, NULL); + if (r != SQLITE_OK) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + r = sqlite3_step(selectStatement); + if (r == SQLITE_ROW) { + result = boost::optional<JID>(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 0))); + } + sqlite3_finalize(selectStatement); + return result; +} + +boost::optional<long long> SQLiteHistoryStorage::getIDFromJID(const JID& jid) const { + boost::optional<long long> result; + sqlite3_stmt* selectStatement; + std::string selectQuery("SELECT id FROM jids WHERE jid='" + jid.toString() + "'"); + long long r = sqlite3_prepare(db_, selectQuery.c_str(), boost::numeric_cast<int>(selectQuery.size()), &selectStatement, NULL); + if (r != SQLITE_OK) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + r = sqlite3_step(selectStatement); + if (r == SQLITE_ROW) { + result = boost::optional<long long>(sqlite3_column_int(selectStatement, 0)); + } + sqlite3_finalize(selectStatement); + return result; +} + +ContactsMap SQLiteHistoryStorage::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const { + ContactsMap result; + sqlite3_stmt* selectStatement; + + // get id + boost::optional<long long> id = getIDFromJID(selfJID); + if (!id) { + return result; + } + + // get contacts + std::string query = "SELECT DISTINCT messages.'fromBare', messages.'fromResource', messages.'toBare', messages.'toResource', messages.'time' " + "FROM messages WHERE (type=" + + boost::lexical_cast<std::string>(type) + " AND (toBare=" + + boost::lexical_cast<std::string>(*id) + " OR fromBare=" + boost::lexical_cast<std::string>(*id) + "))"; + + // match keyword + if (getEscapedString(keyword).length()) { + query += " AND message LIKE '%" + getEscapedString(keyword) + "%'"; + } + + int r = sqlite3_prepare(db_, query.c_str(), boost::numeric_cast<int>(query.size()), &selectStatement, NULL); + if (r != SQLITE_OK) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + + r = sqlite3_step(selectStatement); + while (r == SQLITE_ROW) { + int fromBareID = sqlite3_column_int(selectStatement, 0); + std::string fromResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 1))); + int toBareID = sqlite3_column_int(selectStatement, 2); + std::string toResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 3))); + std::string resource; + + int secondsSinceEpoch(sqlite3_column_int(selectStatement, 4)); + boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch)); + + boost::optional<JID> contactJID; + + if (fromBareID == *id) { + contactJID = getJIDFromID(toBareID); + resource = toResource; + } + else { + contactJID = getJIDFromID(fromBareID); + resource = fromResource; + } + + // check if it is a MUC contact (from a private conversation) + if (type == HistoryMessage::PrivateMessage) { + contactJID = boost::optional<JID>(JID(contactJID->getNode(), contactJID->getDomain(), resource)); + } + + if (contactJID) { + result[*contactJID].insert(time.date()); + } + + r = sqlite3_step(selectStatement); + } + + if (r != SQLITE_DONE) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + sqlite3_finalize(selectStatement); + + return result; +} + +boost::gregorian::date SQLiteHistoryStorage::getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const { + sqlite3_stmt* selectStatement; + boost::optional<long long> selfID = getIDFromJID(selfJID.toBare()); + boost::optional<long long> contactID = getIDFromJID(contactJID.toBare()); + + if (!selfID || !contactID) { + // JIDs missing from the database + return boost::gregorian::date(boost::gregorian::not_a_date_time); + } + + std::string selectQuery = "SELECT time FROM messages WHERE (type=" + boost::lexical_cast<std::string>(type); + if (contactJID.isBare()) { + // match only bare jid + selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" + + boost::lexical_cast<std::string>(*contactID) + ") OR (fromBare=" + + boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + ")))"; + } + else { + // match resource too + selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND (toBare=" + + boost::lexical_cast<std::string>(*contactID) +" AND toResource='" + + getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" + + boost::lexical_cast<std::string>(*contactID) + " AND fromResource='" + + getEscapedString(contactJID.getResource()) + "') AND toBare=" + + boost::lexical_cast<std::string>(*selfID) + ")))"; + } + + int timeStamp = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds() + (reverseOrder ? 0 : 86400); + + selectQuery += " AND time" + (reverseOrder ? std::string("<") : std::string(">")) + boost::lexical_cast<std::string>(timeStamp); + selectQuery += " ORDER BY time " + (reverseOrder ? std::string("DESC") : std::string("ASC")) + " LIMIT 1"; + + int r = sqlite3_prepare(db_, selectQuery.c_str(), boost::numeric_cast<int>(selectQuery.size()), &selectStatement, NULL); + if (r != SQLITE_OK) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + + r = sqlite3_step(selectStatement); + if (r == SQLITE_ROW) { + int secondsSinceEpoch(sqlite3_column_int(selectStatement, 0)); + boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch)); + std::cout << "next day is: " << time.date() << "\n"; + return time.date(); + } + + return boost::gregorian::date(boost::gregorian::not_a_date_time); +} + +std::vector<HistoryMessage> SQLiteHistoryStorage::getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + boost::gregorian::date nextDate = getNextDateWithLogs(selfJID, contactJID, type, date, false); + + if (nextDate.is_not_a_date()) { + return std::vector<HistoryMessage>(); + } + + return getMessagesFromDate(selfJID, contactJID, type, nextDate); +} + +std::vector<HistoryMessage> SQLiteHistoryStorage::getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + boost::gregorian::date previousDate = getNextDateWithLogs(selfJID, contactJID, type, date, true); + + if (previousDate.is_not_a_date()) { + return std::vector<HistoryMessage>(); + } + + return getMessagesFromDate(selfJID, contactJID, type, previousDate); +} + +boost::posix_time::ptime SQLiteHistoryStorage::getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const { + boost::optional<long long> selfID = getIDFromJID(selfJID.toBare()); + boost::optional<long long> mucID = getIDFromJID(mucJID.toBare()); + + if (!selfID || !mucID) { + // JIDs missing from the database + return boost::posix_time::ptime(boost::posix_time::not_a_date_time); + } + + + sqlite3_stmt* selectStatement; + std::string selectQuery = "SELECT messages.'time', messages.'offset' from messages WHERE type=1 AND (toBare=" + + boost::lexical_cast<std::string>(*selfID) + " AND fromBare=" + + boost::lexical_cast<std::string>(*mucID) + ") ORDER BY time DESC LIMIT 1"; + + int r = sqlite3_prepare(db_, selectQuery.c_str(), boost::numeric_cast<int>(selectQuery.size()), &selectStatement, NULL); + if (r != SQLITE_OK) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + + r = sqlite3_step(selectStatement); + if (r == SQLITE_ROW) { + int secondsSinceEpoch(sqlite3_column_int(selectStatement, 0)); + boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch)); + int offset = sqlite3_column_int(selectStatement, 1); + + return time - boost::posix_time::hours(offset); + } + + return boost::posix_time::ptime(boost::posix_time::not_a_date_time); +} + +void SQLiteHistoryStorage::run() { +} + +} diff --git a/Swiften/History/SQLiteHistoryStorage.h b/Swiften/History/SQLiteHistoryStorage.h new file mode 100644 index 0000000..2c1ba7a --- /dev/null +++ b/Swiften/History/SQLiteHistoryStorage.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010-2013 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/Base/API.h> +#include <Swiften/History/HistoryStorage.h> +#include <boost/thread.hpp> +#include <boost/filesystem/path.hpp> + +struct sqlite3; + +namespace Swift { + class SWIFTEN_API SQLiteHistoryStorage : public HistoryStorage { + public: + SQLiteHistoryStorage(const boost::filesystem::path& file); + ~SQLiteHistoryStorage(); + + void addMessage(const HistoryMessage& message); + ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const; + std::vector<HistoryMessage> getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector<HistoryMessage> getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector<HistoryMessage> getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + boost::posix_time::ptime getLastTimeStampFromMUC(const JID& selfJID, const JID& mucJID) const; + + private: + void run(); + boost::gregorian::date getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const; + long long getIDForJID(const JID&); + long long addJID(const JID&); + + boost::optional<JID> getJIDFromID(long long id) const; + boost::optional<long long> getIDFromJID(const JID& jid) const; + + sqlite3* db_; + boost::thread* thread_; + }; +} diff --git a/Swiften/IDN/ICUConverter.cpp b/Swiften/IDN/ICUConverter.cpp new file mode 100644 index 0000000..f698eb9 --- /dev/null +++ b/Swiften/IDN/ICUConverter.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/IDN/ICUConverter.h> + +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wheader-hygiene" +#include <unicode/uidna.h> +#include <unicode/usprep.h> +#include <unicode/ucnv.h> +#include <unicode/ustring.h> + + #include <boost/numeric/conversion/cast.hpp> + +using namespace Swift; +using boost::numeric_cast; + +namespace { + typedef std::vector<UChar, SafeAllocator<UChar> > ICUString; + + const char* toConstCharArray(const std::string& input) { + return input.c_str(); + } + + const char* toConstCharArray(const std::vector<unsigned char, SafeAllocator<unsigned char> >& input) { + return reinterpret_cast<const char*>(vecptr(input)); + } + + template<typename T> + ICUString convertToICUString(const T& s) { + ICUString result; + result.resize(s.size()); + UErrorCode status = U_ZERO_ERROR; + int32_t icuResultLength = numeric_cast<int32_t>(result.size()); + u_strFromUTF8Lenient(vecptr(result), numeric_cast<int32_t>(result.size()), &icuResultLength, toConstCharArray(s), numeric_cast<int32_t>(s.size()), &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + result.resize(numeric_cast<size_t>(icuResultLength)); + u_strFromUTF8Lenient(vecptr(result), numeric_cast<int32_t>(result.size()), &icuResultLength, toConstCharArray(s), numeric_cast<int32_t>(s.size()), &status); + } + if (U_FAILURE(status)) { + return ICUString(); + } + result.resize(numeric_cast<size_t>(icuResultLength)); + return result; + } + + std::vector<char, SafeAllocator<char> > convertToArray(const ICUString& input) { + std::vector<char, SafeAllocator<char> > result; + result.resize(input.size()); + UErrorCode status = U_ZERO_ERROR; + int32_t inputLength = numeric_cast<int32_t>(result.size()); + u_strToUTF8(vecptr(result), numeric_cast<int32_t>(result.size()), &inputLength, vecptr(input), numeric_cast<int32_t>(input.size()), &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + result.resize(numeric_cast<size_t>(inputLength)); + u_strToUTF8(vecptr(result), numeric_cast<int32_t>(result.size()), &inputLength, vecptr(input), numeric_cast<int32_t>(input.size()), &status); + } + if (U_FAILURE(status)) { + return std::vector<char, SafeAllocator<char> >(); + } + + result.resize(numeric_cast<size_t>(inputLength) + 1); + result[result.size() - 1] = '\0'; + return result; + } + + std::string convertToString(const ICUString& input) { + return std::string(vecptr(convertToArray(input))); + } + + UStringPrepProfileType getICUProfileType(IDNConverter::StringPrepProfile profile) { + switch(profile) { + case IDNConverter::NamePrep: return USPREP_RFC3491_NAMEPREP; + case IDNConverter::XMPPNodePrep: return USPREP_RFC3920_NODEPREP; + case IDNConverter::XMPPResourcePrep: return USPREP_RFC3920_RESOURCEPREP; + case IDNConverter::SASLPrep: return USPREP_RFC4013_SASLPREP; + } + assert(false); + return USPREP_RFC3491_NAMEPREP; + } + + template<typename StringType> + std::vector<char, SafeAllocator<char> > getStringPreparedDetail(const StringType& s, IDNConverter::StringPrepProfile profile) { + UErrorCode status = U_ZERO_ERROR; + + boost::shared_ptr<UStringPrepProfile> icuProfile(usprep_openByType(getICUProfileType(profile), &status), usprep_close); + assert(U_SUCCESS(status)); + + ICUString icuInput = convertToICUString(s); + ICUString icuResult; + UParseError parseError; + icuResult.resize(icuInput.size()); + int32_t icuResultLength = usprep_prepare(icuProfile.get(), vecptr(icuInput), numeric_cast<int32_t>(icuInput.size()), vecptr(icuResult), numeric_cast<int32_t>(icuResult.size()), USPREP_ALLOW_UNASSIGNED, &parseError, &status); + icuResult.resize(numeric_cast<size_t>(icuResultLength)); + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + icuResult.resize(numeric_cast<size_t>(icuResultLength)); + icuResultLength = usprep_prepare(icuProfile.get(), vecptr(icuInput), numeric_cast<int32_t>(icuInput.size()), vecptr(icuResult), numeric_cast<int32_t>(icuResult.size()), USPREP_ALLOW_UNASSIGNED, &parseError, &status); + icuResult.resize(numeric_cast<size_t>(icuResultLength)); + } + if (U_FAILURE(status)) { + return std::vector<char, SafeAllocator<char> >(); + } + icuResult.resize(numeric_cast<size_t>(icuResultLength)); + + return convertToArray(icuResult); + } +} + +namespace Swift { + +std::string ICUConverter::getStringPrepared(const std::string& s, StringPrepProfile profile) { + if (s.empty()) { + return ""; + } + std::vector<char, SafeAllocator<char> > preparedData = getStringPreparedDetail(s, profile); + if (preparedData.empty()) { + throw std::exception(); + } + return std::string(vecptr(preparedData)); +} + +SafeByteArray ICUConverter::getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) { + if (s.empty()) { + return SafeByteArray(); + } + std::vector<char, SafeAllocator<char> > preparedData = getStringPreparedDetail(s, profile); + if (preparedData.empty()) { + throw std::exception(); + } + return createSafeByteArray(reinterpret_cast<const char*>(vecptr(preparedData))); +} + +boost::optional<std::string> ICUConverter::getIDNAEncoded(const std::string& domain) { + UErrorCode status = U_ZERO_ERROR; + ICUString icuInput = convertToICUString(domain); + ICUString icuResult; + icuResult.resize(icuInput.size()); + UParseError parseError; + int32_t icuResultLength = uidna_IDNToASCII(vecptr(icuInput), numeric_cast<int32_t>(icuInput.size()), vecptr(icuResult), numeric_cast<int32_t>(icuResult.size()), UIDNA_USE_STD3_RULES, &parseError, &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + icuResult.resize(numeric_cast<size_t>(icuResultLength)); + icuResultLength = uidna_IDNToASCII(vecptr(icuInput), numeric_cast<int32_t>(icuInput.size()), vecptr(icuResult), numeric_cast<int32_t>(icuResult.size()), UIDNA_USE_STD3_RULES, &parseError, &status); + } + if (U_FAILURE(status)) { + return boost::optional<std::string>(); + } + icuResult.resize(numeric_cast<size_t>(icuResultLength)); + return convertToString(icuResult); +} + +} diff --git a/Swiften/IDN/ICUConverter.h b/Swiften/IDN/ICUConverter.h new file mode 100644 index 0000000..05eafcc --- /dev/null +++ b/Swiften/IDN/ICUConverter.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> +#include <Swiften/IDN/IDNConverter.h> + +namespace Swift { + class SWIFTEN_API ICUConverter : public IDNConverter { + public: + virtual std::string getStringPrepared(const std::string& s, StringPrepProfile profile) SWIFTEN_OVERRIDE; + virtual SafeByteArray getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) SWIFTEN_OVERRIDE; + + virtual boost::optional<std::string> getIDNAEncoded(const std::string& s) SWIFTEN_OVERRIDE; + }; +} diff --git a/Swiften/IDN/IDNA.cpp b/Swiften/IDN/IDNA.cpp deleted file mode 100644 index 16b4183..0000000 --- a/Swiften/IDN/IDNA.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/IDN/IDNA.h> - -#include <stringprep.h> -#include <vector> -#include <cstdlib> -#include <idna.h> - -namespace Swift { - -std::string IDNA::getEncoded(const std::string& domain) { - char* output; - if (idna_to_ascii_8z(domain.c_str(), &output, 0) == IDNA_SUCCESS) { - std::string result(output); - free(output); - return result; - } - else { - return domain; - } -} - -} diff --git a/Swiften/History/HistoryManager.cpp b/Swiften/IDN/IDNConverter.cpp index 7eb66ab..7705812 100644 --- a/Swiften/History/HistoryManager.cpp +++ b/Swiften/IDN/IDNConverter.cpp @@ -1,13 +1,13 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <Swiften/History/HistoryManager.h> +#include <Swiften/IDN/IDNConverter.h> namespace Swift { -HistoryManager::~HistoryManager() { +IDNConverter::~IDNConverter() { } diff --git a/Swiften/IDN/IDNConverter.h b/Swiften/IDN/IDNConverter.h new file mode 100644 index 0000000..f6974bc --- /dev/null +++ b/Swiften/IDN/IDNConverter.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <Swiften/Base/API.h> +#include <Swiften/Base/SafeByteArray.h> +#include <boost/optional.hpp> + +namespace Swift { + class SWIFTEN_API IDNConverter { + public: + virtual ~IDNConverter(); + + enum StringPrepProfile { + NamePrep, + XMPPNodePrep, + XMPPResourcePrep, + SASLPrep + }; + + virtual std::string getStringPrepared(const std::string& s, StringPrepProfile profile) = 0; + virtual SafeByteArray getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) = 0; + + // Thread-safe + virtual boost::optional<std::string> getIDNAEncoded(const std::string& s) = 0; + }; +} diff --git a/Swiften/IDN/LibIDNConverter.cpp b/Swiften/IDN/LibIDNConverter.cpp new file mode 100644 index 0000000..45b1d14 --- /dev/null +++ b/Swiften/IDN/LibIDNConverter.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/IDN/LibIDNConverter.h> + +extern "C" { + #include <stringprep.h> + #include <idna.h> +} + +#include <vector> +#include <cassert> +#include <cstdlib> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeAllocator.h> +#include <boost/shared_ptr.hpp> + +using namespace Swift; + +namespace { + static const int MAX_STRINGPREP_SIZE = 1024; + + const Stringprep_profile* getLibIDNProfile(IDNConverter::StringPrepProfile profile) { + switch(profile) { + case IDNConverter::NamePrep: return stringprep_nameprep; + case IDNConverter::XMPPNodePrep: return stringprep_xmpp_nodeprep; + case IDNConverter::XMPPResourcePrep: return stringprep_xmpp_resourceprep; + case IDNConverter::SASLPrep: return stringprep_saslprep; + } + assert(false); + return 0; + } + + template<typename StringType, typename ContainerType> + ContainerType getStringPreparedInternal(const StringType& s, IDNConverter::StringPrepProfile profile) { + ContainerType input(s.begin(), s.end()); + input.resize(MAX_STRINGPREP_SIZE); + if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) { + return input; + } + else { + return ContainerType(); + } + } +} + +namespace Swift { + +std::string LibIDNConverter::getStringPrepared(const std::string& s, StringPrepProfile profile) { + std::vector<char> preparedData = getStringPreparedInternal< std::string, std::vector<char> >(s, profile); + if (preparedData.empty()) { + throw std::exception(); + } + return std::string(vecptr(preparedData)); +} + +SafeByteArray LibIDNConverter::getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) { + std::vector<char, SafeAllocator<char> > preparedData = getStringPreparedInternal<SafeByteArray, std::vector<char, SafeAllocator<char> > >(s, profile); + if (preparedData.empty()) { + throw std::exception(); + } + return createSafeByteArray(reinterpret_cast<const char*>(vecptr(preparedData))); +} + +boost::optional<std::string> LibIDNConverter::getIDNAEncoded(const std::string& domain) { + char* output; + if (idna_to_ascii_8z(domain.c_str(), &output, IDNA_USE_STD3_ASCII_RULES) == IDNA_SUCCESS) { + std::string result(output); + free(output); + return result; + } + else { + return boost::optional<std::string>(); + } +} + +} diff --git a/Swiften/IDN/LibIDNConverter.h b/Swiften/IDN/LibIDNConverter.h new file mode 100644 index 0000000..4cfff1a --- /dev/null +++ b/Swiften/IDN/LibIDNConverter.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2012-2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> +#include <Swiften/IDN/IDNConverter.h> + +namespace Swift { + class SWIFTEN_API LibIDNConverter : public IDNConverter { + public: + virtual std::string getStringPrepared(const std::string& s, StringPrepProfile profile) SWIFTEN_OVERRIDE; + virtual SafeByteArray getStringPrepared(const SafeByteArray& s, StringPrepProfile profile) SWIFTEN_OVERRIDE; + + virtual boost::optional<std::string> getIDNAEncoded(const std::string& s) SWIFTEN_OVERRIDE; + }; +} + diff --git a/Swiften/IDN/PlatformIDNConverter.cpp b/Swiften/IDN/PlatformIDNConverter.cpp new file mode 100644 index 0000000..4882b60 --- /dev/null +++ b/Swiften/IDN/PlatformIDNConverter.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/IDN/PlatformIDNConverter.h> +#if defined(HAVE_LIBIDN) +#include <Swiften/IDN/LibIDNConverter.h> +#elif defined(HAVE_ICU) +#include <Swiften/IDN/ICUConverter.h> +#endif + +namespace Swift { + +IDNConverter* PlatformIDNConverter::create() { +#if defined(HAVE_LIBIDN) + return new LibIDNConverter(); +#elif defined(HAVE_ICU) + return new ICUConverter(); +#else +#if defined(NEED_IDN) +#error "No IDN implementation" +#endif + return 0; +#endif +} + +} diff --git a/Swiften/IDN/PlatformIDNConverter.h b/Swiften/IDN/PlatformIDNConverter.h new file mode 100644 index 0000000..4b1025b --- /dev/null +++ b/Swiften/IDN/PlatformIDNConverter.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> + +namespace Swift { + class IDNConverter; + + namespace PlatformIDNConverter { + SWIFTEN_API IDNConverter* create(); + } +} diff --git a/Swiften/IDN/SConscript b/Swiften/IDN/SConscript index 99b35fd..4c1a71d 100644 --- a/Swiften/IDN/SConscript +++ b/Swiften/IDN/SConscript @@ -1,14 +1,28 @@ Import("swiften_env", "env") + +objects = swiften_env.SwiftenObject(["IDNConverter.cpp"]) + myenv = swiften_env.Clone() +if myenv.get("NEED_IDN"): + myenv.Append(CPPDEFINES = ["NEED_IDN"]) +if myenv.get("HAVE_ICU") : + myenv.MergeFlags(swiften_env["ICU_FLAGS"]) + myenv.Append(CPPDEFINES = ["HAVE_ICU"]) + objects += myenv.SwiftenObject(["ICUConverter.cpp"]) +if myenv.get("HAVE_LIBIDN") : myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) + myenv.Append(CPPDEFINES = ["HAVE_LIBIDN"]) + objects += myenv.SwiftenObject(["LibIDNConverter.cpp"]) +objects += myenv.SwiftenObject(["PlatformIDNConverter.cpp"]) -objects = myenv.SwiftenObject([ - "StringPrep.cpp", - "IDNA.cpp", - ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) -env.Append(UNITTEST_SOURCES = [ - File("UnitTest/StringPrepTest.cpp"), - ]) +if env["TEST"] : + test_env = myenv.Clone() + test_env.UseFlags(swiften_env["CPPUNIT_FLAGS"]) + env.Append(UNITTEST_OBJECTS = test_env.SwiftenObject([ + File("UnitTest/IDNConverterTest.cpp"), + ])) + + diff --git a/Swiften/IDN/StringPrep.cpp b/Swiften/IDN/StringPrep.cpp deleted file mode 100644 index 9085569..0000000 --- a/Swiften/IDN/StringPrep.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/IDN/StringPrep.h> - -extern "C" -{ - #include <stringprep.h> -}; - -#include <vector> -#include <cassert> -#include <Swiften/Base/SafeAllocator.h> - -using namespace Swift; - - namespace { - static const int MAX_STRINGPREP_SIZE = 1024; - - const Stringprep_profile* getLibIDNProfile(StringPrep::Profile profile) { - switch(profile) { - case StringPrep::NamePrep: return stringprep_nameprep; break; - case StringPrep::XMPPNodePrep: return stringprep_xmpp_nodeprep; break; - case StringPrep::XMPPResourcePrep: return stringprep_xmpp_resourceprep; break; - case StringPrep::SASLPrep: return stringprep_saslprep; break; - } - assert(false); - return 0; - } - - template<typename StringType, typename ContainerType> - ContainerType getStringPrepared(const StringType& s, StringPrep::Profile profile) { - ContainerType input(s.begin(), s.end()); - input.resize(MAX_STRINGPREP_SIZE); - if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) { - return input; - } - else { - return ContainerType(); - } - } -} - -namespace Swift { - -std::string StringPrep::getPrepared(const std::string& s, Profile profile) { - std::vector<char> preparedData = getStringPrepared< std::string, std::vector<char> >(s, profile); - if (preparedData.empty()) { - throw std::exception(); - } - return std::string(vecptr(preparedData)); -} - -SafeByteArray StringPrep::getPrepared(const SafeByteArray& s, Profile profile) { - std::vector<char, SafeAllocator<char> > preparedData = getStringPrepared<SafeByteArray, std::vector<char, SafeAllocator<char> > >(s, profile); - if (preparedData.empty()) { - throw std::exception(); - } - return createSafeByteArray(reinterpret_cast<const char*>(vecptr(preparedData))); -} - -} diff --git a/Swiften/IDN/StringPrep.h b/Swiften/IDN/StringPrep.h deleted file mode 100644 index dc8fadc..0000000 --- a/Swiften/IDN/StringPrep.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 <string> -#include <Swiften/Base/SafeByteArray.h> - -namespace Swift { - class StringPrep { - public: - enum Profile { - NamePrep, - XMPPNodePrep, - XMPPResourcePrep, - SASLPrep, - }; - - static std::string getPrepared(const std::string& s, Profile profile); - static SafeByteArray getPrepared(const SafeByteArray& s, Profile profile); - }; -} diff --git a/Swiften/IDN/UnitTest/IDNConverterTest.cpp b/Swiften/IDN/UnitTest/IDNConverterTest.cpp new file mode 100644 index 0000000..a66e141 --- /dev/null +++ b/Swiften/IDN/UnitTest/IDNConverterTest.cpp @@ -0,0 +1,63 @@ +/* + * 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 <boost/shared_ptr.hpp> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/IDN/PlatformIDNConverter.h> + +using namespace Swift; + +class IDNConverterTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(IDNConverterTest); + CPPUNIT_TEST(testStringPrep); + CPPUNIT_TEST(testStringPrep_Empty); + CPPUNIT_TEST(testGetEncoded); + CPPUNIT_TEST(testGetEncoded_International); + CPPUNIT_TEST(testGetEncoded_Invalid); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + testling = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); + } + + void testStringPrep() { + std::string result = testling->getStringPrepared("tron\xc3\x87on", IDNConverter::NamePrep); + + CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), result); + } + + void testStringPrep_Empty() { + CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::NamePrep)); + CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::XMPPNodePrep)); + CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::XMPPResourcePrep)); + } + + void testGetEncoded() { + boost::optional<std::string> result = testling->getIDNAEncoded("www.swift.im"); + CPPUNIT_ASSERT(!!result); + CPPUNIT_ASSERT_EQUAL(std::string("www.swift.im"), *result); + } + + void testGetEncoded_International() { + boost::optional<std::string> result = testling->getIDNAEncoded("www.tron\xc3\x87on.com"); + CPPUNIT_ASSERT(!!result); + CPPUNIT_ASSERT_EQUAL(std::string("www.xn--tronon-zua.com"), *result); + } + + void testGetEncoded_Invalid() { + boost::optional<std::string> result = testling->getIDNAEncoded("www.foo,bar.com"); + CPPUNIT_ASSERT(!result); + } + + private: + boost::shared_ptr<IDNConverter> testling; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(IDNConverterTest); diff --git a/Swiften/IDN/UnitTest/StringPrepTest.cpp b/Swiften/IDN/UnitTest/StringPrepTest.cpp deleted file mode 100644 index beab01e..0000000 --- a/Swiften/IDN/UnitTest/StringPrepTest.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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/IDN/StringPrep.h" - -using namespace Swift; - -class StringPrepTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(StringPrepTest); - CPPUNIT_TEST(testStringPrep); - CPPUNIT_TEST(testStringPrep_Empty); - CPPUNIT_TEST_SUITE_END(); - - public: - void testStringPrep() { - std::string result = StringPrep::getPrepared("tron\xc3\x87on", StringPrep::NamePrep); - - CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), result); - } - - void testStringPrep_Empty() { - CPPUNIT_ASSERT_EQUAL(std::string(""), StringPrep::getPrepared("", StringPrep::NamePrep)); - CPPUNIT_ASSERT_EQUAL(std::string(""), StringPrep::getPrepared("", StringPrep::XMPPNodePrep)); - CPPUNIT_ASSERT_EQUAL(std::string(""), StringPrep::getPrepared("", StringPrep::XMPPResourcePrep)); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(StringPrepTest); diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index 9b47ef7..fcd49f9 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,10 +19,15 @@ #include <boost/algorithm/string/find_format.hpp> #include <boost/algorithm/string/finder.hpp> +#include <boost/optional.hpp> +#include <iostream> #include <sstream> -#include <stringprep.h> #include <Swiften/Base/String.h> #include <Swiften/JID/JID.h> -#include <Swiften/IDN/StringPrep.h> +#include <Swiften/IDN/IDNConverter.h> +#ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER +#include <boost/shared_ptr.hpp> +#include <Swiften/IDN/PlatformIDNConverter.h> +#endif using namespace Swift; @@ -39,4 +44,17 @@ static PrepCache resourcePrepCache; static const std::list<char> escapedChars = boost::assign::list_of(' ')('"')('&')('\'')('/')('<')('>')('@')(':'); +static IDNConverter* idnConverter = NULL; + +#ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER +namespace { + struct IDNInitializer { + IDNInitializer() : defaultIDNConverter(PlatformIDNConverter::create()) { + idnConverter = defaultIDNConverter.get(); + } + boost::shared_ptr<IDNConverter> defaultIDNConverter; + } initializer; +} +#endif + static std::string getEscaped(char c) { return makeString() << '\\' << std::hex << static_cast<int>(c); @@ -113,5 +131,8 @@ struct EscapedCharacterFormatter { #endif +namespace Swift { + JID::JID(const char* jid) : valid_(true) { + assert(jid); initializeFromString(std::string(jid)); } @@ -157,13 +178,12 @@ void JID::initializeFromString(const std::string& jid) { void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { - if (domain.empty()) { + if (domain.empty() || !idnConverter->getIDNAEncoded(domain)) { valid_ = false; return; } - try { #ifndef SWIFTEN_CACHE_JID_PREP - node_ = StringPrep::getPrepared(node, StringPrep::NamePrep); - domain_ = StringPrep::getPrepared(domain, StringPrep::XMPPNodePrep); - resource_ = StringPrep::getPrepared(resource, StringPrep::XMPPResourcePrep); + node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); + domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); + resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); #else boost::mutex::scoped_lock lock(namePrepCacheMutex); @@ -173,5 +193,12 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d r = nodePrepCache.insert(std::make_pair(node, std::string())); if (r.second) { - r.first->second = StringPrep::getPrepared(node, StringPrep::NamePrep); + try { + r.first->second = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); + } + catch (...) { + nodePrepCache.erase(r.first); + valid_ = false; + return; + } } node_ = r.first->second; @@ -179,5 +206,12 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d r = domainPrepCache.insert(std::make_pair(domain, std::string())); if (r.second) { - r.first->second = StringPrep::getPrepared(domain, StringPrep::XMPPNodePrep); + try { + r.first->second = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); + } + catch (...) { + domainPrepCache.erase(r.first); + valid_ = false; + return; + } } domain_ = r.first->second; @@ -185,5 +219,12 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d r = resourcePrepCache.insert(std::make_pair(resource, std::string())); if (r.second) { - r.first->second = StringPrep::getPrepared(resource, StringPrep::XMPPResourcePrep); + try { + r.first->second = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); + } + catch (...) { + resourcePrepCache.erase(r.first); + valid_ = false; + return; + } } resource_ = r.first->second; @@ -195,8 +236,4 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d } } - catch (const std::exception&) { - valid_ = false; - } -} std::string JID::toString() const { @@ -272,2 +309,18 @@ std::string JID::getUnescapedNode() const { //return boost::find_format_all_copy(node_, EscapedCharacterFinder(), EscapedCharacterFormatter()); } + +void JID::setIDNConverter(IDNConverter* converter) { + idnConverter = converter; +} + +std::ostream& operator<<(std::ostream& os, const JID& j) { + os << j.toString(); + return os; +} + +boost::optional<JID> JID::parse(const std::string& s) { + JID jid(s); + return jid.isValid() ? jid : boost::optional<JID>(); +} + +} diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h index a4461ba..aefd3df 100644 --- a/Swiften/JID/JID.h +++ b/Swiften/JID/JID.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,8 +8,12 @@ #include <string> -//#include <iosfwd> -#include <iostream> +#include <iosfwd> + +#include <Swiften/Base/API.h> +#include <boost/optional/optional_fwd.hpp> namespace Swift { + class IDNConverter; + /** * This represents the JID used in XMPP @@ -23,5 +27,5 @@ namespace Swift { * guaranteed to work correctly if they do. */ - class JID { + class SWIFTEN_API JID { public: enum CompareType { @@ -44,4 +48,6 @@ namespace Swift { /** * See std::string constructor. + * + * Must not be NULL. */ JID(const char*); @@ -129,4 +135,12 @@ namespace Swift { } + /** + * Get the full JID with the supplied resource. + */ + JID withResource(const std::string& resource) const { + JID result(this->getNode(), this->getDomain(), resource); + return result; + } + std::string toString() const; @@ -145,8 +159,5 @@ namespace Swift { } - friend std::ostream& operator<<(std::ostream& os, const Swift::JID& j) { - os << j.toString(); - return os; - } + SWIFTEN_API friend std::ostream& operator<<(std::ostream& os, const Swift::JID& j); friend bool operator==(const Swift::JID& a, const Swift::JID& b) { @@ -158,4 +169,17 @@ namespace Swift { } + /** + * Returns an empty optional if the JID is invalid, and an + * optional with a value if the JID is valid. + */ + static boost::optional<JID> parse(const std::string&); + + /** + * If Swiften was compiled with SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER (not default), use this method at + * the beginning of the program to set an IDN converter to use for JID IDN conversions. + * By default, this method shouldn't be used. + */ + static void setIDNConverter(IDNConverter*); + private: void nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource); @@ -169,3 +193,6 @@ namespace Swift { std::string resource_; }; + + SWIFTEN_API std::ostream& operator<<(std::ostream& os, const Swift::JID& j); } + diff --git a/Swiften/JID/SConscript b/Swiften/JID/SConscript index d347cd9..12565fc 100644 --- a/Swiften/JID/SConscript +++ b/Swiften/JID/SConscript @@ -2,6 +2,4 @@ Import("swiften_env") myenv = swiften_env.Clone() -myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) - objects = myenv.SwiftenObject([ "JID.cpp", diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp index 81d24ea..03203de 100644 --- a/Swiften/JID/UnitTest/JIDTest.cpp +++ b/Swiften/JID/UnitTest/JIDTest.cpp @@ -20,4 +20,5 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testConstructorWithString_EmptyResource); CPPUNIT_TEST(testConstructorWithString_OnlyDomain); + CPPUNIT_TEST(testConstructorWithString_InvalidDomain); CPPUNIT_TEST(testConstructorWithString_UpperCaseNode); CPPUNIT_TEST(testConstructorWithString_UpperCaseDomain); @@ -25,4 +26,5 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testConstructorWithString_EmptyNode); CPPUNIT_TEST(testConstructorWithString_IllegalResource); + CPPUNIT_TEST(testConstructorWithString_SpacesInNode); CPPUNIT_TEST(testConstructorWithStrings); CPPUNIT_TEST(testConstructorWithStrings_EmptyDomain); @@ -107,4 +109,8 @@ class JIDTest : public CppUnit::TestFixture } + void testConstructorWithString_InvalidDomain() { + CPPUNIT_ASSERT(!JID("foo@bar,baz").isValid()); + } + void testConstructorWithString_UpperCaseNode() { JID testling("Fo\xCE\xA9@bar"); @@ -138,4 +144,9 @@ class JIDTest : public CppUnit::TestFixture } + void testConstructorWithString_SpacesInNode() { + CPPUNIT_ASSERT(!JID(" alice@wonderland.lit").isValid()); + CPPUNIT_ASSERT(!JID("alice @wonderland.lit").isValid()); + } + void testConstructorWithStrings() { JID testling("foo", "bar", "baz"); diff --git a/Swiften/Jingle/AbstractJingleSessionListener.cpp b/Swiften/Jingle/AbstractJingleSessionListener.cpp new file mode 100644 index 0000000..eaa1a47 --- /dev/null +++ b/Swiften/Jingle/AbstractJingleSessionListener.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Jingle/AbstractJingleSessionListener.h> + +#include <Swiften/Base/Log.h> + +using namespace Swift; + +void AbstractJingleSessionListener::handleSessionAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleDescription>, boost::shared_ptr<JingleTransportPayload>) { + SWIFT_LOG(warning) << "Unimplemented" << std::endl; +} + +void AbstractJingleSessionListener::handleSessionInfoReceived(boost::shared_ptr<JinglePayload>) { + SWIFT_LOG(warning) << "Unimplemented" << std::endl; +} + +void AbstractJingleSessionListener::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason>) { + SWIFT_LOG(warning) << "Unimplemented" << std::endl; +} + +void AbstractJingleSessionListener::handleTransportAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) { + SWIFT_LOG(warning) << "Unimplemented" << std::endl; +} + +void AbstractJingleSessionListener::handleTransportInfoReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) { + SWIFT_LOG(warning) << "Unimplemented" << std::endl; +} + +void AbstractJingleSessionListener::handleTransportRejectReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) { + SWIFT_LOG(warning) << "Unimplemented" << std::endl; +} + +void AbstractJingleSessionListener::handleTransportReplaceReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) { + SWIFT_LOG(warning) << "Unimplemented" << std::endl; +} + +void AbstractJingleSessionListener::handleTransportInfoAcknowledged(const std::string&) { +} diff --git a/Swiften/Jingle/AbstractJingleSessionListener.h b/Swiften/Jingle/AbstractJingleSessionListener.h new file mode 100644 index 0000000..4f76675 --- /dev/null +++ b/Swiften/Jingle/AbstractJingleSessionListener.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> +#include <Swiften/Jingle/JingleSessionListener.h> + +namespace Swift { + class SWIFTEN_API AbstractJingleSessionListener : public JingleSessionListener { + public: + virtual void handleSessionAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleDescription>, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + virtual void handleSessionInfoReceived(boost::shared_ptr<JinglePayload>) SWIFTEN_OVERRIDE; + virtual void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason>) SWIFTEN_OVERRIDE; + virtual void handleTransportAcceptReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + virtual void handleTransportInfoReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + virtual void handleTransportRejectReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + virtual void handleTransportReplaceReceived(const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) SWIFTEN_OVERRIDE; + virtual void handleTransportInfoAcknowledged(const std::string& id) SWIFTEN_OVERRIDE; + }; +} + diff --git a/Swiften/Jingle/FakeJingleSession.cpp b/Swiften/Jingle/FakeJingleSession.cpp index 82ec631..1df106a 100644 --- a/Swiften/Jingle/FakeJingleSession.cpp +++ b/Swiften/Jingle/FakeJingleSession.cpp @@ -34,6 +34,7 @@ void FakeJingleSession::sendAccept(const JingleContentID& id, JingleDescription: } -void FakeJingleSession::sendTransportInfo(const JingleContentID& id, JingleTransportPayload::ref payload) { +std::string FakeJingleSession::sendTransportInfo(const JingleContentID& id, JingleTransportPayload::ref payload) { calledCommands.push_back(InfoTransportCall(id, payload)); + return idGenerator.generateID(); } diff --git a/Swiften/Jingle/FakeJingleSession.h b/Swiften/Jingle/FakeJingleSession.h index fd3d7b7..651ac5f 100644 --- a/Swiften/Jingle/FakeJingleSession.h +++ b/Swiften/Jingle/FakeJingleSession.h @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #pragma once @@ -12,5 +18,8 @@ #include <boost/variant.hpp> +#include <Swiften/Base/API.h> +#include <Swiften/Base/SimpleIDGenerator.h> #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/Override.h> #include <Swiften/JID/JID.h> #include <Swiften/Elements/JinglePayload.h> @@ -21,5 +30,5 @@ namespace Swift { class JingleContentID; - class FakeJingleSession : public JingleSession { + class SWIFTEN_API FakeJingleSession : public JingleSession { public: struct InitiateCall { @@ -79,15 +88,16 @@ namespace Swift { virtual ~FakeJingleSession(); - virtual void sendInitiate(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); - virtual void sendTerminate(JinglePayload::Reason::Type reason); - virtual void sendInfo(boost::shared_ptr<Payload>); - virtual void sendAccept(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref = JingleTransportPayload::ref()); - virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref); - virtual void sendTransportAccept(const JingleContentID&, JingleTransportPayload::ref); - virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref); - virtual void sendTransportReplace(const JingleContentID&, JingleTransportPayload::ref); + virtual void sendInitiate(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref) SWIFTEN_OVERRIDE; + virtual void sendTerminate(JinglePayload::Reason::Type reason) SWIFTEN_OVERRIDE; + virtual void sendInfo(boost::shared_ptr<Payload>) SWIFTEN_OVERRIDE; + virtual void sendAccept(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref = JingleTransportPayload::ref()) SWIFTEN_OVERRIDE; + virtual std::string sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) SWIFTEN_OVERRIDE; + virtual void sendTransportAccept(const JingleContentID&, JingleTransportPayload::ref) SWIFTEN_OVERRIDE; + virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref) SWIFTEN_OVERRIDE; + virtual void sendTransportReplace(const JingleContentID&, JingleTransportPayload::ref) SWIFTEN_OVERRIDE; public: std::vector<Command> calledCommands; + SimpleIDGenerator idGenerator; }; } diff --git a/Swiften/Jingle/JingleResponder.cpp b/Swiften/Jingle/JingleResponder.cpp index 4c82f51..e963ef6 100644 --- a/Swiften/Jingle/JingleResponder.cpp +++ b/Swiften/Jingle/JingleResponder.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -52,5 +52,5 @@ bool JingleResponder::handleSetRequest(const JID& from, const JID& to, const std } else { - std::cerr << "WARN: Didn't find jingle session!" << std::endl; + SWIFT_LOG(warning) << "Didn't find jingle session!"; // TODO: Add jingle-specific error sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel); diff --git a/Swiften/Jingle/JingleSession.cpp b/Swiften/Jingle/JingleSession.cpp index eb649f3..7e09014 100644 --- a/Swiften/Jingle/JingleSession.cpp +++ b/Swiften/Jingle/JingleSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,6 +8,10 @@ #include <boost/smart_ptr/make_shared.hpp> +#include <algorithm> +#include <boost/function.hpp> -namespace Swift { +#include <Swiften/Base/foreach.h> + +using namespace Swift; JingleSession::JingleSession(const JID& initiator, const std::string& id) : initiator(initiator), id(id) { @@ -19,4 +23,2 @@ JingleSession::JingleSession(const JID& initiator, const std::string& id) : init JingleSession::~JingleSession() { } - -} diff --git a/Swiften/Jingle/JingleSession.h b/Swiften/Jingle/JingleSession.h index 150ad79..8307311 100644 --- a/Swiften/Jingle/JingleSession.h +++ b/Swiften/Jingle/JingleSession.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,9 +7,10 @@ #pragma once +#include <string> +#include <vector> #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> -#include <string> - +#include <Swiften/Base/Listenable.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/JID/JID.h> @@ -17,7 +18,8 @@ namespace Swift { + class JingleSessionListener; class JingleContentID; - class JingleSession { + class JingleSession : public Listenable<JingleSessionListener> { public: typedef boost::shared_ptr<JingleSession> ref; @@ -33,25 +35,18 @@ namespace Swift { return id; } + virtual void sendInitiate(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref) = 0; virtual void sendTerminate(JinglePayload::Reason::Type reason) = 0; virtual void sendInfo(boost::shared_ptr<Payload>) = 0; virtual void sendAccept(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref = JingleTransportPayload::ref()) = 0; - virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) = 0; + virtual std::string sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) = 0; virtual void sendTransportAccept(const JingleContentID&, JingleTransportPayload::ref) = 0; virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref) = 0; virtual void sendTransportReplace(const JingleContentID&, JingleTransportPayload::ref) = 0; - public: - boost::signal<void (const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref)> onSessionAcceptReceived; - boost::signal<void (JinglePayload::ref)> onSessionInfoReceived; - boost::signal<void (boost::optional<JinglePayload::Reason>)> onSessionTerminateReceived; - boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportAcceptReceived; - boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportInfoReceived; - boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportRejectReceived; - boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportReplaceReceived; - private: JID initiator; std::string id; + std::vector<JingleSessionListener*> listeners; }; } diff --git a/Swiften/Jingle/JingleSessionImpl.cpp b/Swiften/Jingle/JingleSessionImpl.cpp index 98c5196..ff22d11 100644 --- a/Swiften/Jingle/JingleSessionImpl.cpp +++ b/Swiften/Jingle/JingleSessionImpl.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,7 +8,10 @@ #include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> +#include <algorithm> #include <Swiften/Parser/PayloadParsers/JingleParser.h> #include <Swiften/Jingle/JingleContentID.h> +#include <Swiften/Jingle/JingleSessionListener.h> #include <Swiften/Elements/JingleContentPayload.h> #include <Swiften/Queries/Request.h> @@ -17,6 +20,5 @@ #include <Swiften/Base/Log.h> -#include "Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h" -#include "Swiften/FileTransfer/JingleTransport.h" +#include <Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h> namespace Swift { @@ -28,9 +30,9 @@ JingleSessionImpl::JingleSessionImpl(const JID& initiator, const JID& peerJID, c void JingleSessionImpl::handleIncomingAction(JinglePayload::ref action) { if (action->getAction() == JinglePayload::SessionTerminate) { - onSessionTerminateReceived(action->getReason()); + notifyListeners(&JingleSessionListener::handleSessionTerminateReceived, action->getReason()); return; } if (action->getAction() == JinglePayload::SessionInfo) { - onSessionInfoReceived(action); + notifyListeners(&JingleSessionListener::handleSessionInfoReceived, action); return; } @@ -46,17 +48,17 @@ void JingleSessionImpl::handleIncomingAction(JinglePayload::ref action) { switch(action->getAction()) { case JinglePayload::SessionAccept: - onSessionAcceptReceived(contentID, description, transport); + notifyListeners(&JingleSessionListener::handleSessionAcceptReceived, contentID, description, transport); return; case JinglePayload::TransportAccept: - onTransportAcceptReceived(contentID, transport); + notifyListeners(&JingleSessionListener::handleTransportAcceptReceived, contentID, transport); return; case JinglePayload::TransportInfo: - onTransportInfoReceived(contentID, transport); + notifyListeners(&JingleSessionListener::handleTransportInfoReceived, contentID, transport); return; case JinglePayload::TransportReject: - onTransportRejectReceived(contentID, transport); + notifyListeners(&JingleSessionListener::handleTransportRejectReceived, contentID, transport); return; case JinglePayload::TransportReplace: - onTransportReplaceReceived(contentID, transport); + notifyListeners(&JingleSessionListener::handleTransportReplaceReceived, contentID, transport); return; // following unused Jingle actions @@ -77,5 +79,5 @@ void JingleSessionImpl::handleIncomingAction(JinglePayload::ref action) { return; } - std::cerr << "Unhandled Jingle action!!! ACTION: " << action->getAction() << std::endl; + assert(false); } @@ -137,5 +139,5 @@ void JingleSessionImpl::sendTransportAccept(const JingleContentID& id, JingleTra } -void JingleSessionImpl::sendTransportInfo(const JingleContentID& id, JingleTransportPayload::ref transPayload) { +std::string JingleSessionImpl::sendTransportInfo(const JingleContentID& id, JingleTransportPayload::ref transPayload) { JinglePayload::ref payload = createPayload(); @@ -147,5 +149,5 @@ void JingleSessionImpl::sendTransportInfo(const JingleContentID& id, JingleTrans payload->addPayload(content); - sendSetRequest(payload); + return sendSetRequest(payload); } @@ -168,7 +170,11 @@ void JingleSessionImpl::sendTransportReplace(const JingleContentID& id, JingleTr -void JingleSessionImpl::sendSetRequest(JinglePayload::ref payload) { - boost::shared_ptr<GenericRequest<JinglePayload> > request = boost::make_shared<GenericRequest<JinglePayload> >(IQ::Set, peerJID, payload, iqRouter); - request->send(); +std::string JingleSessionImpl::sendSetRequest(JinglePayload::ref payload) { + boost::shared_ptr<GenericRequest<JinglePayload> > request = boost::make_shared<GenericRequest<JinglePayload> >( + IQ::Set, peerJID, payload, iqRouter); + pendingRequests.insert(std::make_pair( + request, + request->onResponse.connect(boost::bind(&JingleSessionImpl::handleRequestResponse, this, request)))); + return request->send(); } @@ -181,4 +187,13 @@ JinglePayload::ref JingleSessionImpl::createPayload() const { } +void JingleSessionImpl::handleRequestResponse(RequestRef request) { + RequestsMap::iterator i = pendingRequests.find(request); + assert(i != pendingRequests.end()); + if (i->first->getPayloadGeneric()->getAction() == JinglePayload::TransportInfo) { + notifyListeners(&JingleSessionListener::handleTransportInfoAcknowledged, i->first->getID()); + } + i->second.disconnect(); + pendingRequests.erase(i); +} diff --git a/Swiften/Jingle/JingleSessionImpl.h b/Swiften/Jingle/JingleSessionImpl.h index 3c1559a..b7f4a55 100644 --- a/Swiften/Jingle/JingleSessionImpl.h +++ b/Swiften/Jingle/JingleSessionImpl.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,9 +8,12 @@ #include <boost/shared_ptr.hpp> +#include <map> #include <Swiften/Jingle/JingleSession.h> +#include <Swiften/Queries/GenericRequest.h> namespace Swift { class IQRouter; + class Request; class JingleSessionImpl : public JingleSession { @@ -25,5 +28,5 @@ namespace Swift { virtual void sendInfo(boost::shared_ptr<Payload>); virtual void sendAccept(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); - virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref); + virtual std::string sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref); virtual void sendTransportAccept(const JingleContentID&, JingleTransportPayload::ref); virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref); @@ -31,12 +34,17 @@ namespace Swift { private: + typedef boost::shared_ptr<GenericRequest<JinglePayload> > RequestRef; + void handleIncomingAction(JinglePayload::ref); - void sendSetRequest(JinglePayload::ref payload); + std::string sendSetRequest(JinglePayload::ref payload); JinglePayload::ref createPayload() const; + void handleRequestResponse(RequestRef); private: IQRouter *iqRouter; JID peerJID; + typedef std::map<RequestRef, boost::bsignals::connection > RequestsMap; + RequestsMap pendingRequests; }; } diff --git a/Swiften/Jingle/JingleSessionListener.cpp b/Swiften/Jingle/JingleSessionListener.cpp new file mode 100644 index 0000000..75d3be9 --- /dev/null +++ b/Swiften/Jingle/JingleSessionListener.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Jingle/JingleSessionListener.h> + +using namespace Swift; + +JingleSessionListener::~JingleSessionListener() { +} diff --git a/Swiften/Jingle/JingleSessionListener.h b/Swiften/Jingle/JingleSessionListener.h new file mode 100644 index 0000000..e1270c4 --- /dev/null +++ b/Swiften/Jingle/JingleSessionListener.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/JinglePayload.h> + +namespace Swift { + class JingleContentID; + class JingleTransportPayload; + class JingleDescription; + + class SWIFTEN_API JingleSessionListener { + public: + virtual ~JingleSessionListener(); + + virtual void handleSessionAcceptReceived( + const JingleContentID&, + boost::shared_ptr<JingleDescription>, + boost::shared_ptr<JingleTransportPayload>) = 0; + virtual void handleSessionInfoReceived(boost::shared_ptr<JinglePayload>) = 0; + virtual void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason>) = 0; + virtual void handleTransportAcceptReceived( + const JingleContentID&, + boost::shared_ptr<JingleTransportPayload>) = 0; + virtual void handleTransportInfoReceived( + const JingleContentID&, + boost::shared_ptr<JingleTransportPayload>) = 0; + virtual void handleTransportRejectReceived( + const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) = 0; + virtual void handleTransportReplaceReceived( + const JingleContentID&, boost::shared_ptr<JingleTransportPayload>) = 0; + + virtual void handleTransportInfoAcknowledged(const std::string& id) = 0; + }; +} diff --git a/Swiften/Jingle/JingleSessionManager.cpp b/Swiften/Jingle/JingleSessionManager.cpp index 2e15fcd..f31ddb8 100644 --- a/Swiften/Jingle/JingleSessionManager.cpp +++ b/Swiften/Jingle/JingleSessionManager.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <Swiften/Jingle/JingleResponder.h> #include <Swiften/Jingle/IncomingJingleSessionHandler.h> +#include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> #include <Swiften/Base/Algorithm.h> diff --git a/Swiften/Jingle/JingleSessionManager.h b/Swiften/Jingle/JingleSessionManager.h index b4f2846..3412709 100644 --- a/Swiften/Jingle/JingleSessionManager.h +++ b/Swiften/Jingle/JingleSessionManager.h @@ -10,4 +10,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Jingle/JingleSessionImpl.h> @@ -18,5 +19,5 @@ namespace Swift { class IncomingJingleSessionHandler; - class JingleSessionManager { + class SWIFTEN_API JingleSessionManager { friend class JingleResponder; public: diff --git a/Swiften/Jingle/SConscript b/Swiften/Jingle/SConscript index 5dcf293..546c1b2 100644 --- a/Swiften/Jingle/SConscript +++ b/Swiften/Jingle/SConscript @@ -3,4 +3,6 @@ Import("swiften_env") sources = [ "JingleSession.cpp", + "JingleSessionListener.cpp", + "AbstractJingleSessionListener.cpp", "JingleSessionImpl.cpp", "IncomingJingleSessionHandler.cpp", diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h index 6e79290..52d6654 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,5 @@ #include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> #include <Swiften/EventLoop/EventLoop.h> +#include <boost/numeric/conversion/cast.hpp> namespace Swift { @@ -49,5 +50,5 @@ namespace Swift { else { //std::cout << "Discovered service: name:" << name << " domain:" << domain << " type: " << type << std::endl; - DNSSDServiceID service(name, domain, type, interfaceIndex); + DNSSDServiceID service(name, domain, type, boost::numeric_cast<int>(interfaceIndex)); if (flags & kDNSServiceFlagsAdd) { eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h index d3c9488..45628e2 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,8 +7,11 @@ #pragma once -#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h> -#include <Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h> +#include <boost/numeric/conversion/cast.hpp> +#include <boost/thread.hpp> + #include <Swiften/Base/ByteArray.h> #include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h> namespace Swift { @@ -19,6 +22,6 @@ namespace Swift { BonjourRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, boost::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { DNSServiceErrorType result = DNSServiceRegister( - &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port, - txtRecord.size(), vecptr(txtRecord), + &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, boost::numeric_cast<unsigned short>(port), + boost::numeric_cast<unsigned short>(txtRecord.size()), vecptr(txtRecord), &BonjourRegisterQuery::handleServiceRegisteredStatic, this); if (result != kDNSServiceErr_NoError) { @@ -42,5 +45,5 @@ namespace Swift { void updateServiceInfo(const ByteArray& txtRecord) { boost::lock_guard<boost::mutex> lock(sdRefMutex); - DNSServiceUpdateRecord(sdRef, NULL, 0, txtRecord.size(), vecptr(txtRecord), 0); + DNSServiceUpdateRecord(sdRef, NULL, 0, boost::numeric_cast<unsigned short>(txtRecord.size()), vecptr(txtRecord), 0); } diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h index 9fdd3d5..59d1af5 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,4 +14,5 @@ #include <Swiften/EventLoop/EventLoop.h> #include <Swiften/Network/HostAddress.h> +#include <boost/numeric/conversion/cast.hpp> #include <netinet/in.h> @@ -24,5 +25,5 @@ namespace Swift { BonjourResolveHostnameQuery(const std::string& hostname, int interfaceIndex, boost::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { DNSServiceErrorType result = DNSServiceGetAddrInfo( - &sdRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4, + &sdRef, 0, boost::numeric_cast<unsigned int>(interfaceIndex), kDNSServiceProtocol_IPv4, hostname.c_str(), &BonjourResolveHostnameQuery::handleHostnameResolvedStatic, this); diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h index 1fb050c..2eeac64 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -20,5 +20,5 @@ namespace Swift { BonjourResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { DNSServiceErrorType result = DNSServiceResolve( - &sdRef, 0, service.getNetworkInterfaceID(), + &sdRef, 0, boost::numeric_cast<unsigned int>(service.getNetworkInterfaceID()), service.getName().c_str(), service.getType().c_str(), service.getDomain().c_str(), diff --git a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h index 9ce0781..6c36de0 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h @@ -7,8 +7,9 @@ #pragma once +#include <Swiften/Base/API.h> #include <string> namespace Swift { - class DNSSDServiceID { + class SWIFTEN_API DNSSDServiceID { public: static const char* PresenceServiceType; diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h index f5166ee..9fc4608 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h @@ -13,4 +13,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> #include <Swiften/EventLoop/EventOwner.h> @@ -24,5 +25,5 @@ namespace Swift { class EventLoop; - class FakeDNSSDQuerier : + class SWIFTEN_API FakeDNSSDQuerier : public DNSSDQuerier, public EventOwner, diff --git a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h index ca5570f..2eb21ed 100644 --- a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h +++ b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h @@ -9,9 +9,11 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> + namespace Swift { class DNSSDQuerier; class EventLoop; - class PlatformDNSSDQuerierFactory { + class SWIFTEN_API PlatformDNSSDQuerierFactory { public: PlatformDNSSDQuerierFactory(EventLoop* eventLoop); diff --git a/Swiften/LinkLocal/IncomingLinkLocalSession.cpp b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp index 610b28b..63f3ca1 100644 --- a/Swiften/LinkLocal/IncomingLinkLocalSession.cpp +++ b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -50,5 +50,5 @@ void IncomingLinkLocalSession::handleStreamStart(const ProtocolHeader& incomingH } -void IncomingLinkLocalSession::handleElement(boost::shared_ptr<Element> element) { +void IncomingLinkLocalSession::handleElement(boost::shared_ptr<ToplevelElement> element) { boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element); // If we get our first stanza before streamfeatures, our session is implicitly diff --git a/Swiften/LinkLocal/IncomingLinkLocalSession.h b/Swiften/LinkLocal/IncomingLinkLocalSession.h index f00c166..e10cd0a 100644 --- a/Swiften/LinkLocal/IncomingLinkLocalSession.h +++ b/Swiften/LinkLocal/IncomingLinkLocalSession.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ namespace Swift { class ProtocolHeader; class XMLParserFactory; - class Element; + class ToplevelElement; class PayloadParserFactoryCollection; class PayloadSerializerCollection; @@ -33,5 +33,5 @@ namespace Swift { private: - void handleElement(boost::shared_ptr<Element>); + void handleElement(boost::shared_ptr<ToplevelElement>); void handleStreamStart(const ProtocolHeader&); void setInitialized(); diff --git a/Swiften/LinkLocal/LinkLocalConnector.cpp b/Swiften/LinkLocal/LinkLocalConnector.cpp index af96e65..6471ca7 100644 --- a/Swiften/LinkLocal/LinkLocalConnector.cpp +++ b/Swiften/LinkLocal/LinkLocalConnector.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -72,5 +72,5 @@ void LinkLocalConnector::handleConnected(bool error) { } -void LinkLocalConnector::queueElement(boost::shared_ptr<Element> element) { +void LinkLocalConnector::queueElement(boost::shared_ptr<ToplevelElement> element) { queuedElements.push_back(element); } diff --git a/Swiften/LinkLocal/LinkLocalConnector.h b/Swiften/LinkLocal/LinkLocalConnector.h index 0acdc51..367e972 100644 --- a/Swiften/LinkLocal/LinkLocalConnector.h +++ b/Swiften/LinkLocal/LinkLocalConnector.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,4 +12,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/LinkLocal/LinkLocalService.h> @@ -18,5 +19,5 @@ namespace Swift { class ConnectionFactory; class HostAddress; - class Element; + class ToplevelElement; class PayloadParserFactoryCollection; class PayloadSerializerCollection; @@ -24,5 +25,5 @@ namespace Swift { class DNSSDResolveHostnameQuery; - class LinkLocalConnector : public boost::enable_shared_from_this<LinkLocalConnector> { + class SWIFTEN_API LinkLocalConnector : public boost::enable_shared_from_this<LinkLocalConnector> { public: LinkLocalConnector( @@ -38,7 +39,7 @@ namespace Swift { void connect(); void cancel(); - void queueElement(boost::shared_ptr<Element> element); + void queueElement(boost::shared_ptr<ToplevelElement> element); - const std::vector<boost::shared_ptr<Element> >& getQueuedElements() const { + const std::vector<boost::shared_ptr<ToplevelElement> >& getQueuedElements() const { return queuedElements; } @@ -61,5 +62,5 @@ namespace Swift { boost::shared_ptr<Connection> connection; boost::bsignals::connection connectionConnectFinishedConnection; - std::vector<boost::shared_ptr<Element> > queuedElements; + std::vector<boost::shared_ptr<ToplevelElement> > queuedElements; }; } diff --git a/Swiften/LinkLocal/LinkLocalService.h b/Swiften/LinkLocal/LinkLocalService.h index 2b7f7b2..56be9ef 100644 --- a/Swiften/LinkLocal/LinkLocalService.h +++ b/Swiften/LinkLocal/LinkLocalService.h @@ -8,4 +8,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <Swiften/LinkLocal/DNSSD/DNSSDServiceID.h> @@ -14,5 +15,5 @@ namespace Swift { - class LinkLocalService { + class SWIFTEN_API LinkLocalService { public: LinkLocalService( diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp index 4b68a33..ae97933 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -53,5 +53,5 @@ void LinkLocalServiceBrowser::stop() { bool LinkLocalServiceBrowser::isRunning() const { - return browseQuery; + return !!browseQuery; } @@ -61,5 +61,5 @@ bool LinkLocalServiceBrowser::hasError() const { bool LinkLocalServiceBrowser::isRegistered() const { - return registerQuery; + return !!registerQuery; } diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h index 57ed969..f9a12f3 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.h +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h @@ -14,4 +14,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> #include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> @@ -22,5 +23,5 @@ namespace Swift { - class LinkLocalServiceBrowser { + class SWIFTEN_API LinkLocalServiceBrowser { public: LinkLocalServiceBrowser(boost::shared_ptr<DNSSDQuerier> querier); diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp index 516d303..7e18315 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Algorithm.h> @@ -50,5 +51,5 @@ ByteArray LinkLocalServiceInfo::getEncoded(const std::string& s) { ByteArray sizeByte; sizeByte.resize(1); - sizeByte[0] = s.size(); + sizeByte[0] = boost::numeric_cast<unsigned char>(s.size()); return concat(sizeByte, createByteArray(s)); } @@ -110,9 +111,9 @@ std::pair<std::string,std::string> LinkLocalServiceInfo::readEntry(const ByteArr } else { - key += record[i]; + key += static_cast<char>(record[i]); } } else { - value += record[i]; + value += static_cast<char>(record[i]); } ++i; diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.h b/Swiften/LinkLocal/LinkLocalServiceInfo.h index 79a8cb8..ac7b86f 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.h +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.h @@ -9,4 +9,5 @@ #include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> #include <string> @@ -15,5 +16,5 @@ namespace Swift { - class LinkLocalServiceInfo { + class SWIFTEN_API LinkLocalServiceInfo { public: enum Status { Available, Away, DND }; diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp index 7a59715..1d280ef 100644 --- a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp +++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -36,5 +36,5 @@ void OutgoingLinkLocalSession::handleSessionStarted() { void OutgoingLinkLocalSession::handleStreamStart(const ProtocolHeader&) { - foreach(const boost::shared_ptr<Element>& stanza, queuedElements_) { + foreach(const boost::shared_ptr<ToplevelElement>& stanza, queuedElements_) { sendElement(stanza); } @@ -42,9 +42,9 @@ void OutgoingLinkLocalSession::handleStreamStart(const ProtocolHeader&) { } -void OutgoingLinkLocalSession::handleElement(boost::shared_ptr<Element> element) { +void OutgoingLinkLocalSession::handleElement(boost::shared_ptr<ToplevelElement> element) { onElementReceived(element); } -void OutgoingLinkLocalSession::queueElement(boost::shared_ptr<Element> element) { +void OutgoingLinkLocalSession::queueElement(boost::shared_ptr<ToplevelElement> element) { queuedElements_.push_back(element); } diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.h b/Swiften/LinkLocal/OutgoingLinkLocalSession.h index b97f2bf..4550ae4 100644 --- a/Swiften/LinkLocal/OutgoingLinkLocalSession.h +++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,5 +18,5 @@ namespace Swift { class ConnectionFactory; class XMLParserFactory; - class Element; + class ToplevelElement; class PayloadParserFactoryCollection; class PayloadSerializerCollection; @@ -32,13 +32,13 @@ namespace Swift { XMLParserFactory* xmlParserFactory); - void queueElement(boost::shared_ptr<Element> element); + void queueElement(boost::shared_ptr<ToplevelElement> element); private: void handleSessionStarted(); - void handleElement(boost::shared_ptr<Element>); + void handleElement(boost::shared_ptr<ToplevelElement>); void handleStreamStart(const ProtocolHeader&); private: - std::vector<boost::shared_ptr<Element> > queuedElements_; + std::vector<boost::shared_ptr<ToplevelElement> > queuedElements_; }; } diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp index a52f552..c7ba470 100644 --- a/Swiften/MUC/MUC.cpp +++ b/Swiften/MUC/MUC.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,408 +7,8 @@ #include <Swiften/MUC/MUC.h> -#include <boost/bind.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/smart_ptr/make_shared.hpp> - -#include <Swiften/Base/foreach.h> -#include <Swiften/Presence/DirectedPresenceSender.h> -#include <Swiften/Client/StanzaChannel.h> -#include <Swiften/Queries/IQRouter.h> -#include <Swiften/Elements/Form.h> -#include <Swiften/Elements/Message.h> -#include <Swiften/Elements/IQ.h> -#include <Swiften/Elements/MUCUserPayload.h> -#include <Swiften/Elements/MUCAdminPayload.h> -#include <Swiften/Elements/MUCPayload.h> -#include <Swiften/Elements/MUCDestroyPayload.h> -#include <Swiften/Elements/MUCInvitationPayload.h> -#include <Swiften/MUC/MUCRegistry.h> -#include <Swiften/Queries/GenericRequest.h> - namespace Swift { -typedef std::pair<std::string, MUCOccupant> StringMUCOccupantPair; - -MUC::MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry) : ownMUCJID(muc), stanzaChannel(stanzaChannel), iqRouter_(iqRouter), presenceSender(presenceSender), mucRegistry(mucRegistry), createAsReservedIfNew(false), unlocking(false) { - scopedConnection_ = stanzaChannel->onPresenceReceived.connect(boost::bind(&MUC::handleIncomingPresence, this, _1)); -} - -//FIXME: discover reserved nickname - -/** - * Join the MUC with default context. - */ -void MUC::joinAs(const std::string &nick) { - joinSince_ = boost::posix_time::not_a_date_time; - internalJoin(nick); -} - -/** - * Set the password used for entering the room. - */ -void MUC::setPassword(const boost::optional<std::string>& newPassword) { - password = newPassword; -} - -/** - * Join the MUC with context since date. - */ -void MUC::joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) { - joinSince_ = since; - internalJoin(nick); -} - -void MUC::internalJoin(const std::string &nick) { - //TODO: history request - joinComplete_ = false; - joinSucceeded_ = false; - - mucRegistry->addMUC(getJID()); - - ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick); - - Presence::ref joinPresence = boost::make_shared<Presence>(*presenceSender->getLastSentUndirectedPresence()); - assert(joinPresence->getType() == Presence::Available); - joinPresence->setTo(ownMUCJID); - MUCPayload::ref mucPayload = boost::make_shared<MUCPayload>(); - if (joinSince_ != boost::posix_time::not_a_date_time) { - mucPayload->setSince(joinSince_); - } - if (password) { - mucPayload->setPassword(*password); - } - joinPresence->addPayload(mucPayload); - - presenceSender->sendPresence(joinPresence); -} - -void MUC::part() { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - mucRegistry->removeMUC(getJID()); -} - -void MUC::handleUserLeft(LeavingType type) { - std::map<std::string,MUCOccupant>::iterator i = occupants.find(ownMUCJID.getResource()); - if (i != occupants.end()) { - MUCOccupant me = i->second; - occupants.erase(i); - onOccupantLeft(me, type, ""); - } - occupants.clear(); - joinComplete_ = false; - joinSucceeded_ = false; - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); -} - -void MUC::handleIncomingPresence(Presence::ref presence) { - if (!isFromMUC(presence->getFrom())) { - return; - } - - MUCUserPayload::ref mucPayload; - foreach (MUCUserPayload::ref payload, presence->getPayloads<MUCUserPayload>()) { - if (!payload->getItems().empty() || !payload->getStatusCodes().empty()) { - mucPayload = payload; - } - } - - // On the first incoming presence, check if our join has succeeded - // (i.e. we start getting non-error presence from the MUC) or not - if (!joinSucceeded_) { - if (presence->getType() == Presence::Error) { - std::string reason; - onJoinFailed(presence->getPayload<ErrorPayload>()); - return; - } - else { - joinSucceeded_ = true; - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - } - } - - std::string nick = presence->getFrom().getResource(); - if (nick.empty()) { - return; - } - MUCOccupant::Role role(MUCOccupant::NoRole); - MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation); - boost::optional<JID> realJID; - if (mucPayload && mucPayload->getItems().size() > 0) { - role = mucPayload->getItems()[0].role ? mucPayload->getItems()[0].role.get() : MUCOccupant::NoRole; - affiliation = mucPayload->getItems()[0].affiliation ? mucPayload->getItems()[0].affiliation.get() : MUCOccupant::NoAffiliation; - realJID = mucPayload->getItems()[0].realJID; - } - - //100 is non-anonymous - //TODO: 100 may also be specified in a <message/> - //170 is room logging to http - //TODO: Nick changes - if (presence->getType() == Presence::Unavailable) { - LeavingType type = LeavePart; - if (mucPayload) { - if (boost::dynamic_pointer_cast<MUCDestroyPayload>(mucPayload->getPayload())) { - type = LeaveDestroy; - } - else foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { - if (status.code == 307) { - type = LeaveKick; - } - else if (status.code == 301) { - type = LeaveBan; - } - else if (status.code == 321) { - type = LeaveNotMember; - } - } - } - - if (presence->getFrom() == ownMUCJID) { - handleUserLeft(type); - return; - } - else { - std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); - if (i != occupants.end()) { - //TODO: part type - onOccupantLeft(i->second, type, ""); - occupants.erase(i); - } - } - } - else if (presence->getType() == Presence::Available) { - std::map<std::string, MUCOccupant>::iterator it = occupants.find(nick); - MUCOccupant occupant(nick, role, affiliation); - bool isJoin = true; - if (realJID) { - occupant.setRealJID(realJID.get()); - } - if (it != occupants.end()) { - isJoin = false; - MUCOccupant oldOccupant = it->second; - if (oldOccupant.getRole() != role) { - onOccupantRoleChanged(nick, occupant, oldOccupant.getRole()); - } - if (oldOccupant.getAffiliation() != affiliation) { - onOccupantAffiliationChanged(nick, affiliation, oldOccupant.getAffiliation()); - } - occupants.erase(it); - } - std::pair<std::map<std::string, MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, occupant)); - if (isJoin) { - onOccupantJoined(result.first->second); - } - onOccupantPresenceChange(presence); - } - if (mucPayload && !joinComplete_) { - foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { - if (status.code == 110) { - /* Simply knowing this is your presence is enough, 210 doesn't seem to be necessary. */ - joinComplete_ = true; - if (ownMUCJID != presence->getFrom()) { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - ownMUCJID = presence->getFrom(); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - } - onJoinComplete(getOwnNick()); - } - if (status.code == 201) { - /* Room is created and locked */ - /* Currently deal with this by making an instant room */ - if (ownMUCJID != presence->getFrom()) { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - ownMUCJID = presence->getFrom(); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - } - if (createAsReservedIfNew) { - unlocking = true; - requestConfigurationForm(); - } - else { - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - mucPayload->setPayload(boost::make_shared<Form>(Form::SubmitType)); - GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUC::handleCreationConfigResponse, this, _1, _2)); - request->send(); - } +MUC::~MUC() { } - } - } -} - -void MUC::handleCreationConfigResponse(MUCOwnerPayload::ref /*unused*/, ErrorPayload::ref error) { - unlocking = false; - if (error) { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - onJoinFailed(error); - } else { - onJoinComplete(getOwnNick()); /* Previously, this wasn't needed here, as the presence duplication bug caused an emit elsewhere. */ - } -} - -bool MUC::hasOccupant(const std::string& nick) { - return occupants.find(nick) != occupants.end(); -} - -const MUCOccupant& MUC::getOccupant(const std::string& nick) { - return occupants.find(nick)->second; -} - -void MUC::kickOccupant(const JID& jid) { - changeOccupantRole(jid, MUCOccupant::NoRole); -} - -/** - * Call with the room JID, not the real JID. - */ -void MUC::changeOccupantRole(const JID& jid, MUCOccupant::Role role) { - MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); - MUCItem item; - item.role = role; - item.nick = jid.getResource(); - mucPayload->addItem(item); - GenericRequest<MUCAdminPayload>* request = new GenericRequest<MUCAdminPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUC::handleOccupantRoleChangeResponse, this, _1, _2, jid, role)); - request->send(); - -} - -void MUC::handleOccupantRoleChangeResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid, MUCOccupant::Role role) { - if (error) { - onRoleChangeFailed(error, jid, role); - } -} - -void MUC::requestAffiliationList(MUCOccupant::Affiliation affiliation) { - MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); - MUCItem item; - item.affiliation = affiliation; - mucPayload->addItem(item); - GenericRequest<MUCAdminPayload>* request = new GenericRequest<MUCAdminPayload>(IQ::Get, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUC::handleAffiliationListResponse, this, _1, _2, affiliation)); - request->send(); -} - -/** - * Must be called with the real JID, not the room JID. - */ -void MUC::changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation) { - MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); - MUCItem item; - item.affiliation = affiliation; - item.realJID = jid.toBare(); - mucPayload->addItem(item); - GenericRequest<MUCAdminPayload>* request = new GenericRequest<MUCAdminPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUC::handleAffiliationChangeResponse, this, _1, _2, jid, affiliation)); - request->send(); -} - -void MUC::handleAffiliationListResponse(MUCAdminPayload::ref payload, ErrorPayload::ref error, MUCOccupant::Affiliation affiliation) { - if (error) { - onAffiliationListFailed(error); - } - else { - std::vector<JID> jids; - foreach (MUCItem item, payload->getItems()) { - if (item.realJID) { - jids.push_back(*item.realJID); - } - } - onAffiliationListReceived(affiliation, jids); - } -} - -void MUC::handleAffiliationChangeResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid, MUCOccupant::Affiliation affiliation) { - if (error) { - onAffiliationChangeFailed(error, jid, affiliation); - } -} - -void MUC::changeSubject(const std::string& subject) { - Message::ref message = boost::make_shared<Message>(); - message->setSubject(subject); - message->setType(Message::Groupchat); - message->setTo(ownMUCJID.toBare()); - stanzaChannel->sendMessage(message); -} - -void MUC::requestConfigurationForm() { - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Get, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUC::handleConfigurationFormReceived, this, _1, _2)); - request->send(); -} - -void MUC::cancelConfigureRoom() { - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - mucPayload->setPayload(boost::make_shared<Form>(Form::CancelType)); - GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); - request->send(); -} - -void MUC::handleConfigurationFormReceived(MUCOwnerPayload::ref payload, ErrorPayload::ref error) { - Form::ref form; - if (payload) { - form = payload->getForm(); - } - if (error || !form) { - onConfigurationFailed(error); - } else { - onConfigurationFormReceived(form); - } -} - -void MUC::handleConfigurationResultReceived(MUCOwnerPayload::ref /*payload*/, ErrorPayload::ref error) { - if (error) { - onConfigurationFailed(error); - } -} - -void MUC::configureRoom(Form::ref form) { - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - mucPayload->setPayload(form); - GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); - if (unlocking) { - request->onResponse.connect(boost::bind(&MUC::handleCreationConfigResponse, this, _1, _2)); - } - else { - request->onResponse.connect(boost::bind(&MUC::handleConfigurationResultReceived, this, _1, _2)); - } - request->send(); -} - -void MUC::destroyRoom() { - MUCOwnerPayload::ref mucPayload = boost::make_shared<MUCOwnerPayload>(); - MUCDestroyPayload::ref mucDestroyPayload = boost::make_shared<MUCDestroyPayload>(); - mucPayload->setPayload(mucDestroyPayload); - GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUC::handleConfigurationResultReceived, this, _1, _2)); - request->send(); -} - -void MUC::invitePerson(const JID& person, const std::string& reason) { - Message::ref message = boost::make_shared<Message>(); - message->setTo(person); - message->setType(Message::Normal); - MUCInvitationPayload::ref invite = boost::make_shared<MUCInvitationPayload>(); - invite->setReason(reason); - invite->setJID(ownMUCJID.toBare()); - message->addPayload(invite); - stanzaChannel->sendMessage(message); -} - -//TODO: Invites(direct/mediated) - -//TODO: requesting membership - -//TODO: get member list - -//TODO: request voice - -//TODO: moderator use cases - -//TODO: Admin use cases - -//TODO: Owner use cases } diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h index 60ed697..8815489 100644 --- a/Swiften/MUC/MUC.h +++ b/Swiften/MUC/MUC.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <Swiften/JID/JID.h> +#include <Swiften/Base/API.h> #include <string> #include <Swiften/Elements/Message.h> @@ -28,5 +29,5 @@ namespace Swift { class DirectedPresenceSender; - class MUC { + class SWIFTEN_API MUC { public: typedef boost::shared_ptr<MUC> ref; @@ -36,38 +37,44 @@ namespace Swift { public: - MUC(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry); + virtual ~MUC(); /** * Returns the (bare) JID of the MUC. */ - JID getJID() const { - return ownMUCJID.toBare(); - } + virtual JID getJID() const = 0; - void joinAs(const std::string &nick); - void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since); - /*void queryRoomInfo(); */ - /*void queryRoomItems(); */ - std::string getCurrentNick(); - void part(); - void handleIncomingMessage(Message::ref message); + /** + * Returns if the room is unlocked and other people can join the room. + * @return True if joinable by others; false otherwise. + */ + virtual bool isUnlocked() const = 0; + + virtual void joinAs(const std::string &nick) = 0; + virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) = 0; + /*virtual void queryRoomInfo(); */ + /*virtual void queryRoomItems(); */ + /*virtual std::string getCurrentNick() = 0; */ + virtual std::map<std::string, MUCOccupant> getOccupants() const = 0; + virtual void changeNickname(const std::string& newNickname) = 0; + virtual void part() = 0; + /*virtual void handleIncomingMessage(Message::ref message) = 0; */ /** Expose public so it can be called when e.g. user goes offline */ - void handleUserLeft(LeavingType); + virtual void handleUserLeft(LeavingType) = 0; /** Get occupant information*/ - const MUCOccupant& getOccupant(const std::string& nick); - bool hasOccupant(const std::string& nick); - void kickOccupant(const JID& jid); - void changeOccupantRole(const JID& jid, MUCOccupant::Role role); - void requestAffiliationList(MUCOccupant::Affiliation); - void changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation); - void changeSubject(const std::string& subject); - void requestConfigurationForm(); - void configureRoom(Form::ref); - void cancelConfigureRoom(); - void destroyRoom(); + virtual const MUCOccupant& getOccupant(const std::string& nick) = 0; + virtual bool hasOccupant(const std::string& nick) = 0; + virtual void kickOccupant(const JID& jid) = 0; + virtual void changeOccupantRole(const JID& jid, MUCOccupant::Role role) = 0; + virtual void requestAffiliationList(MUCOccupant::Affiliation) = 0; + virtual void changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation) = 0; + virtual void changeSubject(const std::string& subject) = 0; + virtual void requestConfigurationForm() = 0; + virtual void configureRoom(Form::ref) = 0; + virtual void cancelConfigureRoom() = 0; + virtual void destroyRoom() = 0; /** Send an invite for the person to join the MUC */ - void invitePerson(const JID& person, const std::string& reason = ""); - void setCreateAsReservedIfNew() {createAsReservedIfNew = true;} - void setPassword(const boost::optional<std::string>& password); + virtual void invitePerson(const JID& person, const std::string& reason = "", bool isImpromptu = false, bool isReuseChat = false) = 0; + virtual void setCreateAsReservedIfNew() = 0; + virtual void setPassword(const boost::optional<std::string>& password) = 0; public: @@ -82,44 +89,12 @@ namespace Swift { boost::signal<void (const std::string&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged; boost::signal<void (const MUCOccupant&)> onOccupantJoined; + boost::signal<void (const std::string& /*oldNickname*/, const std::string& /*newNickname*/ )> onOccupantNicknameChanged; boost::signal<void (const MUCOccupant&, LeavingType, const std::string& /*reason*/)> onOccupantLeft; boost::signal<void (Form::ref)> onConfigurationFormReceived; boost::signal<void (MUCOccupant::Affiliation, const std::vector<JID>&)> onAffiliationListReceived; + boost::signal<void ()> onUnlocked; /* boost::signal<void (const MUCInfo&)> onInfoResult; */ /* boost::signal<void (const blah&)> onItemsResult; */ - - private: - bool isFromMUC(const JID& j) const { - return ownMUCJID.equals(j, JID::WithoutResource); - } - - const std::string& getOwnNick() const { - return ownMUCJID.getResource(); - } - - private: - void handleIncomingPresence(Presence::ref presence); - void internalJoin(const std::string& nick); - void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref); - void handleOccupantRoleChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Role); - void handleAffiliationChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Affiliation); - void handleAffiliationListResponse(MUCAdminPayload::ref, ErrorPayload::ref, MUCOccupant::Affiliation); - void handleConfigurationFormReceived(MUCOwnerPayload::ref, ErrorPayload::ref); - void handleConfigurationResultReceived(MUCOwnerPayload::ref, ErrorPayload::ref); - - private: - JID ownMUCJID; - StanzaChannel* stanzaChannel; - IQRouter* iqRouter_; - DirectedPresenceSender* presenceSender; - MUCRegistry* mucRegistry; - std::map<std::string, MUCOccupant> occupants; - bool joinSucceeded_; - bool joinComplete_; - boost::bsignals::scoped_connection scopedConnection_; - boost::posix_time::ptime joinSince_; - bool createAsReservedIfNew; - bool unlocking; - boost::optional<std::string> password; }; } diff --git a/Swiften/MUC/MUCBookmarkManager.h b/Swiften/MUC/MUCBookmarkManager.h index ccea46c..667caa4 100644 --- a/Swiften/MUC/MUCBookmarkManager.h +++ b/Swiften/MUC/MUCBookmarkManager.h @@ -13,4 +13,5 @@ #include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/MUC/MUCBookmark.h> #include <Swiften/Elements/Storage.h> @@ -20,5 +21,5 @@ namespace Swift { class IQRouter; - class MUCBookmarkManager { + class SWIFTEN_API MUCBookmarkManager { public: MUCBookmarkManager(IQRouter* iqRouter); diff --git a/Swiften/MUC/MUCImpl.cpp b/Swiften/MUC/MUCImpl.cpp new file mode 100644 index 0000000..ab5faf4 --- /dev/null +++ b/Swiften/MUC/MUCImpl.cpp @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2010-2014 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/MUC/MUCImpl.h> + +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Presence/DirectedPresenceSender.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/MUCUserPayload.h> +#include <Swiften/Elements/MUCAdminPayload.h> +#include <Swiften/Elements/MUCPayload.h> +#include <Swiften/Elements/MUCDestroyPayload.h> +#include <Swiften/Elements/MUCInvitationPayload.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Queries/GenericRequest.h> + +namespace Swift { + +typedef std::pair<std::string, MUCOccupant> StringMUCOccupantPair; + +MUCImpl::MUCImpl(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry) : ownMUCJID(muc), stanzaChannel(stanzaChannel), iqRouter_(iqRouter), presenceSender(presenceSender), mucRegistry(mucRegistry), createAsReservedIfNew(false), unlocking(false), isUnlocked_(false) { + scopedConnection_ = stanzaChannel->onPresenceReceived.connect(boost::bind(&MUCImpl::handleIncomingPresence, this, _1)); +} + +MUCImpl::~MUCImpl() +{ +} + +//FIXME: discover reserved nickname + +/** + * Join the MUC with default context. + */ +void MUCImpl::joinAs(const std::string &nick) { + joinSince_ = boost::posix_time::not_a_date_time; + internalJoin(nick); +} + +/** + * Set the password used for entering the room. + */ +void MUCImpl::setPassword(const boost::optional<std::string>& newPassword) { + password = newPassword; +} + +/** + * Join the MUC with context since date. + */ +void MUCImpl::joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) { + joinSince_ = since; + internalJoin(nick); +} + +std::map<std::string, MUCOccupant> MUCImpl::getOccupants() const { + return occupants; +} + +void MUCImpl::internalJoin(const std::string &nick) { + //TODO: history request + joinComplete_ = false; + joinSucceeded_ = false; + + mucRegistry->addMUC(getJID()); + + ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick); + + Presence::ref joinPresence = boost::make_shared<Presence>(*presenceSender->getLastSentUndirectedPresence()); + assert(joinPresence->getType() == Presence::Available); + joinPresence->setTo(ownMUCJID); + MUCPayload::ref mucPayload = boost::make_shared<MUCPayload>(); + if (joinSince_ != boost::posix_time::not_a_date_time) { + mucPayload->setSince(joinSince_); + } + if (password) { + mucPayload->setPassword(*password); + } + joinPresence->addPayload(mucPayload); + + presenceSender->sendPresence(joinPresence); +} + +void MUCImpl::changeNickname(const std::string& newNickname) { + Presence::ref changeNicknamePresence = boost::make_shared<Presence>(); + changeNicknamePresence->setTo(ownMUCJID.toBare().toString() + std::string("/") + newNickname); + presenceSender->sendPresence(changeNicknamePresence); +} + +void MUCImpl::part() { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + mucRegistry->removeMUC(getJID()); +} + +void MUCImpl::handleUserLeft(LeavingType type) { + std::map<std::string,MUCOccupant>::iterator i = occupants.find(ownMUCJID.getResource()); + if (i != occupants.end()) { + MUCOccupant me = i->second; + occupants.erase(i); + onOccupantLeft(me, type, ""); + } + occupants.clear(); + joinComplete_ = false; + joinSucceeded_ = false; + isUnlocked_ = false; + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); +} + +void MUCImpl::handleIncomingPresence(Presence::ref presence) { + if (!isFromMUC(presence->getFrom())) { + return; + } + + MUCUserPayload::ref mucPayload; + foreach (MUCUserPayload::ref payload, presence->getPayloads<MUCUserPayload>()) { + if (!payload->getItems().empty() || !payload->getStatusCodes().empty()) { + mucPayload = payload; + } + } + + // On the first incoming presence, check if our join has succeeded + // (i.e. we start getting non-error presence from the MUC) or not + if (!joinSucceeded_) { + if (presence->getType() == Presence::Error) { + std::string reason; + onJoinFailed(presence->getPayload<ErrorPayload>()); + return; + } + else { + joinSucceeded_ = true; + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + } + } + + std::string nick = presence->getFrom().getResource(); + if (nick.empty()) { + return; + } + MUCOccupant::Role role(MUCOccupant::NoRole); + MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation); + boost::optional<JID> realJID; + if (mucPayload && mucPayload->getItems().size() > 0) { + role = mucPayload->getItems()[0].role ? mucPayload->getItems()[0].role.get() : MUCOccupant::NoRole; + affiliation = mucPayload->getItems()[0].affiliation ? mucPayload->getItems()[0].affiliation.get() : MUCOccupant::NoAffiliation; + realJID = mucPayload->getItems()[0].realJID; + } + + //100 is non-anonymous + //TODO: 100 may also be specified in a <message/> + //170 is room logging to http + //TODO: Nick changes + if (presence->getType() == Presence::Unavailable) { + LeavingType type = LeavePart; + boost::optional<std::string> newNickname; + if (mucPayload) { + if (boost::dynamic_pointer_cast<MUCDestroyPayload>(mucPayload->getPayload())) { + type = LeaveDestroy; + } + else foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { + if (status.code == 307) { + type = LeaveKick; + } + else if (status.code == 301) { + type = LeaveBan; + } + else if (status.code == 321) { + type = LeaveNotMember; + } + else if (status.code == 303) { + if (mucPayload->getItems().size() == 1) { + newNickname = mucPayload->getItems()[0].nick; + } + } + } + } + if (newNickname) { + std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); + if (i != occupants.end()) { + MUCOccupant occupant = i->second; + occupants.erase(i); + occupant.setNick(newNickname.get()); + occupants.insert(std::make_pair(newNickname.get(), occupant)); + onOccupantNicknameChanged(nick, newNickname.get()); + } + } + else { + if (presence->getFrom() == ownMUCJID) { + handleUserLeft(type); + return; + } + else { + std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); + if (i != occupants.end()) { + //TODO: part type + MUCOccupant occupant = i->second; + occupants.erase(i); + onOccupantLeft(occupant, type, ""); + } + } + } + } + else if (presence->getType() == Presence::Available) { + std::map<std::string, MUCOccupant>::iterator it = occupants.find(nick); + MUCOccupant occupant(nick, role, affiliation); + bool isJoin = true; + if (realJID) { + occupant.setRealJID(realJID.get()); + } + if (it != occupants.end()) { + isJoin = false; + MUCOccupant oldOccupant = it->second; + if (oldOccupant.getRole() != role) { + onOccupantRoleChanged(nick, occupant, oldOccupant.getRole()); + } + if (oldOccupant.getAffiliation() != affiliation) { + onOccupantAffiliationChanged(nick, affiliation, oldOccupant.getAffiliation()); + } + occupants.erase(it); + } + std::pair<std::map<std::string, MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, occupant)); + if (isJoin) { + onOccupantJoined(result.first->second); + } + onOccupantPresenceChange(presence); + } + if (mucPayload && !joinComplete_) { + bool isLocked = false; + foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { + if (status.code == 110) { + /* Simply knowing this is your presence is enough, 210 doesn't seem to be necessary. */ + joinComplete_ = true; + if (ownMUCJID != presence->getFrom()) { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + ownMUCJID = presence->getFrom(); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + } + onJoinComplete(getOwnNick()); + } + if (status.code == 201) { + isLocked = true; + /* Room is created and locked */ + /* Currently deal with this by making an instant room */ + if (ownMUCJID != presence->getFrom()) { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + ownMUCJID = presence->getFrom(); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + } + if (createAsReservedIfNew) { + unlocking = true; + requestConfigurationForm(); + } + else { + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + mucPayload->setPayload(boost::make_shared<Form>(Form::SubmitType)); + boost::shared_ptr< GenericRequest<MUCOwnerPayload> > request = boost::make_shared< GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); + request->send(); + } + } + } + if (!isLocked && !isUnlocked_ && (presence->getFrom() == ownMUCJID)) { + isUnlocked_ = true; + onUnlocked(); + } + } +} + +void MUCImpl::handleCreationConfigResponse(MUCOwnerPayload::ref /*unused*/, ErrorPayload::ref error) { + unlocking = false; + if (error) { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + onJoinFailed(error); + } else { + onJoinComplete(getOwnNick()); /* Previously, this wasn't needed here, as the presence duplication bug caused an emit elsewhere. */ + isUnlocked_ = true; + onUnlocked(); + } +} + +bool MUCImpl::hasOccupant(const std::string& nick) { + return occupants.find(nick) != occupants.end(); +} + +const MUCOccupant& MUCImpl::getOccupant(const std::string& nick) { + return occupants.find(nick)->second; +} + +void MUCImpl::kickOccupant(const JID& jid) { + changeOccupantRole(jid, MUCOccupant::NoRole); +} + +/** + * Call with the room JID, not the real JID. + */ +void MUCImpl::changeOccupantRole(const JID& jid, MUCOccupant::Role role) { + MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.role = role; + item.nick = jid.getResource(); + mucPayload->addItem(item); + boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared<GenericRequest<MUCAdminPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleOccupantRoleChangeResponse, this, _1, _2, jid, role)); + request->send(); + +} + +void MUCImpl::handleOccupantRoleChangeResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid, MUCOccupant::Role role) { + if (error) { + onRoleChangeFailed(error, jid, role); + } +} + +void MUCImpl::requestAffiliationList(MUCOccupant::Affiliation affiliation) { + MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.affiliation = affiliation; + mucPayload->addItem(item); + boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared< GenericRequest<MUCAdminPayload> >(IQ::Get, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleAffiliationListResponse, this, _1, _2, affiliation)); + request->send(); +} + +/** + * Must be called with the real JID, not the room JID. + */ +void MUCImpl::changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation) { + MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.affiliation = affiliation; + item.realJID = jid.toBare(); + mucPayload->addItem(item); + boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared<GenericRequest<MUCAdminPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleAffiliationChangeResponse, this, _1, _2, jid, affiliation)); + request->send(); +} + +void MUCImpl::handleAffiliationListResponse(MUCAdminPayload::ref payload, ErrorPayload::ref error, MUCOccupant::Affiliation affiliation) { + if (error) { + onAffiliationListFailed(error); + } + else { + std::vector<JID> jids; + foreach (MUCItem item, payload->getItems()) { + if (item.realJID) { + jids.push_back(*item.realJID); + } + } + onAffiliationListReceived(affiliation, jids); + } +} + +void MUCImpl::handleAffiliationChangeResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid, MUCOccupant::Affiliation affiliation) { + if (error) { + onAffiliationChangeFailed(error, jid, affiliation); + } +} + +void MUCImpl::changeSubject(const std::string& subject) { + Message::ref message = boost::make_shared<Message>(); + message->setSubject(subject); + message->setType(Message::Groupchat); + message->setTo(ownMUCJID.toBare()); + stanzaChannel->sendMessage(message); +} + +void MUCImpl::requestConfigurationForm() { + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Get, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationFormReceived, this, _1, _2)); + request->send(); +} + +void MUCImpl::cancelConfigureRoom() { + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + mucPayload->setPayload(boost::make_shared<Form>(Form::CancelType)); + boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->send(); +} + +void MUCImpl::handleConfigurationFormReceived(MUCOwnerPayload::ref payload, ErrorPayload::ref error) { + Form::ref form; + if (payload) { + form = payload->getForm(); + } + if (error || !form) { + onConfigurationFailed(error); + } else { + onConfigurationFormReceived(form); + } +} + +void MUCImpl::handleConfigurationResultReceived(MUCOwnerPayload::ref /*payload*/, ErrorPayload::ref error) { + if (error) { + onConfigurationFailed(error); + } +} + +void MUCImpl::configureRoom(Form::ref form) { + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + mucPayload->setPayload(form); + boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + if (unlocking) { + request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); + } + else { + request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationResultReceived, this, _1, _2)); + } + request->send(); +} + +void MUCImpl::destroyRoom() { + MUCOwnerPayload::ref mucPayload = boost::make_shared<MUCOwnerPayload>(); + MUCDestroyPayload::ref mucDestroyPayload = boost::make_shared<MUCDestroyPayload>(); + mucPayload->setPayload(mucDestroyPayload); + boost::shared_ptr< GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationResultReceived, this, _1, _2)); + request->send(); +} + +void MUCImpl::invitePerson(const JID& person, const std::string& reason, bool isImpromptu, bool isReuseChat) { + Message::ref message = boost::make_shared<Message>(); + message->setTo(person); + message->setType(Message::Normal); + MUCInvitationPayload::ref invite = boost::make_shared<MUCInvitationPayload>(); + invite->setReason(reason); + invite->setJID(ownMUCJID.toBare()); + invite->setIsImpromptu(isImpromptu); + invite->setIsContinuation(isReuseChat); + message->addPayload(invite); + stanzaChannel->sendMessage(message); +} + +//TODO: Invites(direct/mediated) + +//TODO: requesting membership + +//TODO: get member list + +//TODO: request voice + +//TODO: moderator use cases + +//TODO: Admin use cases + +//TODO: Owner use cases + +} diff --git a/Swiften/MUC/MUCImpl.h b/Swiften/MUC/MUCImpl.h new file mode 100644 index 0000000..8eabb80 --- /dev/null +++ b/Swiften/MUC/MUCImpl.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2010-2013 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/MUC/MUC.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Base/API.h> +#include <string> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/MUCOccupant.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Elements/MUCOwnerPayload.h> +#include <Swiften/Elements/MUCAdminPayload.h> +#include <Swiften/Elements/Form.h> + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> +#include <boost/signals/connection.hpp> + +#include <map> + +namespace Swift { + class StanzaChannel; + class IQRouter; + class DirectedPresenceSender; + + class SWIFTEN_API MUCImpl : public MUC { + public: + typedef boost::shared_ptr<MUCImpl> ref; + + public: + MUCImpl(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry); + virtual ~MUCImpl(); + + /** + * Returns the (bare) JID of the MUC. + */ + virtual JID getJID() const { + return ownMUCJID.toBare(); + } + + /** + * Returns if the room is unlocked and other people can join the room. + * @return True if joinable by others; false otherwise. + */ + virtual bool isUnlocked() const { + return isUnlocked_; + } + + virtual void joinAs(const std::string &nick); + virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since); + /*virtual void queryRoomInfo(); */ + /*virtual void queryRoomItems(); */ + /*virtual std::string getCurrentNick(); */ + virtual std::map<std::string, MUCOccupant> getOccupants() const; + + /** + * Send a new presence to the MUC indicating a nickname change. Any custom status the user had in the is cleared. + * @param newNickname The nickname to change to. + */ + virtual void changeNickname(const std::string& newNickname); + virtual void part(); + /*virtual void handleIncomingMessage(Message::ref message); */ + /** Expose public so it can be called when e.g. user goes offline */ + virtual void handleUserLeft(LeavingType); + /** Get occupant information*/ + virtual const MUCOccupant& getOccupant(const std::string& nick); + virtual bool hasOccupant(const std::string& nick); + virtual void kickOccupant(const JID& jid); + virtual void changeOccupantRole(const JID& jid, MUCOccupant::Role role); + virtual void requestAffiliationList(MUCOccupant::Affiliation); + virtual void changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation); + virtual void changeSubject(const std::string& subject); + virtual void requestConfigurationForm(); + virtual void configureRoom(Form::ref); + virtual void cancelConfigureRoom(); + virtual void destroyRoom(); + /** Send an invite for the person to join the MUC */ + virtual void invitePerson(const JID& person, const std::string& reason = "", bool isImpromptu = false, bool isReuseChat = false); + virtual void setCreateAsReservedIfNew() {createAsReservedIfNew = true;} + virtual void setPassword(const boost::optional<std::string>& password); + + private: + bool isFromMUC(const JID& j) const { + return ownMUCJID.equals(j, JID::WithoutResource); + } + + const std::string& getOwnNick() const { + return ownMUCJID.getResource(); + } + + private: + void handleIncomingPresence(Presence::ref presence); + void internalJoin(const std::string& nick); + void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref); + void handleOccupantRoleChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Role); + void handleAffiliationChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Affiliation); + void handleAffiliationListResponse(MUCAdminPayload::ref, ErrorPayload::ref, MUCOccupant::Affiliation); + void handleConfigurationFormReceived(MUCOwnerPayload::ref, ErrorPayload::ref); + void handleConfigurationResultReceived(MUCOwnerPayload::ref, ErrorPayload::ref); + + private: + JID ownMUCJID; + StanzaChannel* stanzaChannel; + IQRouter* iqRouter_; + DirectedPresenceSender* presenceSender; + MUCRegistry* mucRegistry; + std::map<std::string, MUCOccupant> occupants; + bool joinSucceeded_; + bool joinComplete_; + boost::bsignals::scoped_connection scopedConnection_; + boost::posix_time::ptime joinSince_; + bool createAsReservedIfNew; + bool unlocking; + bool isUnlocked_; + boost::optional<std::string> password; + }; +} diff --git a/Swiften/MUC/MUCManager.cpp b/Swiften/MUC/MUCManager.cpp index 6e9b820..0581829 100644 --- a/Swiften/MUC/MUCManager.cpp +++ b/Swiften/MUC/MUCManager.cpp @@ -6,4 +6,5 @@ #include <Swiften/MUC/MUCManager.h> +#include <Swiften/MUC/MUCImpl.h> namespace Swift { @@ -13,5 +14,5 @@ MUCManager::MUCManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, Directe MUC::ref MUCManager::createMUC(const JID& jid) { - return MUC::ref(new MUC(stanzaChannel, iqRouter, presenceSender, jid, mucRegistry)); + return boost::make_shared<MUCImpl>(stanzaChannel, iqRouter, presenceSender, jid, mucRegistry); } diff --git a/Swiften/MUC/MUCManager.h b/Swiften/MUC/MUCManager.h index 36ae61e..cf9000b 100644 --- a/Swiften/MUC/MUCManager.h +++ b/Swiften/MUC/MUCManager.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/MUC/MUC.h> @@ -15,5 +16,5 @@ namespace Swift { class MUCRegistry; - class MUCManager { + class SWIFTEN_API MUCManager { public: MUCManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, MUCRegistry* mucRegistry); diff --git a/Swiften/MUC/MUCRegistry.h b/Swiften/MUC/MUCRegistry.h index 0ed2d2e..6ad1b89 100644 --- a/Swiften/MUC/MUCRegistry.h +++ b/Swiften/MUC/MUCRegistry.h @@ -9,4 +9,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> @@ -14,5 +15,5 @@ namespace Swift { class JID; - class MUCRegistry { + class SWIFTEN_API MUCRegistry { public: ~MUCRegistry(); diff --git a/Swiften/MUC/UnitTest/MUCTest.cpp b/Swiften/MUC/UnitTest/MUCTest.cpp index 427e938..773edb6 100644 --- a/Swiften/MUC/UnitTest/MUCTest.cpp +++ b/Swiften/MUC/UnitTest/MUCTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,5 +11,5 @@ #include <boost/bind.hpp> -#include <Swiften/MUC/MUC.h> +#include <Swiften/MUC/MUCImpl.h> #include <Swiften/Client/DummyStanzaChannel.h> #include <Swiften/Presence/StanzaChannelPresenceSender.h> @@ -31,4 +31,5 @@ class MUCTest : public CppUnit::TestFixture { CPPUNIT_TEST(testCreateInstant); CPPUNIT_TEST(testReplicateBug); + CPPUNIT_TEST(testNicknameChange); /*CPPUNIT_TEST(testJoin_Success); CPPUNIT_TEST(testJoin_Fail);*/ @@ -42,4 +43,5 @@ class MUCTest : public CppUnit::TestFixture { stanzaChannelPresenceSender = new StanzaChannelPresenceSender(channel); presenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); + nickChanges = 0; } @@ -142,4 +144,65 @@ class MUCTest : public CppUnit::TestFixture { } + void testNicknameChange() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + // Join as Rabbit + testling->joinAs("Rabbit"); + + // Rabbit joins + Presence::ref rabbitJoins = boost::make_shared<Presence>(); + rabbitJoins->setTo("test@swift.im/6913d576d55f0b67"); + rabbitJoins->setFrom(testling->getJID().toString() + "/Rabbit"); + channel->onPresenceReceived(rabbitJoins); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Rabbit")); + + // Alice joins + Presence::ref aliceJoins = boost::make_shared<Presence>(); + aliceJoins->setTo("test@swift.im/6913d576d55f0b67"); + aliceJoins->setFrom(testling->getJID().toString() + "/Alice"); + channel->onPresenceReceived(aliceJoins); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice")); + + // Change nick to Dodo + testling->changeNickname("Dodo"); + Presence::ref stanza = channel->getStanzaAtIndex<Presence>(1); + CPPUNIT_ASSERT(stanza); + CPPUNIT_ASSERT_EQUAL(std::string("Dodo"), stanza->getTo().getResource()); + + // Alice changes nick to Alice2 + stanza = boost::make_shared<Presence>(); + stanza->setFrom(JID("foo@bar.com/Alice")); + stanza->setTo(JID(router->getJID())); + stanza->setType(Presence::Unavailable); + MUCUserPayload::ref mucPayload(new MUCUserPayload()); + MUCItem myItem; + myItem.affiliation = MUCOccupant::Member; + myItem.nick = "Alice2"; + myItem.role = MUCOccupant::Participant; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(303); + stanza->addPayload(mucPayload); + channel->onPresenceReceived(stanza); + CPPUNIT_ASSERT_EQUAL(1, nickChanges); + CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Alice")); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice2")); + + // We (Rabbit) change nick to Robot + stanza = boost::make_shared<Presence>(); + stanza->setFrom(JID("foo@bar.com/Rabbit")); + stanza->setTo(JID(router->getJID())); + stanza->setType(Presence::Unavailable); + mucPayload = MUCUserPayload::ref(new MUCUserPayload()); + myItem.affiliation = MUCOccupant::Member; + myItem.nick = "Robot"; + myItem.role = MUCOccupant::Participant; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(303); + stanza->addPayload(mucPayload); + channel->onPresenceReceived(stanza); + CPPUNIT_ASSERT_EQUAL(2, nickChanges); + CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Rabbit")); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Robot")); + } + /*void testJoin_Success() { MUC::ref testling = createMUC(JID("foo@bar.com")); @@ -159,5 +222,7 @@ class MUCTest : public CppUnit::TestFixture { private: MUC::ref createMUC(const JID& jid) { - return boost::make_shared<MUC>(channel, router, presenceSender, jid, mucRegistry); + MUC::ref muc = boost::make_shared<MUCImpl>(channel, router, presenceSender, jid, mucRegistry); + muc->onOccupantNicknameChanged.connect(boost::bind(&MUCTest::handleOccupantNicknameChanged, this, _1, _2)); + return muc; } @@ -178,4 +243,8 @@ class MUCTest : public CppUnit::TestFixture { } + void handleOccupantNicknameChanged(const std::string&, const std::string&) { + nickChanges++; + } + private: DummyStanzaChannel* channel; @@ -189,4 +258,5 @@ class MUCTest : public CppUnit::TestFixture { }; std::vector<JoinResult> joinResults; + int nickChanges; }; diff --git a/Swiften/MUC/UnitTest/MockMUC.cpp b/Swiften/MUC/UnitTest/MockMUC.cpp new file mode 100644 index 0000000..9ca35ec --- /dev/null +++ b/Swiften/MUC/UnitTest/MockMUC.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/MUC/UnitTest/MockMUC.h> + +namespace Swift { + +MockMUC::MockMUC(const JID &muc) +: ownMUCJID(muc) +{ +} + +MockMUC::~MockMUC() { +} + +void MockMUC::insertOccupant(const MUCOccupant& occupant) +{ + occupants_.insert(std::make_pair(occupant.getNick(), occupant)); + onOccupantJoined(occupant); +} + +const MUCOccupant& MockMUC::getOccupant(const std::string& nick) { + return occupants_.find(nick)->second; +} + +bool MockMUC::hasOccupant(const std::string& nick) { + return occupants_.find(nick) != occupants_.end(); +} + +void MockMUC::changeAffiliation(const JID &jid, MUCOccupant::Affiliation newAffilation) { + std::map<std::string, MUCOccupant>::iterator i = occupants_.find(jid.getResource()); + if (i != occupants_.end()) { + const MUCOccupant old = i->second; + i->second = MUCOccupant(old.getNick(), old.getRole(), newAffilation); + onOccupantAffiliationChanged(i->first, newAffilation, old.getAffiliation()); + } +} + +void MockMUC::changeOccupantRole(const JID &jid, MUCOccupant::Role newRole) { + std::map<std::string, MUCOccupant>::iterator i = occupants_.find(jid.getResource()); + if (i != occupants_.end()) { + const MUCOccupant old = i->second; + i->second = MUCOccupant(old.getNick(), newRole, old.getAffiliation()); + onOccupantRoleChanged(i->first, i->second, old.getRole()); + } +} + +} diff --git a/Swiften/MUC/UnitTest/MockMUC.h b/Swiften/MUC/UnitTest/MockMUC.h new file mode 100644 index 0000000..8673a90 --- /dev/null +++ b/Swiften/MUC/UnitTest/MockMUC.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/MUC/MUC.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/MUCOccupant.h> +#include <Swiften/Elements/MUCOwnerPayload.h> +#include <Swiften/Elements/MUCAdminPayload.h> +#include <Swiften/Elements/Form.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> +#include <boost/signals/connection.hpp> +#include <boost/shared_ptr.hpp> +#include <string> +#include <map> + +namespace Swift { + class StanzaChannel; + class IQRouter; + class DirectedPresenceSender; + + class SWIFTEN_API MockMUC : public MUC{ + public: + typedef boost::shared_ptr<MockMUC> ref; + + public: + MockMUC(const JID &muc); + virtual ~MockMUC(); + + /** + * Cause a user to appear to have entered the room. For testing only. + */ + void insertOccupant(const MUCOccupant& occupant); + + /** + * Returns the (bare) JID of the MUC. + */ + virtual JID getJID() const { + return ownMUCJID.toBare(); + } + /** + * Returns if the room is unlocked and other people can join the room. + * @return True if joinable by others; false otherwise. + */ + virtual bool isUnlocked() const { return true; } + + virtual void joinAs(const std::string&) {} + virtual void joinWithContextSince(const std::string&, const boost::posix_time::ptime&) {} + /*virtual void queryRoomInfo(); */ + /*virtual void queryRoomItems(); */ + /*virtual std::string getCurrentNick() = 0; */ + virtual std::map<std::string, MUCOccupant> getOccupants() const { return occupants_; } + virtual void changeNickname(const std::string&) { } + virtual void part() {} + /*virtual void handleIncomingMessage(Message::ref message) = 0; */ + /** Expose public so it can be called when e.g. user goes offline */ + virtual void handleUserLeft(LeavingType) {} + /** Get occupant information*/ + virtual const MUCOccupant& getOccupant(const std::string&); + virtual bool hasOccupant(const std::string&); + virtual void kickOccupant(const JID&) {} + virtual void changeOccupantRole(const JID&, MUCOccupant::Role); + virtual void requestAffiliationList(MUCOccupant::Affiliation) {} + virtual void changeAffiliation(const JID&, MUCOccupant::Affiliation); + virtual void changeSubject(const std::string&) {} + virtual void requestConfigurationForm() {} + virtual void configureRoom(Form::ref) {} + virtual void cancelConfigureRoom() {} + virtual void destroyRoom() {} + /** Send an invite for the person to join the MUC */ + virtual void invitePerson(const JID&, const std::string&, bool, bool) {} + virtual void setCreateAsReservedIfNew() {} + virtual void setPassword(const boost::optional<std::string>&) {} + + protected: + virtual bool isFromMUC(const JID& j) const { + return ownMUCJID.equals(j, JID::WithoutResource); + } + + virtual const std::string& getOwnNick() const { + return ownMUCJID.getResource(); + } + + private: + JID ownMUCJID; + std::map<std::string, MUCOccupant> occupants_; + }; +} diff --git a/Swiften/Network/BOSHConnection.cpp b/Swiften/Network/BOSHConnection.cpp index 73f8ed6..28e27d5 100644 --- a/Swiften/Network/BOSHConnection.cpp +++ b/Swiften/Network/BOSHConnection.cpp @@ -6,5 +6,5 @@ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -33,4 +33,5 @@ BOSHConnection::BOSHConnection(const URL& boshURL, Connector::ref connector, XML sid_(), waitingForStartResponse_(false), + rid_(~0ULL), pending_(false), connectionReady_(false) @@ -61,9 +62,12 @@ void BOSHConnection::cancelConnector() { void BOSHConnection::disconnect() { - cancelConnector(); if (connection_) { connection_->disconnect(); sid_ = ""; } + else { + /* handleDisconnected takes care of the connector_ as well */ + handleDisconnected(boost::optional<Connection::Error>()); + } } @@ -102,7 +106,11 @@ std::pair<SafeByteArray, size_t> BOSHConnection::createHTTPRequest(const SafeByt size = safeContent.size(); - header << "POST /" << boshURL.getPath() << " HTTP/1.1\r\n" - << "Host: " << boshURL.getHost() << ":" << boshURL.getPort() << "\r\n" - /*<< "Accept-Encoding: deflate\r\n"*/ + header << "POST " << boshURL.getPath() << " HTTP/1.1\r\n" + << "Host: " << boshURL.getHost(); + if (boshURL.getPort()) { + header << ":" << *boshURL.getPort(); + } + header << "\r\n" + // << "Accept-Encoding: deflate\r\n" << "Content-Type: text/xml; charset=utf-8\r\n" << "Content-Length: " << size << "\r\n\r\n"; @@ -129,5 +137,5 @@ void BOSHConnection::write(const SafeByteArray& data, bool streamRestart, bool t void BOSHConnection::handleConnectFinished(Connection::ref connection) { cancelConnector(); - connectionReady_ = connection; + connectionReady_ = !!connection; if (connectionReady_) { connection_ = connection; @@ -150,5 +158,5 @@ void BOSHConnection::startStream(const std::string& to, unsigned long long rid) << " ver='1.6'" << " wait='60'" /* FIXME: we probably want this configurable*/ - /*<< " ack='0'" FIXME: support acks */ + // << " ack='0'" FIXME: support acks << " xml:lang='en'" << " xmlns:xmpp='urn:xmpp:bosh'" @@ -158,7 +166,11 @@ void BOSHConnection::startStream(const std::string& to, unsigned long long rid) std::string contentString = content.str(); - header << "POST /" << boshURL_.getPath() << " HTTP/1.1\r\n" - << "Host: " << boshURL_.getHost() << ":" << boshURL_.getPort() << "\r\n" - /*<< "Accept-Encoding: deflate\r\n"*/ + header << "POST " << boshURL_.getPath() << " HTTP/1.1\r\n" + << "Host: " << boshURL_.getHost(); + if (boshURL_.getPort()) { + header << ":" << *boshURL_.getPort(); + } + header << "\r\n" + // << "Accept-Encoding: deflate\r\n" << "Content-Type: text/xml; charset=utf-8\r\n" << "Content-Length: " << contentString.size() << "\r\n\r\n" @@ -198,5 +210,5 @@ void BOSHConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { sid_ = parser.getBody()->attributes.getAttribute("sid"); std::string requestsString = parser.getBody()->attributes.getAttribute("requests"); - int requests = 2; + size_t requests = 2; if (!requestsString.empty()) { try { @@ -274,5 +286,5 @@ void BOSHConnection::setSID(const std::string& sid) { void BOSHConnection::handleDisconnected(const boost::optional<Connection::Error>& error) { cancelConnector(); - onDisconnected(error); + onDisconnected(error ? true : false); sid_ = ""; connectionReady_ = false; diff --git a/Swiften/Network/BOSHConnection.h b/Swiften/Network/BOSHConnection.h index a2abfcd..01341cc 100644 --- a/Swiften/Network/BOSHConnection.h +++ b/Swiften/Network/BOSHConnection.h @@ -16,4 +16,5 @@ #include <boost/enable_shared_from_this.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/Connector.h> @@ -37,5 +38,5 @@ namespace Swift { class TLSContextFactory; - class BOSHError : public SessionStream::SessionStreamError { + class SWIFTEN_API BOSHError : public SessionStream::SessionStreamError { public: enum Type {BadRequest, HostGone, HostUnknown, ImproperAddressing, @@ -52,5 +53,5 @@ namespace Swift { - class BOSHConnection : public boost::enable_shared_from_this<BOSHConnection> { + class SWIFTEN_API BOSHConnection : public boost::enable_shared_from_this<BOSHConnection> { public: typedef boost::shared_ptr<BOSHConnection> ref; diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp index bb24aa5..fdfe420 100644 --- a/Swiften/Network/BOSHConnectionPool.cpp +++ b/Swiften/Network/BOSHConnectionPool.cpp @@ -15,5 +15,5 @@ #include <Swiften/Network/TLSConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> -#include <Swiften/Network/CachingNameOnlyDomainNameResolver.h> +#include <Swiften/Network/CachingDomainNameResolver.h> namespace Swift { @@ -22,5 +22,4 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r connectionFactory(connectionFactoryParameter), xmlParserFactory(parserFactory), - tlsFactory(tlsFactory), timerFactory(timerFactory), rid(initialRID), @@ -31,10 +30,10 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r pendingRestart(false) { - if (!boshHTTPConnectProxyURL.empty()) { + if (!boshHTTPConnectProxyURL.isEmpty()) { if (boshHTTPConnectProxyURL.getScheme() == "https") { connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory); myConnectionFactories.push_back(connectionFactory); } - connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, eventLoop, boshHTTPConnectProxyURL.getHost(), boshHTTPConnectProxyURL.getPort(), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); + connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, boshHTTPConnectProxyURL.getHost(), URL::getPortOrDefaultPort(boshHTTPConnectProxyURL), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); } if (boshURL.getScheme() == "https") { @@ -42,10 +41,17 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r myConnectionFactories.push_back(connectionFactory); } - resolver = new CachingNameOnlyDomainNameResolver(realResolver, eventLoop); + resolver = new CachingDomainNameResolver(realResolver, eventLoop); createConnection(); } BOSHConnectionPool::~BOSHConnectionPool() { - close(); + /* Don't do a normal close here. Instead kill things forcibly, as close() or writeFooter() will already have been called */ + std::vector<BOSHConnection::ref> connectionCopies = connections; + foreach (BOSHConnection::ref connection, connectionCopies) { + if (connection) { + destroyConnection(connection); + connection->disconnect(); + } + } foreach (ConnectionFactory* factory, myConnectionFactories) { delete factory; @@ -84,10 +90,14 @@ void BOSHConnectionPool::writeFooter() { void BOSHConnectionPool::close() { - /* TODO: Send a terminate here. */ + if (!sid.empty()) { + writeFooter(); + } + else { + pendingTerminate = true; std::vector<BOSHConnection::ref> connectionCopies = connections; foreach (BOSHConnection::ref connection, connectionCopies) { if (connection) { connection->disconnect(); - destroyConnection(connection); + } } } @@ -160,5 +170,6 @@ void BOSHConnectionPool::tryToSendQueuedData() { suitableConnection->setRID(rid); suitableConnection->terminateStream(); - onSessionTerminated(boost::shared_ptr<BOSHError>()); + sid = ""; + close(); } } @@ -200,9 +211,12 @@ void BOSHConnectionPool::handleHTTPError(const std::string& /*errorCode*/) { } -void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection::ref connection) { +void BOSHConnectionPool::handleConnectionDisconnected(bool/* error*/, BOSHConnection::ref connection) { destroyConnection(connection); - if (false && error) { - handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition)); + if (pendingTerminate && sid.empty() && connections.empty()) { + handleSessionTerminated(BOSHError::ref()); } + //else if (error) { + // handleSessionTerminated(boost::make_shared<BOSHError>(BOSHError::UndefinedCondition)); + //} else { /* We might have just freed up a connection slot to send with */ @@ -212,5 +226,5 @@ void BOSHConnectionPool::handleConnectionDisconnected(bool error, BOSHConnection boost::shared_ptr<BOSHConnection> BOSHConnectionPool::createConnection() { - Connector::ref connector = Connector::create(boshURL.getHost(), resolver, connectionFactory, timerFactory, boshURL.getPort()); + Connector::ref connector = Connector::create(boshURL.getHost(), URL::getPortOrDefaultPort(boshURL), boost::optional<std::string>(), resolver, connectionFactory, timerFactory); BOSHConnection::ref connection = BOSHConnection::create(boshURL, connector, xmlParserFactory); connection->onXMPPDataRead.connect(boost::bind(&BOSHConnectionPool::handleDataRead, this, _1)); diff --git a/Swiften/Network/BOSHConnectionPool.h b/Swiften/Network/BOSHConnectionPool.h index 8bc0a7c..de707e8 100644 --- a/Swiften/Network/BOSHConnectionPool.h +++ b/Swiften/Network/BOSHConnectionPool.h @@ -10,4 +10,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeString.h> #include <Swiften/Network/BOSHConnection.h> @@ -16,8 +17,8 @@ namespace Swift { class HTTPConnectProxiedConnectionFactory; class TLSConnectionFactory; - class CachingNameOnlyDomainNameResolver; + class CachingDomainNameResolver; class EventLoop; - class BOSHConnectionPool : public boost::bsignals::trackable { + class SWIFTEN_API BOSHConnectionPool : public boost::bsignals::trackable { public: BOSHConnectionPool(const URL& boshURL, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword); @@ -54,5 +55,4 @@ namespace Swift { ConnectionFactory* connectionFactory; XMLParserFactory* xmlParserFactory; - TLSContextFactory* tlsFactory; TimerFactory* timerFactory; std::vector<BOSHConnection::ref> connections; @@ -66,5 +66,5 @@ namespace Swift { bool pendingRestart; std::vector<ConnectionFactory*> myConnectionFactories; - CachingNameOnlyDomainNameResolver* resolver; + CachingDomainNameResolver* resolver; }; } diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp index 1d4bd32..5137c3c 100644 --- a/Swiften/Network/BoostConnection.cpp +++ b/Swiften/Network/BoostConnection.cpp @@ -15,4 +15,5 @@ #include <boost/asio/write.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Log.h> @@ -64,5 +65,5 @@ void BoostConnection::listen() { void BoostConnection::connect(const HostAddressPort& addressPort) { boost::asio::ip::tcp::endpoint endpoint( - boost::asio::ip::address::from_string(addressPort.getAddress().toString()), addressPort.getPort()); + boost::asio::ip::address::from_string(addressPort.getAddress().toString()), boost::numeric_cast<unsigned short>(addressPort.getPort())); socket_.async_connect( endpoint, diff --git a/Swiften/Network/BoostConnection.h b/Swiften/Network/BoostConnection.h index 0e29c54..636853a 100644 --- a/Swiften/Network/BoostConnection.h +++ b/Swiften/Network/BoostConnection.h @@ -12,4 +12,5 @@ #include <boost/thread/mutex.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/EventLoop/EventOwner.h> @@ -26,5 +27,5 @@ namespace Swift { class EventLoop; - class BoostConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<BoostConnection> { + class SWIFTEN_API BoostConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<BoostConnection> { public: typedef boost::shared_ptr<BoostConnection> ref; diff --git a/Swiften/Network/BoostConnectionServer.cpp b/Swiften/Network/BoostConnectionServer.cpp index eccffc6..c90b554 100644 --- a/Swiften/Network/BoostConnectionServer.cpp +++ b/Swiften/Network/BoostConnectionServer.cpp @@ -10,4 +10,6 @@ #include <boost/system/system_error.hpp> #include <boost/asio/placeholders.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <boost/optional.hpp> #include <Swiften/EventLoop/EventLoop.h> @@ -22,4 +24,11 @@ BoostConnectionServer::BoostConnectionServer(const HostAddress &address, int por void BoostConnectionServer::start() { + boost::optional<Error> error = tryStart(); + if (error) { + eventLoop->postEvent(boost::bind(boost::ref(onStopped), *error), shared_from_this()); + } +} + +boost::optional<BoostConnectionServer::Error> BoostConnectionServer::tryStart() { try { assert(!acceptor_); @@ -27,10 +36,10 @@ void BoostConnectionServer::start() { acceptor_ = new boost::asio::ip::tcp::acceptor( *ioService_, - boost::asio::ip::tcp::endpoint(address_.getRawAddress(), port_)); + boost::asio::ip::tcp::endpoint(address_.getRawAddress(), boost::numeric_cast<unsigned short>(port_))); } else { acceptor_ = new boost::asio::ip::tcp::acceptor( *ioService_, - boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port_)); + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), boost::numeric_cast<unsigned short>(port_))); } acceptNextConnection(); @@ -38,10 +47,11 @@ void BoostConnectionServer::start() { catch (const boost::system::system_error& e) { if (e.code() == boost::asio::error::address_in_use) { - eventLoop->postEvent(boost::bind(boost::ref(onStopped), Conflict), shared_from_this()); + return Conflict; } else { - eventLoop->postEvent(boost::bind(boost::ref(onStopped), UnknownError), shared_from_this()); + return UnknownError; } } + return boost::optional<Error>(); } diff --git a/Swiften/Network/BoostConnectionServer.h b/Swiften/Network/BoostConnectionServer.h index 56dc8bd..3ad0450 100644 --- a/Swiften/Network/BoostConnectionServer.h +++ b/Swiften/Network/BoostConnectionServer.h @@ -11,20 +11,17 @@ #include <boost/asio/ip/tcp.hpp> #include <boost/enable_shared_from_this.hpp> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/BoostConnection.h> #include <Swiften/Network/ConnectionServer.h> #include <Swiften/EventLoop/EventOwner.h> +#include <boost/optional/optional_fwd.hpp> namespace Swift { - class BoostConnectionServer : public ConnectionServer, public EventOwner, public boost::enable_shared_from_this<BoostConnectionServer> { + class SWIFTEN_API BoostConnectionServer : public ConnectionServer, public EventOwner, public boost::enable_shared_from_this<BoostConnectionServer> { public: typedef boost::shared_ptr<BoostConnectionServer> ref; - enum Error { - Conflict, - UnknownError - }; - static ref create(int port, boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) { return ref(new BoostConnectionServer(port, ioService, eventLoop)); @@ -35,4 +32,5 @@ namespace Swift { } + virtual boost::optional<Error> tryStart(); // FIXME: This should become the new start virtual void start(); virtual void stop(); diff --git a/Swiften/Network/BoostIOServiceThread.h b/Swiften/Network/BoostIOServiceThread.h index 00fb397..d1a5f37 100644 --- a/Swiften/Network/BoostIOServiceThread.h +++ b/Swiften/Network/BoostIOServiceThread.h @@ -11,6 +11,8 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> + namespace Swift { - class BoostIOServiceThread { + class SWIFTEN_API BoostIOServiceThread { public: BoostIOServiceThread(); diff --git a/Swiften/Network/BoostNetworkFactories.cpp b/Swiften/Network/BoostNetworkFactories.cpp index 488e519..870ae97 100644 --- a/Swiften/Network/BoostNetworkFactories.cpp +++ b/Swiften/Network/BoostNetworkFactories.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,11 +8,22 @@ #include <Swiften/Network/BoostTimerFactory.h> #include <Swiften/Network/BoostConnectionFactory.h> -#include <Swiften/Network/PlatformDomainNameResolver.h> + #include <Swiften/Network/BoostConnectionServerFactory.h> #include <Swiften/Network/PlatformNATTraversalWorker.h> #include <Swiften/Parser/PlatformXMLParserFactory.h> #include <Swiften/Network/NullNATTraverser.h> +#include <Swiften/Network/PlatformNetworkEnvironment.h> #include <Swiften/TLS/PlatformTLSFactories.h> #include <Swiften/Network/PlatformProxyProvider.h> +#include <Swiften/IDN/PlatformIDNConverter.h> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> +#include <Swiften/Crypto/CryptoProvider.h> + +#ifdef USE_UNBOUND +#include <Swiften/Network/UnboundDomainNameResolver.h> +#else +#include <Swiften/Network/PlatformDomainNameResolver.h> +#endif namespace Swift { @@ -21,5 +32,4 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(e timerFactory = new BoostTimerFactory(ioServiceThread.getIOService(), eventLoop); connectionFactory = new BoostConnectionFactory(ioServiceThread.getIOService(), eventLoop); - domainNameResolver = new PlatformDomainNameResolver(eventLoop); connectionServerFactory = new BoostConnectionServerFactory(ioServiceThread.getIOService(), eventLoop); #ifdef SWIFT_EXPERIMENTAL_FT @@ -28,16 +38,28 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(e natTraverser = new NullNATTraverser(eventLoop); #endif + networkEnvironment = new PlatformNetworkEnvironment(); xmlParserFactory = new PlatformXMLParserFactory(); tlsFactories = new PlatformTLSFactories(); proxyProvider = new PlatformProxyProvider(); + idnConverter = PlatformIDNConverter::create(); +#ifdef USE_UNBOUND + // TODO: What to do about idnConverter. + domainNameResolver = new UnboundDomainNameResolver(idnConverter, ioServiceThread.getIOService(), eventLoop); +#else + domainNameResolver = new PlatformDomainNameResolver(idnConverter, eventLoop); +#endif + cryptoProvider = PlatformCryptoProvider::create(); } BoostNetworkFactories::~BoostNetworkFactories() { + delete cryptoProvider; + delete domainNameResolver; + delete idnConverter; delete proxyProvider; delete tlsFactories; delete xmlParserFactory; + delete networkEnvironment; delete natTraverser; delete connectionServerFactory; - delete domainNameResolver; delete connectionFactory; delete timerFactory; diff --git a/Swiften/Network/BoostNetworkFactories.h b/Swiften/Network/BoostNetworkFactories.h index c9b12da..9c3bab1 100644 --- a/Swiften/Network/BoostNetworkFactories.h +++ b/Swiften/Network/BoostNetworkFactories.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,6 @@ #pragma once +#include <Swiften/Base/API.h> +#include <Swiften/Base/Override.h> #include <Swiften/Network/NetworkFactories.h> #include <Swiften/Network/BoostIOServiceThread.h> @@ -15,14 +17,14 @@ namespace Swift { class PlatformTLSFactories; - class BoostNetworkFactories : public NetworkFactories { + class SWIFTEN_API BoostNetworkFactories : public NetworkFactories { public: BoostNetworkFactories(EventLoop* eventLoop); ~BoostNetworkFactories(); - virtual TimerFactory* getTimerFactory() const { + virtual TimerFactory* getTimerFactory() const SWIFTEN_OVERRIDE { return timerFactory; } - virtual ConnectionFactory* getConnectionFactory() const { + virtual ConnectionFactory* getConnectionFactory() const SWIFTEN_OVERRIDE { return connectionFactory; } @@ -32,30 +34,42 @@ namespace Swift { } - DomainNameResolver* getDomainNameResolver() const { + DomainNameResolver* getDomainNameResolver() const SWIFTEN_OVERRIDE { return domainNameResolver; } - ConnectionServerFactory* getConnectionServerFactory() const { + ConnectionServerFactory* getConnectionServerFactory() const SWIFTEN_OVERRIDE { return connectionServerFactory; } - NATTraverser* getNATTraverser() const { + NetworkEnvironment* getNetworkEnvironment() const SWIFTEN_OVERRIDE { + return networkEnvironment; + } + + NATTraverser* getNATTraverser() const SWIFTEN_OVERRIDE { return natTraverser; } - virtual XMLParserFactory* getXMLParserFactory() const { + virtual XMLParserFactory* getXMLParserFactory() const SWIFTEN_OVERRIDE { return xmlParserFactory; } - virtual TLSContextFactory* getTLSContextFactory() const; + virtual TLSContextFactory* getTLSContextFactory() const SWIFTEN_OVERRIDE; - virtual ProxyProvider* getProxyProvider() const { + virtual ProxyProvider* getProxyProvider() const SWIFTEN_OVERRIDE { return proxyProvider; } - virtual EventLoop* getEventLoop() const { + virtual EventLoop* getEventLoop() const SWIFTEN_OVERRIDE { return eventLoop; } + virtual IDNConverter* getIDNConverter() const SWIFTEN_OVERRIDE { + return idnConverter; + } + + virtual CryptoProvider* getCryptoProvider() const SWIFTEN_OVERRIDE { + return cryptoProvider; + } + private: BoostIOServiceThread ioServiceThread; @@ -65,8 +79,11 @@ namespace Swift { ConnectionServerFactory* connectionServerFactory; NATTraverser* natTraverser; + NetworkEnvironment* networkEnvironment; XMLParserFactory* xmlParserFactory; PlatformTLSFactories* tlsFactories; ProxyProvider* proxyProvider; EventLoop* eventLoop; + IDNConverter* idnConverter; + CryptoProvider* cryptoProvider; }; } diff --git a/Swiften/Network/CachingDomainNameResolver.cpp b/Swiften/Network/CachingDomainNameResolver.cpp new file mode 100644 index 0000000..fea14a3 --- /dev/null +++ b/Swiften/Network/CachingDomainNameResolver.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/CachingDomainNameResolver.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +CachingDomainNameResolver::CachingDomainNameResolver(DomainNameResolver* realResolver, EventLoop*) : realResolver(realResolver) { +} + +CachingDomainNameResolver::~CachingDomainNameResolver() { + +} + +DomainNameServiceQuery::ref CachingDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + //TODO: Cache + return realResolver->createServiceQuery(serviceLookupPrefix, domain); +} + +DomainNameAddressQuery::ref CachingDomainNameResolver::createAddressQuery(const std::string& name) { + //TODO: Cache + return realResolver->createAddressQuery(name); +} + +} diff --git a/Swiften/Network/CachingNameOnlyDomainNameResolver.h b/Swiften/Network/CachingDomainNameResolver.h index d9e78e6..3d50676 100644 --- a/Swiften/Network/CachingNameOnlyDomainNameResolver.h +++ b/Swiften/Network/CachingDomainNameResolver.h @@ -12,21 +12,20 @@ #include <Swiften/Network/StaticDomainNameResolver.h> - +/* + * FIXME: Does not do any caching yet. + */ namespace Swift { class EventLoop; - class CachingNameOnlyDomainNameResolver : public DomainNameResolver { + + class CachingDomainNameResolver : public DomainNameResolver { public: - CachingNameOnlyDomainNameResolver(DomainNameResolver* realResolver, EventLoop* eventLoop); - ~CachingNameOnlyDomainNameResolver(); + CachingDomainNameResolver(DomainNameResolver* realResolver, EventLoop* eventLoop); + ~CachingDomainNameResolver(); - virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& name); + virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); virtual DomainNameAddressQuery::ref createAddressQuery(const std::string& name); private: - void handleAddressQueryResult(const std::string hostname, const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error); - - private: DomainNameResolver* realResolver; - boost::shared_ptr<StaticDomainNameResolver> staticResolver; }; } diff --git a/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp b/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp deleted file mode 100644 index a83bebd..0000000 --- a/Swiften/Network/CachingNameOnlyDomainNameResolver.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2012 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Network/CachingNameOnlyDomainNameResolver.h> - -#include <boost/smart_ptr/make_shared.hpp> - -namespace Swift { -CachingNameOnlyDomainNameResolver::CachingNameOnlyDomainNameResolver(DomainNameResolver* realResolver, EventLoop* eventLoop) : realResolver(realResolver) { - staticResolver = boost::make_shared<StaticDomainNameResolver>(eventLoop); -} - -CachingNameOnlyDomainNameResolver::~CachingNameOnlyDomainNameResolver() { - -} - -DomainNameServiceQuery::ref CachingNameOnlyDomainNameResolver::createServiceQuery(const std::string& name) { - return staticResolver->createServiceQuery(name); -} - -DomainNameAddressQuery::ref CachingNameOnlyDomainNameResolver::createAddressQuery(const std::string& name) { - return realResolver->createAddressQuery(name); -} - -void CachingNameOnlyDomainNameResolver::handleAddressQueryResult(const std::string hostname, const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> error) { - //FIXME: Cache -} - -} diff --git a/Swiften/Network/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp index 0a1283f..14d66ae 100644 --- a/Swiften/Network/ChainedConnector.cpp +++ b/Swiften/Network/ChainedConnector.cpp @@ -19,8 +19,12 @@ using namespace Swift; ChainedConnector::ChainedConnector( const std::string& hostname, + int port, + const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, const std::vector<ConnectionFactory*>& connectionFactories, TimerFactory* timerFactory) : hostname(hostname), + port(port), + serviceLookupPrefix(serviceLookupPrefix), resolver(resolver), connectionFactories(connectionFactories), @@ -59,5 +63,5 @@ void ChainedConnector::tryNextConnectionFactory() { SWIFT_LOG(debug) << "Trying next connection factory: " << typeid(*connectionFactory).name() << std::endl; connectionFactoryQueue.pop_front(); - currentConnector = Connector::create(hostname, resolver, connectionFactory, timerFactory); + currentConnector = Connector::create(hostname, port, serviceLookupPrefix, resolver, connectionFactory, timerFactory); currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h index 12ef023..0a1cca9 100644 --- a/Swiften/Network/ChainedConnector.h +++ b/Swiften/Network/ChainedConnector.h @@ -11,5 +11,7 @@ #include <deque> #include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/Error.h> @@ -22,7 +24,7 @@ namespace Swift { class DomainNameResolver; - class ChainedConnector { + class SWIFTEN_API ChainedConnector { public: - ChainedConnector(const std::string& hostname, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); + ChainedConnector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); void setTimeoutMilliseconds(int milliseconds); @@ -39,4 +41,6 @@ namespace Swift { private: std::string hostname; + int port; + boost::optional<std::string> serviceLookupPrefix; DomainNameResolver* resolver; std::vector<ConnectionFactory*> connectionFactories; @@ -47,3 +51,3 @@ namespace Swift { boost::shared_ptr<Error> lastError; }; -}; +} diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h index 6ad2999..97c287d 100644 --- a/Swiften/Network/Connection.h +++ b/Swiften/Network/Connection.h @@ -10,4 +10,5 @@ #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> @@ -15,5 +16,5 @@ namespace Swift { class HostAddressPort; - class Connection { + class SWIFTEN_API Connection { public: typedef boost::shared_ptr<Connection> ref; diff --git a/Swiften/Network/ConnectionFactory.h b/Swiften/Network/ConnectionFactory.h index 9e92c36..c8be2fc 100644 --- a/Swiften/Network/ConnectionFactory.h +++ b/Swiften/Network/ConnectionFactory.h @@ -9,8 +9,10 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> + namespace Swift { class Connection; - class ConnectionFactory { + class SWIFTEN_API ConnectionFactory { public: virtual ~ConnectionFactory(); diff --git a/Swiften/Network/ConnectionServer.h b/Swiften/Network/ConnectionServer.h index 00703a4..2e09348 100644 --- a/Swiften/Network/ConnectionServer.h +++ b/Swiften/Network/ConnectionServer.h @@ -8,16 +8,25 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/HostAddressPort.h> +#include <boost/optional/optional_fwd.hpp> namespace Swift { - class ConnectionServer { + class SWIFTEN_API ConnectionServer { public: + enum Error { + Conflict, + UnknownError + }; + virtual ~ConnectionServer(); virtual HostAddressPort getAddressPort() const = 0; + virtual boost::optional<Error> tryStart() = 0; // FIXME: This should become the new start + virtual void start() = 0; diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 5e7f8d9..1db1eac 100644 --- a/Swiften/Network/Connector.cpp +++ b/Swiften/Network/Connector.cpp @@ -18,5 +18,5 @@ namespace Swift { -Connector::Connector(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, int defaultPort) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), defaultPort(defaultPort), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { +Connector::Connector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : hostname(hostname), port(port), serviceLookupPrefix(serviceLookupPrefix), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { } @@ -32,13 +32,17 @@ void Connector::start() { assert(!timer); queriedAllServices = false; - serviceQuery = resolver->createServiceQuery("_xmpp-client._tcp." + hostname); - serviceQuery->onResult.connect(boost::bind(&Connector::handleServiceQueryResult, shared_from_this(), _1)); if (timeoutMilliseconds > 0) { timer = timerFactory->createTimer(timeoutMilliseconds); timer->onTick.connect(boost::bind(&Connector::handleTimeout, shared_from_this())); - timer->start(); } + if (serviceLookupPrefix) { + serviceQuery = resolver->createServiceQuery(*serviceLookupPrefix, hostname); + serviceQuery->onResult.connect(boost::bind(&Connector::handleServiceQueryResult, shared_from_this(), _1)); serviceQuery->run(); } + else { + queryAddress(hostname); + } +} void Connector::stop() { @@ -110,10 +114,10 @@ void Connector::tryNextAddress() { addressQueryResults.pop_front(); - int port = defaultPort; + int connectPort = (port == -1 ? 5222 : port); if (!serviceQueryResults.empty()) { - port = serviceQueryResults.front().port; + connectPort = serviceQueryResults.front().port; } - tryConnect(HostAddressPort(address, port)); + tryConnect(HostAddressPort(address, connectPort)); } } @@ -125,8 +129,15 @@ void Connector::tryConnect(const HostAddressPort& target) { currentConnection->onConnectFinished.connect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); currentConnection->connect(target); + if (timer) { + timer->start(); + } } void Connector::handleConnectionConnectFinished(bool error) { SWIFT_LOG(debug) << "ConnectFinished: " << (error ? "error" : "success") << std::endl; + if (timer) { + timer->stop(); + timer.reset(); + } currentConnection->onConnectFinished.disconnect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); if (error) { @@ -170,6 +181,6 @@ void Connector::finish(boost::shared_ptr<Connection> connection) { void Connector::handleTimeout() { SWIFT_LOG(debug) << "Timeout" << std::endl; - finish(boost::shared_ptr<Connection>()); + handleConnectionConnectFinished(true); } -}; +} diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index bf0efaf..16f8539 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -10,5 +10,6 @@ #include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> - +#include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/DomainNameServiceQuery.h> #include <Swiften/Network/Connection.h> @@ -24,10 +25,10 @@ namespace Swift { class TimerFactory; - class Connector : public boost::bsignals::trackable, public boost::enable_shared_from_this<Connector> { + class SWIFTEN_API Connector : public boost::bsignals::trackable, public boost::enable_shared_from_this<Connector> { public: typedef boost::shared_ptr<Connector> ref; - static Connector::ref create(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, int defaultPort = 5222) { - return ref(new Connector(hostname, resolver, connectionFactory, timerFactory, defaultPort)); + static Connector::ref create(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { + return ref(new Connector(hostname, port, serviceLookupPrefix, resolver, connectionFactory, timerFactory)); } @@ -39,5 +40,5 @@ namespace Swift { private: - Connector(const std::string& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*, int defaultPort); + Connector(const std::string& hostname, int port, const boost::optional<std::string>& serviceLookupPrefix, DomainNameResolver*, ConnectionFactory*, TimerFactory*); void handleServiceQueryResult(const std::vector<DomainNameServiceQuery::Result>& result); @@ -56,8 +57,9 @@ namespace Swift { private: std::string hostname; + int port; + boost::optional<std::string> serviceLookupPrefix; DomainNameResolver* resolver; ConnectionFactory* connectionFactory; TimerFactory* timerFactory; - int defaultPort; int timeoutMilliseconds; boost::shared_ptr<Timer> timer; @@ -70,3 +72,3 @@ namespace Swift { bool foundSomeDNS; }; -}; +} diff --git a/Swiften/Network/DomainNameResolver.h b/Swiften/Network/DomainNameResolver.h index b0ebc35..dc7013e 100644 --- a/Swiften/Network/DomainNameResolver.h +++ b/Swiften/Network/DomainNameResolver.h @@ -8,7 +8,8 @@ #include <boost/shared_ptr.hpp> - #include <string> +#include <Swiften/Base/API.h> + namespace Swift { class DomainNameServiceQuery; @@ -16,9 +17,9 @@ namespace Swift { - class DomainNameResolver { + class SWIFTEN_API DomainNameResolver { public: virtual ~DomainNameResolver(); - virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name) = 0; + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) = 0; virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name) = 0; }; diff --git a/Swiften/Network/DomainNameServiceQuery.cpp b/Swiften/Network/DomainNameServiceQuery.cpp index da1e1ab..5e87295 100644 --- a/Swiften/Network/DomainNameServiceQuery.cpp +++ b/Swiften/Network/DomainNameServiceQuery.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,6 +14,10 @@ #include <Swiften/Base/RandomGenerator.h> #include <boost/numeric/conversion/cast.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> +#include <boost/typeof/typeof.hpp> using namespace Swift; +namespace lambda = boost::lambda; namespace { @@ -23,12 +27,4 @@ namespace { } }; - - struct GetWeight { - GetWeight() {} - - int operator()(const DomainNameServiceQuery::Result& result) { - return result.weight + 1 /* easy hack to account for '0' weights getting at least some weight */; - } - }; } @@ -40,5 +36,5 @@ DomainNameServiceQuery::~DomainNameServiceQuery() { void DomainNameServiceQuery::sortResults(std::vector<DomainNameServiceQuery::Result>& queries, RandomGenerator& generator) { ResultPriorityComparator comparator; - std::sort(queries.begin(), queries.end(), comparator); + std::stable_sort(queries.begin(), queries.end(), comparator); std::vector<DomainNameServiceQuery::Result>::iterator i = queries.begin(); @@ -47,10 +43,15 @@ void DomainNameServiceQuery::sortResults(std::vector<DomainNameServiceQuery::Res if (std::distance(i, next) > 1) { std::vector<int> weights; - std::transform(i, next, std::back_inserter(weights), GetWeight()); - for (size_t j = 0; j < weights.size() - 1; ++j) { + std::transform(i, next, std::back_inserter(weights), + /* easy hack to account for '0' weights getting at least some weight */ + lambda::bind(&Result::weight, lambda::_1) + 1); + for (int j = 0; j < boost::numeric_cast<int>(weights.size() - 1); ++j) { std::vector<int> cumulativeWeights; - std::partial_sum(weights.begin() + j, weights.end(), std::back_inserter(cumulativeWeights)); + std::partial_sum( + weights.begin() + j, + weights.end(), + std::back_inserter(cumulativeWeights)); int randomNumber = generator.generateRandomInteger(cumulativeWeights.back()); - int selectedIndex = std::lower_bound(cumulativeWeights.begin(), cumulativeWeights.end(), randomNumber) - cumulativeWeights.begin(); + BOOST_AUTO(selectedIndex, std::lower_bound(cumulativeWeights.begin(), cumulativeWeights.end(), randomNumber) - cumulativeWeights.begin()); std::swap(i[j], i[j + selectedIndex]); std::swap(weights.begin()[j], weights.begin()[j + selectedIndex]); diff --git a/Swiften/Network/DomainNameServiceQuery.h b/Swiften/Network/DomainNameServiceQuery.h index 0e80233..fdf5b5d 100644 --- a/Swiften/Network/DomainNameServiceQuery.h +++ b/Swiften/Network/DomainNameServiceQuery.h @@ -13,4 +13,5 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Network/DomainNameResolveError.h> @@ -18,5 +19,5 @@ namespace Swift { class RandomGenerator; - class DomainNameServiceQuery { + class SWIFTEN_API DomainNameServiceQuery { public: typedef boost::shared_ptr<DomainNameServiceQuery> ref; diff --git a/Swiften/Network/DummyConnection.h b/Swiften/Network/DummyConnection.h index 5191e30..36bf897 100644 --- a/Swiften/Network/DummyConnection.h +++ b/Swiften/Network/DummyConnection.h @@ -9,4 +9,5 @@ #include <boost/enable_shared_from_this.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/HostAddressPort.h> @@ -15,5 +16,5 @@ namespace Swift { - class DummyConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<DummyConnection> { + class SWIFTEN_API DummyConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<DummyConnection> { public: DummyConnection(EventLoop* eventLoop); diff --git a/Swiften/Network/DummyTimerFactory.h b/Swiften/Network/DummyTimerFactory.h index 0c49f3d..1e9413b 100644 --- a/Swiften/Network/DummyTimerFactory.h +++ b/Swiften/Network/DummyTimerFactory.h @@ -9,8 +9,9 @@ #include <list> +#include <Swiften/Base/API.h> #include <Swiften/Network/TimerFactory.h> namespace Swift { - class DummyTimerFactory : public TimerFactory { + class SWIFTEN_API DummyTimerFactory : public TimerFactory { public: class DummyTimer; diff --git a/Swiften/Network/FakeConnection.cpp b/Swiften/Network/FakeConnection.cpp index be5555c..a84c92e 100644 --- a/Swiften/Network/FakeConnection.cpp +++ b/Swiften/Network/FakeConnection.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -44,5 +44,5 @@ void FakeConnection::connect(const HostAddressPort& address) { } eventLoop->postEvent( - boost::bind(boost::ref(onConnectFinished), error), + boost::bind(boost::ref(onConnectFinished), error ? true : false), shared_from_this()); } diff --git a/Swiften/Network/FakeConnection.h b/Swiften/Network/FakeConnection.h index 99cb584..eca45da 100644 --- a/Swiften/Network/FakeConnection.h +++ b/Swiften/Network/FakeConnection.h @@ -11,4 +11,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/HostAddressPort.h> @@ -17,5 +18,5 @@ namespace Swift { - class FakeConnection : + class SWIFTEN_API FakeConnection : public Connection, public EventOwner, diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp index 512381f..a88ded1 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -16,5 +16,4 @@ #include <iostream> #include <boost/bind.hpp> -#include <boost/thread.hpp> #include <boost/lexical_cast.hpp> @@ -25,69 +24,25 @@ #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Network/ConnectionFactory.h> -#include <Swiften/Network/CachingNameOnlyDomainNameResolver.h> #include <Swiften/StringCodecs/Base64.h> using namespace Swift; -HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) : connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)), authID_(authID), authPassword_(authPassword) { - resolver_ = new CachingNameOnlyDomainNameResolver(resolver, eventLoop); - connected_ = false; +HTTPConnectProxiedConnection::HTTPConnectProxiedConnection( + DomainNameResolver* resolver, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + const std::string& proxyHost, + int proxyPort, + const SafeString& authID, + const SafeString& authPassword) : + ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort), + authID_(authID), + authPassword_(authPassword) { } -HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { - cancelConnector(); - delete resolver_; - if (connection_) { - connection_->onDataRead.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); - } - - if (connected_) { - std::cerr << "Warning: Connection was still established." << std::endl; - } -} - -void HTTPConnectProxiedConnection::cancelConnector() { - if (connector_) { - connector_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectFinished, shared_from_this(), _1)); - connector_->stop(); - connector_.reset(); - } -} - -void HTTPConnectProxiedConnection::connect(const HostAddressPort& server) { - server_ = server; - connector_ = Connector::create(proxyHost_, resolver_, connectionFactory_, timerFactory_, proxyPort_); - connector_->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnection::handleConnectFinished, shared_from_this(), _1)); - connector_->start(); -} - -void HTTPConnectProxiedConnection::listen() { - assert(false); - connection_->listen(); -} - -void HTTPConnectProxiedConnection::disconnect() { - connected_ = false; - connection_->disconnect(); -} - -void HTTPConnectProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { - onDisconnected(error); -} - -void HTTPConnectProxiedConnection::write(const SafeByteArray& data) { - connection_->write(data); -} - -void HTTPConnectProxiedConnection::handleConnectFinished(Connection::ref connection) { - cancelConnector(); - if (connection) { - connection_ = connection; - connection_->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); +void HTTPConnectProxiedConnection::initializeProxy() { std::stringstream connect; - connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n"; + connect << "CONNECT " << getServer().getAddress().toString() << ":" << getServer().getPort() << " HTTP/1.1\r\n"; SafeByteArray data = createSafeByteArray(connect.str()); if (!authID_.empty() && !authPassword_.empty()) { @@ -101,34 +56,29 @@ void HTTPConnectProxiedConnection::handleConnectFinished(Connection::ref connect append(data, createSafeByteArray("\r\n")); SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl; - connection_->write(data); - } - else { - onConnectFinished(true); - } + write(data); } -void HTTPConnectProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { - if (!connected_) { +void HTTPConnectProxiedConnection::handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) { SWIFT_LOG(debug) << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl; std::vector<std::string> tmp = String::split(byteArrayToString(ByteArray(data->begin(), data->end())), ' '); if (tmp.size() > 1) { - int status = boost::lexical_cast<int> (tmp[1].c_str()); + try { + int status = boost::lexical_cast<int>(tmp[1]); SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl; if (status / 100 == 2) { // all 2XX states are OK - connected_ = true; - onConnectFinished(false); - return; + setProxyInitializeFinished(true); } + else { SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl; + setProxyInitializeFinished(false); } - disconnect(); - onConnectFinished(true); } - else { - onDataRead(data); + catch (boost::bad_lexical_cast&) { + SWIFT_LOG(warning) << "Unexpected response: " << tmp[1] << std::endl; + setProxyInitializeFinished(false); } } - -HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const { - return connection_->getLocalAddress(); + else { + setProxyInitializeFinished(false); + } } diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h index 8318ecc..c209dc1 100644 --- a/Swiften/Network/HTTPConnectProxiedConnection.h +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -14,58 +14,30 @@ #pragma once -#include <boost/enable_shared_from_this.hpp> - -#include <Swiften/Network/Connection.h> -#include <Swiften/Network/Connector.h> -#include <Swiften/Network/HostAddressPort.h> -#include <Swiften/Base/SafeString.h> - -namespace boost { - class thread; - namespace system { - class error_code; - } -} +#include <Swiften/Base/API.h> +#include <Swiften/Network/ProxiedConnection.h> namespace Swift { + class DomainNameResolver; class ConnectionFactory; class EventLoop; + class TimerFactory; - class HTTPConnectProxiedConnection : public Connection, public boost::enable_shared_from_this<HTTPConnectProxiedConnection> { + class SWIFTEN_API HTTPConnectProxiedConnection : public ProxiedConnection { public: typedef boost::shared_ptr<HTTPConnectProxiedConnection> ref; - ~HTTPConnectProxiedConnection(); - - static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) { - return ref(new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, eventLoop, proxyHost, proxyPort, authID, authPassword)); + static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) { + return ref(new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, authID, authPassword)); } - virtual void listen(); - virtual void connect(const HostAddressPort& address); - virtual void disconnect(); - virtual void write(const SafeByteArray& data); - - virtual HostAddressPort getLocalAddress() const; private: - HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); + HTTPConnectProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); - void handleConnectFinished(Connection::ref connection); - void handleDataRead(boost::shared_ptr<SafeByteArray> data); - void handleDisconnected(const boost::optional<Error>& error); - void cancelConnector(); + virtual void initializeProxy(); + virtual void handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data); private: - bool connected_; - DomainNameResolver* resolver_; - ConnectionFactory* connectionFactory_; - TimerFactory* timerFactory_; - std::string proxyHost_; - int proxyPort_; - HostAddressPort server_; SafeByteArray authID_; SafeByteArray authPassword_; - Connector::ref connector_; - boost::shared_ptr<Connection> connection_; }; } diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp index 14d702c..cf4cef5 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp @@ -17,13 +17,13 @@ namespace Swift { -HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), eventLoop_(eventLoop), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), authPassword_("") { +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(""), authPassword_("") { } -HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), eventLoop_(eventLoop), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword) { +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort), authID_(authID), authPassword_(authPassword) { } boost::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() { - return HTTPConnectProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, eventLoop_, proxyHost_, proxyPort_, authID_, authPassword_); + return HTTPConnectProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_, authID_, authPassword_); } diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h index 7d003e8..3efcecd 100644 --- a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h @@ -23,6 +23,6 @@ namespace Swift { class HTTPConnectProxiedConnectionFactory : public ConnectionFactory { public: - HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort); - HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); + HTTPConnectProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort, const SafeString& authID, const SafeString& authPassword); virtual boost::shared_ptr<Connection> createConnection(); @@ -32,5 +32,4 @@ namespace Swift { ConnectionFactory* connectionFactory_; TimerFactory* timerFactory_; - EventLoop* eventLoop_; std::string proxyHost_; int proxyPort_; diff --git a/Swiften/Network/HostAddress.cpp b/Swiften/Network/HostAddress.cpp index f00581f..ff5c1c4 100644 --- a/Swiften/Network/HostAddress.cpp +++ b/Swiften/Network/HostAddress.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,4 +16,7 @@ #include <string> +static boost::asio::ip::address localhost4 = boost::asio::ip::address(boost::asio::ip::address_v4::loopback()); +static boost::asio::ip::address localhost6 = boost::asio::ip::address(boost::asio::ip::address_v6::loopback()); + namespace Swift { @@ -29,9 +32,9 @@ HostAddress::HostAddress(const std::string& address) { } -HostAddress::HostAddress(const unsigned char* address, int length) { +HostAddress::HostAddress(const unsigned char* address, size_t length) { assert(length == 4 || length == 16); if (length == 4) { boost::asio::ip::address_v4::bytes_type data; - for (int i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { data[i] = address[i]; } @@ -40,5 +43,5 @@ HostAddress::HostAddress(const unsigned char* address, int length) { else { boost::asio::ip::address_v6::bytes_type data; - for (int i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { data[i] = address[i]; } @@ -62,3 +65,7 @@ boost::asio::ip::address HostAddress::getRawAddress() const { } +bool HostAddress::isLocalhost() const { + return address_ == localhost4 || address_ == localhost6; +} + } diff --git a/Swiften/Network/HostAddress.h b/Swiften/Network/HostAddress.h index 0b3bdda..c62239b 100644 --- a/Swiften/Network/HostAddress.h +++ b/Swiften/Network/HostAddress.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,10 +9,12 @@ #include <boost/asio/ip/address.hpp> +#include <Swiften/Base/API.h> + namespace Swift { - class HostAddress { + class SWIFTEN_API HostAddress { public: HostAddress(); HostAddress(const std::string&); - HostAddress(const unsigned char* address, int length); + HostAddress(const unsigned char* address, size_t length); HostAddress(const boost::asio::ip::address& address); @@ -25,4 +27,5 @@ namespace Swift { bool isValid() const; + bool isLocalhost() const; private: diff --git a/Swiften/Network/HostAddressPort.h b/Swiften/Network/HostAddressPort.h index e3c0413..68f3a1c 100644 --- a/Swiften/Network/HostAddressPort.h +++ b/Swiften/Network/HostAddressPort.h @@ -9,8 +9,9 @@ #include <boost/asio/ip/tcp.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/HostAddress.h> namespace Swift { - class HostAddressPort { + class SWIFTEN_API HostAddressPort { public: HostAddressPort(const HostAddress& address = HostAddress(), int port = -1); diff --git a/Swiften/Network/HostNameOrAddress.cpp b/Swiften/Network/HostNameOrAddress.cpp new file mode 100644 index 0000000..bc2737d --- /dev/null +++ b/Swiften/Network/HostNameOrAddress.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/HostNameOrAddress.h> + +using namespace Swift; + +namespace { + struct ToStringVisitor : public boost::static_visitor<std::string> { + std::string operator()(const HostAddress& address) const { + return address.toString(); + } + + std::string operator()(const std::string & str) const { + return str; + } + }; +} + +namespace Swift { + +std::string toString(const HostNameOrAddress& address) { + return boost::apply_visitor(ToStringVisitor(), address); +} + +} diff --git a/Swiften/Network/HostNameOrAddress.h b/Swiften/Network/HostNameOrAddress.h new file mode 100644 index 0000000..f804d15 --- /dev/null +++ b/Swiften/Network/HostNameOrAddress.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ +#pragma once + +#include <string> +#include <Swiften/Network/HostAddress.h> +#include <boost/variant.hpp> + +namespace Swift { + typedef boost::variant<std::string, HostAddress> HostNameOrAddress; + + std::string toString(const HostNameOrAddress& address); +} diff --git a/Swiften/Network/MacOSXProxyProvider.cpp b/Swiften/Network/MacOSXProxyProvider.cpp index eaadd28..3456c73 100644 --- a/Swiften/Network/MacOSXProxyProvider.cpp +++ b/Swiften/Network/MacOSXProxyProvider.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + #include <Swiften/Base/Platform.h> #include <Swiften/Network/MacOSXProxyProvider.h> @@ -11,4 +17,5 @@ #include <stdlib.h> #include <iostream> +#include <boost/numeric/conversion/cast.hpp> #include <utility> @@ -17,4 +24,6 @@ #endif +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" + using namespace Swift; @@ -28,5 +37,5 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl CFNumberRef zero = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i); CFComparisonResult result = CFNumberCompare(numberValue, zero, NULL); - CFRelease(numberValue); + CFRelease(zero); if(result != kCFCompareEqualTo) { @@ -38,5 +47,4 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl if(numberValue != NULL) { CFNumberGetValue(numberValue, kCFNumberIntType, &port); - CFRelease(numberValue); } @@ -47,5 +55,5 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl // if the string is toby the length must be at least 5. CFIndex length = CFStringGetLength(stringValue) + 1; - buffer.resize(length); + buffer.resize(boost::numeric_cast<size_t>(length)); if(CFStringGetCString(stringValue, &buffer[0], length, kCFStringEncodingMacRoman)) { for(std::vector<char>::iterator iter = buffer.begin(); iter != buffer.end(); ++iter) { @@ -53,5 +61,4 @@ static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabl } } - CFRelease(stringValue); } } @@ -79,4 +86,5 @@ HostAddressPort MacOSXProxyProvider::getHTTPConnectProxy() const { if(proxies != NULL) { result = getFromDictionary(proxies, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort); + CFRelease(proxies); } #endif @@ -90,4 +98,5 @@ HostAddressPort MacOSXProxyProvider::getSOCKS5Proxy() const { if(proxies != NULL) { result = getFromDictionary(proxies, kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort); + CFRelease(proxies); } #endif diff --git a/Swiften/Network/MiniUPnPInterface.cpp b/Swiften/Network/MiniUPnPInterface.cpp index c9f682f..bfa989f 100644 --- a/Swiften/Network/MiniUPnPInterface.cpp +++ b/Swiften/Network/MiniUPnPInterface.cpp @@ -7,6 +7,8 @@ #include <Swiften/Network/MiniUPnPInterface.h> +#include <miniupnpc.h> #include <upnpcommands.h> #include <upnperrors.h> +#include <boost/smart_ptr/make_shared.hpp> #include <boost/lexical_cast.hpp> @@ -15,32 +17,41 @@ namespace Swift { -MiniUPnPInterface::MiniUPnPInterface() : isValid(false) { +struct MiniUPnPInterface::Private { + bool isValid; + std::string localAddress; + UPNPDev* deviceList; + UPNPUrls urls; + IGDdatas data; +}; + +MiniUPnPInterface::MiniUPnPInterface() : p(boost::make_shared<Private>()) { + p->isValid = false; int error = 0; - deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); - if (!deviceList) { + p->deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); + if (!p->deviceList) { return; } char lanAddress[64]; - if (!UPNP_GetValidIGD(deviceList, &urls, &data, lanAddress, sizeof(lanAddress))) { + if (!UPNP_GetValidIGD(p->deviceList, &p->urls, &p->data, lanAddress, sizeof(lanAddress))) { return; } - localAddress = std::string(lanAddress); - isValid = true; + p->localAddress = std::string(lanAddress); + p->isValid = true; } MiniUPnPInterface::~MiniUPnPInterface() { - if (isValid) { - FreeUPNPUrls(&urls); + if (p->isValid) { + FreeUPNPUrls(&p->urls); } - freeUPNPDevlist(deviceList); + freeUPNPDevlist(p->deviceList); } boost::optional<HostAddress> MiniUPnPInterface::getPublicIP() { - if (!isValid) { + if (!p->isValid) { return boost::optional<HostAddress>(); } char externalIPAddress[40]; - int ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); + int ret = UPNP_GetExternalIPAddress(p->urls.controlURL, p->data.first.servicetype, externalIPAddress); if (ret != UPNPCOMMAND_SUCCESS) { return boost::optional<HostAddress>(); @@ -52,5 +63,5 @@ boost::optional<HostAddress> MiniUPnPInterface::getPublicIP() { boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLocalPort, int actualPublicPort) { - if (!isValid) { + if (!p->isValid) { return boost::optional<NATPortMapping>(); } @@ -62,5 +73,14 @@ boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLoca std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.getLeaseInSeconds()); - int ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), localPort.c_str(), localAddress.c_str(), 0, mapping.getPublicPort() == NATPortMapping::TCP ? "TCP" : "UDP", 0, leaseSeconds.c_str()); + int ret = UPNP_AddPortMapping( + p->urls.controlURL, + p->data.first.servicetype, + publicPort.c_str(), + localPort.c_str(), + p->localAddress.c_str(), + 0, + mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", + 0, + leaseSeconds.c_str()); if (ret == UPNPCOMMAND_SUCCESS) { return mapping; @@ -72,5 +92,5 @@ boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLoca bool MiniUPnPInterface::removePortForward(const NATPortMapping& mapping) { - if (!isValid) { + if (!p->isValid) { return false; } @@ -80,7 +100,11 @@ bool MiniUPnPInterface::removePortForward(const NATPortMapping& mapping) { std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.getLeaseInSeconds()); - int ret = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", 0); + int ret = UPNP_DeletePortMapping(p->urls.controlURL, p->data.first.servicetype, publicPort.c_str(), mapping.getProtocol() == NATPortMapping::TCP ? "TCP" : "UDP", 0); return ret == UPNPCOMMAND_SUCCESS; } +bool MiniUPnPInterface::isAvailable() { + return p->isValid; +} + } diff --git a/Swiften/Network/MiniUPnPInterface.h b/Swiften/Network/MiniUPnPInterface.h index ae9be66..61d12ca 100644 --- a/Swiften/Network/MiniUPnPInterface.h +++ b/Swiften/Network/MiniUPnPInterface.h @@ -8,5 +8,6 @@ #include <boost/optional.hpp> -#include <miniupnpc.h> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> #include <Swiften/Network/NATPortMapping.h> @@ -14,12 +15,10 @@ namespace Swift { - class MiniUPnPInterface : public NATTraversalInterface { + class MiniUPnPInterface : public NATTraversalInterface, boost::noncopyable { public: MiniUPnPInterface(); ~MiniUPnPInterface(); - virtual bool isAvailable() { - return isValid; - } + virtual bool isAvailable(); boost::optional<HostAddress> getPublicIP(); @@ -28,9 +27,6 @@ namespace Swift { private: - bool isValid; - std::string localAddress; - UPNPDev* deviceList; - UPNPUrls urls; - IGDdatas data; + struct Private; + boost::shared_ptr<Private> p; }; } diff --git a/Swiften/Network/NATPMPInterface.cpp b/Swiften/Network/NATPMPInterface.cpp index 36553ed..dcae641 100644 --- a/Swiften/Network/NATPMPInterface.cpp +++ b/Swiften/Network/NATPMPInterface.cpp @@ -5,26 +5,43 @@ */ +/* +* Copyright (c) 2014 Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + #include <Swiften/Network/NATPMPInterface.h> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + #include <Swiften/Base/Log.h> +// This has to be included after the previous headers, because of WIN32 macro +// being defined somewhere. +#include <natpmp.h> + #pragma GCC diagnostic ignored "-Wold-style-cast" namespace Swift { -NATPMPInterface::NATPMPInterface() { - initnatpmp(&natpmp, 0, 0); +struct NATPMPInterface::Private { + natpmp_t natpmp; +}; + +NATPMPInterface::NATPMPInterface() : p(boost::make_shared<Private>()) { + initnatpmp(&p->natpmp, 0, 0); } NATPMPInterface::~NATPMPInterface() { - closenatpmp(&natpmp); + closenatpmp(&p->natpmp); } bool NATPMPInterface::isAvailable() { - return getPublicIP(); + return getPublicIP() ? true : false; } boost::optional<HostAddress> NATPMPInterface::getPublicIP() { - if (sendpublicaddressrequest(&natpmp) < 0) { + if (sendpublicaddressrequest(&p->natpmp) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl; return boost::optional<HostAddress>(); @@ -37,8 +54,8 @@ boost::optional<HostAddress> NATPMPInterface::getPublicIP() { struct timeval timeout; FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); + FD_SET(p->natpmp.s, &fds); + getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); + r = readnatpmpresponseorretry(&p->natpmp, &response); } while (r == NATPMP_TRYAGAIN); @@ -54,5 +71,10 @@ boost::optional<HostAddress> NATPMPInterface::getPublicIP() { boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, int publicPort) { NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); - if (sendnewportmappingrequest(&natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, mapping.getLeaseInSeconds(), mapping.getPublicPort(), mapping.getLocalPort()) < 0) { + if (sendnewportmappingrequest( + &p->natpmp, + mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, + boost::numeric_cast<uint16_t>(mapping.getLocalPort()), + boost::numeric_cast<uint16_t>(mapping.getPublicPort()), + boost::numeric_cast<uint32_t>(mapping.getLeaseInSeconds())) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl; return boost::optional<NATPortMapping>(); @@ -65,12 +87,12 @@ boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, i struct timeval timeout; FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); + FD_SET(p->natpmp.s, &fds); + getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); + r = readnatpmpresponseorretry(&p->natpmp, &response); } while(r == NATPMP_TRYAGAIN); if (r == 0) { - NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, response.pnu.newportmapping.lifetime); + NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, boost::numeric_cast<int>(response.pnu.newportmapping.lifetime)); return result; } @@ -82,5 +104,5 @@ boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, i bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { - if (sendnewportmappingrequest(&natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, mapping.getLocalPort()) < 0) { + if (sendnewportmappingrequest(&p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, boost::numeric_cast<uint32_t>(mapping.getLocalPort())) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl; return false; @@ -93,8 +115,8 @@ bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { struct timeval timeout; FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); + FD_SET(p->natpmp.s, &fds); + getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); + r = readnatpmpresponseorretry(&p->natpmp, &response); } while(r == NATPMP_TRYAGAIN); diff --git a/Swiften/Network/NATPMPInterface.h b/Swiften/Network/NATPMPInterface.h index 6e7fb73..e079a59 100644 --- a/Swiften/Network/NATPMPInterface.h +++ b/Swiften/Network/NATPMPInterface.h @@ -8,13 +8,11 @@ #include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> #include <Swiften/Network/NATPortMapping.h> #include <Swiften/Network/NATTraversalInterface.h> -// This has to be included after the previous headers, because of WIN32 macro -// being defined somewhere. -#include <natpmp.h> - namespace Swift { - class NATPMPInterface : public NATTraversalInterface { + class NATPMPInterface : public NATTraversalInterface, boost::noncopyable { public: NATPMPInterface(); @@ -28,5 +26,6 @@ namespace Swift { private: - natpmp_t natpmp; + struct Private; + boost::shared_ptr<Private> p; }; } diff --git a/Swiften/Network/NATPortMapping.h b/Swiften/Network/NATPortMapping.h index db14500..0f6bd95 100644 --- a/Swiften/Network/NATPortMapping.h +++ b/Swiften/Network/NATPortMapping.h @@ -14,8 +14,9 @@ namespace Swift { enum Protocol { TCP, - UDP, + UDP }; - NATPortMapping(int localPort, int publicPort, Protocol protocol = TCP, int leaseInSeconds = 60 * 60 * 24) : publicPort(publicPort), localPort(localPort), protocol(protocol), leaseInSeconds(leaseInSeconds) { + NATPortMapping(int localPort, int publicPort, Protocol protocol = TCP, int leaseInSeconds = 60 * 60 * 24) : + publicPort(publicPort), localPort(localPort), protocol(protocol), leaseInSeconds(leaseInSeconds) { } diff --git a/Swiften/Network/NATTraversalForwardPortRequest.h b/Swiften/Network/NATTraversalForwardPortRequest.h index 1bbc9ca..48f85ea 100644 --- a/Swiften/Network/NATTraversalForwardPortRequest.h +++ b/Swiften/Network/NATTraversalForwardPortRequest.h @@ -9,12 +9,14 @@ #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> #include <Swiften/Network/NATPortMapping.h> namespace Swift { - class NATTraversalForwardPortRequest { + class SWIFTEN_API NATTraversalForwardPortRequest { public: virtual ~NATTraversalForwardPortRequest(); - virtual void run() = 0; + virtual void start() = 0; + virtual void stop() = 0; boost::signal<void (boost::optional<NATPortMapping>)> onResult; diff --git a/Swiften/Network/NATTraversalGetPublicIPRequest.h b/Swiften/Network/NATTraversalGetPublicIPRequest.h index db1f005..1270db3 100644 --- a/Swiften/Network/NATTraversalGetPublicIPRequest.h +++ b/Swiften/Network/NATTraversalGetPublicIPRequest.h @@ -15,5 +15,6 @@ namespace Swift { virtual ~NATTraversalGetPublicIPRequest(); - virtual void run() = 0; + virtual void start() = 0; + virtual void stop() = 0; boost::signal<void (boost::optional<HostAddress>)> onResult; diff --git a/Swiften/Network/NATTraversalRemovePortForwardingRequest.h b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h index cf349b1..210cbcb 100644 --- a/Swiften/Network/NATTraversalRemovePortForwardingRequest.h +++ b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h @@ -16,5 +16,5 @@ namespace Swift { enum Protocol { TCP, - UDP, + UDP }; @@ -28,5 +28,6 @@ namespace Swift { virtual ~NATTraversalRemovePortForwardingRequest(); - virtual void run() = 0; + virtual void start() = 0; + virtual void stop() = 0; boost::signal<void (boost::optional<bool> /* failure */)> onResult; diff --git a/Swiften/Network/NetworkEnvironment.h b/Swiften/Network/NetworkEnvironment.h index fbff0cb..36a2bde 100644 --- a/Swiften/Network/NetworkEnvironment.h +++ b/Swiften/Network/NetworkEnvironment.h @@ -9,9 +9,10 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/NetworkInterface.h> namespace Swift { - class NetworkEnvironment { + class SWIFTEN_API NetworkEnvironment { public: virtual ~NetworkEnvironment(); diff --git a/Swiften/Network/NetworkFactories.h b/Swiften/Network/NetworkFactories.h index c8009a6..dd8e216 100644 --- a/Swiften/Network/NetworkFactories.h +++ b/Swiften/Network/NetworkFactories.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,4 +18,7 @@ namespace Swift { class ProxyProvider; class EventLoop; + class IDNConverter; + class NetworkEnvironment; + class CryptoProvider; /** @@ -31,8 +34,11 @@ namespace Swift { virtual ConnectionServerFactory* getConnectionServerFactory() const = 0; virtual NATTraverser* getNATTraverser() const = 0; + virtual NetworkEnvironment* getNetworkEnvironment() const = 0; virtual XMLParserFactory* getXMLParserFactory() const = 0; virtual TLSContextFactory* getTLSContextFactory() const = 0; virtual ProxyProvider* getProxyProvider() const = 0; virtual EventLoop* getEventLoop() const = 0; + virtual IDNConverter* getIDNConverter() const = 0; + virtual CryptoProvider* getCryptoProvider() const = 0; }; } diff --git a/Swiften/Network/NullNATTraverser.cpp b/Swiften/Network/NullNATTraverser.cpp index 8cb35cd..43fcd08 100644 --- a/Swiften/Network/NullNATTraverser.cpp +++ b/Swiften/Network/NullNATTraverser.cpp @@ -22,8 +22,11 @@ class NullNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest } - virtual void run() { + virtual void start() { eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<HostAddress>())); } + virtual void stop() { + } + private: EventLoop* eventLoop; @@ -35,8 +38,11 @@ class NullNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest } - virtual void run() { + virtual void start() { eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<NATPortMapping>())); } + virtual void stop() { + } + private: EventLoop* eventLoop; @@ -48,8 +54,11 @@ class NullNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePor } - virtual void run() { + virtual void start() { eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<bool>(true))); } + virtual void stop() { + } + private: EventLoop* eventLoop; diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.cpp b/Swiften/Network/PlatformDomainNameAddressQuery.cpp index ec7e663..91d15b9 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.cpp +++ b/Swiften/Network/PlatformDomainNameAddressQuery.cpp @@ -14,5 +14,9 @@ namespace Swift { -PlatformDomainNameAddressQuery::PlatformDomainNameAddressQuery(const std::string& host, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), hostname(host), eventLoop(eventLoop) { +PlatformDomainNameAddressQuery::PlatformDomainNameAddressQuery(const boost::optional<std::string>& host, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), hostnameValid(false), eventLoop(eventLoop) { + if (!!host) { + hostname = *host; + hostnameValid = true; + } } @@ -22,4 +26,8 @@ void PlatformDomainNameAddressQuery::run() { void PlatformDomainNameAddressQuery::runBlocking() { + if (!hostnameValid) { + emitError(); + return; + } //std::cout << "PlatformDomainNameResolver::doRun()" << std::endl; boost::asio::ip::tcp::resolver resolver(ioService); diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.h b/Swiften/Network/PlatformDomainNameAddressQuery.h index e1dc05f..9e89086 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.h +++ b/Swiften/Network/PlatformDomainNameAddressQuery.h @@ -21,5 +21,5 @@ namespace Swift { class PlatformDomainNameAddressQuery : public DomainNameAddressQuery, public PlatformDomainNameQuery, public boost::enable_shared_from_this<PlatformDomainNameAddressQuery>, public EventOwner { public: - PlatformDomainNameAddressQuery(const std::string& host, EventLoop* eventLoop, PlatformDomainNameResolver*); + PlatformDomainNameAddressQuery(const boost::optional<std::string>& host, EventLoop* eventLoop, PlatformDomainNameResolver*); void run(); @@ -32,4 +32,5 @@ namespace Swift { boost::asio::io_service ioService; std::string hostname; + bool hostnameValid; EventLoop* eventLoop; }; diff --git a/Swiften/Network/PlatformDomainNameResolver.cpp b/Swiften/Network/PlatformDomainNameResolver.cpp index 63f7404..b65e884 100644 --- a/Swiften/Network/PlatformDomainNameResolver.cpp +++ b/Swiften/Network/PlatformDomainNameResolver.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ #include <string> -#include <Swiften/IDN/IDNA.h> +#include <Swiften/IDN/IDNConverter.h> #include <Swiften/Network/HostAddress.h> #include <Swiften/EventLoop/EventLoop.h> @@ -28,5 +28,5 @@ using namespace Swift; namespace Swift { -PlatformDomainNameResolver::PlatformDomainNameResolver(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false) { +PlatformDomainNameResolver::PlatformDomainNameResolver(IDNConverter* idnConverter, EventLoop* eventLoop) : idnConverter(idnConverter), eventLoop(eventLoop), stopRequested(false) { thread = new boost::thread(boost::bind(&PlatformDomainNameResolver::run, this)); } @@ -39,10 +39,15 @@ PlatformDomainNameResolver::~PlatformDomainNameResolver() { } -boost::shared_ptr<DomainNameServiceQuery> PlatformDomainNameResolver::createServiceQuery(const std::string& name) { - return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(IDNA::getEncoded(name), eventLoop, this)); +boost::shared_ptr<DomainNameServiceQuery> PlatformDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + boost::optional<std::string> encodedDomain = idnConverter->getIDNAEncoded(domain); + std::string result; + if (encodedDomain) { + result = serviceLookupPrefix + *encodedDomain; + } + return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(result, eventLoop, this)); } boost::shared_ptr<DomainNameAddressQuery> PlatformDomainNameResolver::createAddressQuery(const std::string& name) { - return boost::shared_ptr<DomainNameAddressQuery>(new PlatformDomainNameAddressQuery(IDNA::getEncoded(name), eventLoop, this)); + return boost::shared_ptr<DomainNameAddressQuery>(new PlatformDomainNameAddressQuery(idnConverter->getIDNAEncoded(name), eventLoop, this)); } diff --git a/Swiften/Network/PlatformDomainNameResolver.h b/Swiften/Network/PlatformDomainNameResolver.h index 295ecc5..6c3bf10 100644 --- a/Swiften/Network/PlatformDomainNameResolver.h +++ b/Swiften/Network/PlatformDomainNameResolver.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,4 +12,5 @@ #include <boost/thread/condition_variable.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/DomainNameResolver.h> #include <Swiften/Network/PlatformDomainNameQuery.h> @@ -18,13 +19,13 @@ namespace Swift { - + class IDNConverter; class EventLoop; - class PlatformDomainNameResolver : public DomainNameResolver { + class SWIFTEN_API PlatformDomainNameResolver : public DomainNameResolver { public: - PlatformDomainNameResolver(EventLoop* eventLoop); + PlatformDomainNameResolver(IDNConverter* idnConverter, EventLoop* eventLoop); ~PlatformDomainNameResolver(); - virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& name); + virtual DomainNameServiceQuery::ref createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); virtual DomainNameAddressQuery::ref createAddressQuery(const std::string& name); @@ -36,4 +37,5 @@ namespace Swift { friend class PlatformDomainNameServiceQuery; friend class PlatformDomainNameAddressQuery; + IDNConverter* idnConverter; EventLoop* eventLoop; bool stopRequested; diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.cpp b/Swiften/Network/PlatformDomainNameServiceQuery.cpp index b0579a7..58cf8d2 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.cpp +++ b/Swiften/Network/PlatformDomainNameServiceQuery.cpp @@ -13,4 +13,5 @@ #include <Swiften/Base/Platform.h> #include <stdlib.h> +#include <boost/numeric/conversion/cast.hpp> #ifdef SWIFTEN_PLATFORM_WINDOWS #undef UNICODE @@ -38,5 +39,9 @@ using namespace Swift; namespace Swift { -PlatformDomainNameServiceQuery::PlatformDomainNameServiceQuery(const std::string& service, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), eventLoop(eventLoop), service(service) { +PlatformDomainNameServiceQuery::PlatformDomainNameServiceQuery(const boost::optional<std::string>& serviceName, EventLoop* eventLoop, PlatformDomainNameResolver* resolver) : PlatformDomainNameQuery(resolver), eventLoop(eventLoop), serviceValid(false) { + if (!!serviceName) { + service = *serviceName; + serviceValid = true; + } } @@ -46,4 +51,9 @@ void PlatformDomainNameServiceQuery::run() { void PlatformDomainNameServiceQuery::runBlocking() { + if (!serviceValid) { + emitError(); + return; + } + SWIFT_LOG(debug) << "Querying " << service << std::endl; @@ -122,5 +132,5 @@ void PlatformDomainNameServiceQuery::runBlocking() { return; } - record.priority = ns_get16(currentEntry); + record.priority = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; @@ -130,5 +140,5 @@ void PlatformDomainNameServiceQuery::runBlocking() { return; } - record.weight = ns_get16(currentEntry); + record.weight = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; @@ -138,5 +148,5 @@ void PlatformDomainNameServiceQuery::runBlocking() { return; } - record.port = ns_get16(currentEntry); + record.port = boost::numeric_cast<int>(ns_get16(currentEntry)); currentEntry += 2; diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.h b/Swiften/Network/PlatformDomainNameServiceQuery.h index 3372517..e105479 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.h +++ b/Swiften/Network/PlatformDomainNameServiceQuery.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { class PlatformDomainNameServiceQuery : public DomainNameServiceQuery, public PlatformDomainNameQuery, public boost::enable_shared_from_this<PlatformDomainNameServiceQuery>, public EventOwner { public: - PlatformDomainNameServiceQuery(const std::string& service, EventLoop* eventLoop, PlatformDomainNameResolver* resolver); + PlatformDomainNameServiceQuery(const boost::optional<std::string>& serviceName, EventLoop* eventLoop, PlatformDomainNameResolver* resolver); virtual void run(); @@ -30,4 +30,5 @@ namespace Swift { EventLoop* eventLoop; std::string service; + bool serviceValid; }; } diff --git a/Swiften/Network/PlatformNATTraversalWorker.cpp b/Swiften/Network/PlatformNATTraversalWorker.cpp index c962b3b..65ff577 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.cpp +++ b/Swiften/Network/PlatformNATTraversalWorker.cpp @@ -9,11 +9,17 @@ #include <boost/smart_ptr/make_shared.hpp> #include <boost/enable_shared_from_this.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/Log.h> +#include <Swiften/EventLoop/EventLoop.h> #include <Swiften/Network/NATTraversalGetPublicIPRequest.h> #include <Swiften/Network/NATTraversalForwardPortRequest.h> #include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> +#ifdef HAVE_LIBNATPMP #include <Swiften/Network/NATPMPInterface.h> +#endif +#ifdef HAVE_LIBMINIUPNPC #include <Swiften/Network/MiniUPnPInterface.h> +#endif namespace Swift { @@ -38,4 +44,8 @@ class PlatformNATTraversalRequest : public boost::enable_shared_from_this<Platfo } + EventLoop* getEventLoop() const { + return worker->getEventLoop(); + } + virtual void runBlocking() = 0; @@ -50,10 +60,14 @@ class PlatformNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPReq } - virtual void run() { + virtual void start() { doRun(); } + virtual void stop() { + // TODO + } + virtual void runBlocking() { - onResult(getNATTraversalInterface()->getPublicIP()); + getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->getPublicIP())); } }; @@ -64,10 +78,14 @@ class PlatformNATTraversalForwardPortRequest : public NATTraversalForwardPortReq } - virtual void run() { + virtual void start() { doRun(); } + virtual void stop() { + // TODO + } + virtual void runBlocking() { - onResult(getNATTraversalInterface()->addPortForward(localIP, publicIP)); + getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->addPortForward(boost::numeric_cast<int>(localIP), boost::numeric_cast<int>(publicIP)))); } @@ -82,10 +100,14 @@ class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemov } - virtual void run() { + virtual void start() { doRun(); } + virtual void stop() { + // TODO + } + virtual void runBlocking() { - onResult(getNATTraversalInterface()->removePortForward(mapping)); + getEventLoop()->postEvent(boost::bind(boost::ref(onResult), getNATTraversalInterface()->removePortForward(mapping))); } @@ -96,5 +118,6 @@ class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemov PlatformNATTraversalWorker::PlatformNATTraversalWorker(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false), natPMPSupported(boost::logic::indeterminate), natPMPInterface(NULL), miniUPnPSupported(boost::logic::indeterminate), miniUPnPInterface(NULL) { nullNATTraversalInterface = new NullNATTraversalInterface(); - thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::run, this)); + // FIXME: This should be done from start(), and the current start() should be an internal method + thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::start, this)); } @@ -104,10 +127,15 @@ PlatformNATTraversalWorker::~PlatformNATTraversalWorker() { thread->join(); delete thread; +#ifdef HAVE_LIBNATPMP delete natPMPInterface; +#endif +#ifdef HAVE_LIBMINIUPNPC delete miniUPnPInterface; +#endif delete nullNATTraversalInterface; } NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() const { +#ifdef HAVE_LIBMINIUPNPC if (boost::logic::indeterminate(miniUPnPSupported)) { miniUPnPInterface = new MiniUPnPInterface(); @@ -117,6 +145,7 @@ NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() co return miniUPnPInterface; } +#endif - +#ifdef HAVE_LIBNATPMP if (boost::logic::indeterminate(natPMPSupported)) { natPMPInterface = new NATPMPInterface(); @@ -126,4 +155,5 @@ NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() co return natPMPInterface; } +#endif return nullNATTraversalInterface; @@ -143,5 +173,5 @@ boost::shared_ptr<NATTraversalRemovePortForwardingRequest> PlatformNATTraversalW } -void PlatformNATTraversalWorker::run() { +void PlatformNATTraversalWorker::start() { while (!stopRequested) { PlatformNATTraversalRequest::ref request; @@ -162,4 +192,8 @@ void PlatformNATTraversalWorker::run() { } +void PlatformNATTraversalWorker::stop() { + // TODO +} + void PlatformNATTraversalWorker::addRequestToQueue(PlatformNATTraversalRequest::ref request) { { diff --git a/Swiften/Network/PlatformNATTraversalWorker.h b/Swiften/Network/PlatformNATTraversalWorker.h index 94d3339..91b83f8 100644 --- a/Swiften/Network/PlatformNATTraversalWorker.h +++ b/Swiften/Network/PlatformNATTraversalWorker.h @@ -14,4 +14,5 @@ #include <boost/logic/tribool.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/NATTraverser.h> #include <Swiften/Network/HostAddressPort.h> @@ -29,5 +30,5 @@ namespace Swift { class NATPortMapping; - class PlatformNATTraversalWorker : public NATTraverser { + class SWIFTEN_API PlatformNATTraversalWorker : public NATTraverser { friend class PlatformNATTraversalRequest; @@ -43,5 +44,10 @@ namespace Swift { NATTraversalInterface* getNATTraversalInterface() const; void addRequestToQueue(boost::shared_ptr<PlatformNATTraversalRequest>); - void run(); + void start(); + void stop(); + + EventLoop* getEventLoop() const { + return eventLoop; + } private: diff --git a/Swiften/Network/PlatformNetworkEnvironment.h b/Swiften/Network/PlatformNetworkEnvironment.h index c6b945e..2092bfd 100644 --- a/Swiften/Network/PlatformNetworkEnvironment.h +++ b/Swiften/Network/PlatformNetworkEnvironment.h @@ -19,4 +19,10 @@ namespace Swift { typedef WindowsNetworkEnvironment PlatformNetworkEnvironment; } +#elif defined(SWIFTEN_PLATFORM_SOLARIS) +#include <Swiften/Network/SolarisNetworkEnvironment.h> +namespace Swift { + typedef SolarisNetworkEnvironment PlatformNetworkEnvironment; +} + #else #include <Swiften/Network/UnixNetworkEnvironment.h> diff --git a/Swiften/Network/ProxiedConnection.cpp b/Swiften/Network/ProxiedConnection.cpp new file mode 100644 index 0000000..0061820 --- /dev/null +++ b/Swiften/Network/ProxiedConnection.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#include <Swiften/Network/ProxiedConnection.h> + +#include <iostream> +#include <boost/bind.hpp> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/ConnectionFactory.h> + +using namespace Swift; + +ProxiedConnection::ProxiedConnection( + DomainNameResolver* resolver, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + const std::string& proxyHost, + int proxyPort) : + resolver_(resolver), + connectionFactory_(connectionFactory), + timerFactory_(timerFactory), + proxyHost_(proxyHost), + proxyPort_(proxyPort), + server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) { + connected_ = false; +} + +ProxiedConnection::~ProxiedConnection() { + cancelConnector(); + if (connection_) { + connection_->onDataRead.disconnect(boost::bind(&ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.disconnect(boost::bind(&ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + } + if (connected_) { + std::cerr << "Warning: Connection was still established." << std::endl; + } +} + +void ProxiedConnection::cancelConnector() { + if (connector_) { + connector_->onConnectFinished.disconnect(boost::bind(&ProxiedConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->stop(); + connector_.reset(); + } +} + +void ProxiedConnection::connect(const HostAddressPort& server) { + server_ = server; + + connector_ = Connector::create(proxyHost_, proxyPort_, boost::optional<std::string>(), resolver_, connectionFactory_, timerFactory_); + connector_->onConnectFinished.connect(boost::bind(&ProxiedConnection::handleConnectFinished, shared_from_this(), _1)); + connector_->start(); +} + +void ProxiedConnection::listen() { + assert(false); + connection_->listen(); +} + +void ProxiedConnection::disconnect() { + connected_ = false; + connection_->disconnect(); +} + +void ProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { + onDisconnected(error); +} + +void ProxiedConnection::write(const SafeByteArray& data) { + connection_->write(data); +} + +void ProxiedConnection::handleConnectFinished(Connection::ref connection) { + cancelConnector(); + if (connection) { + connection_ = connection; + connection_->onDataRead.connect(boost::bind(&ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + + initializeProxy(); + } + else { + onConnectFinished(true); + } +} + +void ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { + if (!connected_) { + handleProxyInitializeData(data); + } + else { + onDataRead(data); + } +} + +HostAddressPort ProxiedConnection::getLocalAddress() const { + return connection_->getLocalAddress(); +} + +void ProxiedConnection::setProxyInitializeFinished(bool success) { + connected_ = success; + if (!success) { + disconnect(); + } + onConnectFinished(!success); +} diff --git a/Swiften/Network/ProxiedConnection.h b/Swiften/Network/ProxiedConnection.h new file mode 100644 index 0000000..aa8df38 --- /dev/null +++ b/Swiften/Network/ProxiedConnection.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#pragma once + +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/Connector.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Base/SafeString.h> + +namespace boost { + class thread; + namespace system { + class error_code; + } +} + +namespace Swift { + class ConnectionFactory; + + class ProxiedConnection : public Connection, public boost::enable_shared_from_this<ProxiedConnection> { + public: + ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); + ~ProxiedConnection(); + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const SafeByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + + private: + void handleConnectFinished(Connection::ref connection); + void handleDataRead(boost::shared_ptr<SafeByteArray> data); + void handleDisconnected(const boost::optional<Error>& error); + void cancelConnector(); + + protected: + void setProxyInitializeFinished(bool success); + + virtual void initializeProxy() = 0; + virtual void handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) = 0; + + const HostAddressPort& getServer() const { + return server_; + } + + private: + bool connected_; + DomainNameResolver* resolver_; + ConnectionFactory* connectionFactory_; + TimerFactory* timerFactory_; + std::string proxyHost_; + int proxyPort_; + HostAddressPort server_; + Connector::ref connector_; + boost::shared_ptr<Connection> connection_; + }; +} + diff --git a/Swiften/Network/ProxyProvider.h b/Swiften/Network/ProxyProvider.h index 0b63d51..9a1ccee 100644 --- a/Swiften/Network/ProxyProvider.h +++ b/Swiften/Network/ProxyProvider.h @@ -8,5 +8,4 @@ #include <map> -#include <Swiften/Base/Log.h> #include <Swiften/Network/HostAddressPort.h> #include <Swiften/Base/String.h> diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index ecd7be9..284c1f4 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -2,7 +2,11 @@ Import("swiften_env") myenv = swiften_env.Clone() -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) + +if myenv.get("unbound", False) : + myenv.MergeFlags(myenv.get("UNBOUND_FLAGS", {})) + myenv.MergeFlags(myenv.get("LDNS_FLAGS", {})) sourceList = [ + "ProxiedConnection.cpp", "HTTPConnectProxiedConnection.cpp", "HTTPConnectProxiedConnectionFactory.cpp", @@ -16,5 +20,5 @@ sourceList = [ "BOSHConnection.cpp", "BOSHConnectionPool.cpp", - "CachingNameOnlyDomainNameResolver.cpp", + "CachingDomainNameResolver.cpp", "ConnectionFactory.cpp", "ConnectionServer.cpp", @@ -31,10 +35,8 @@ sourceList = [ "DomainNameAddressQuery.cpp", "DomainNameServiceQuery.cpp", - "PlatformDomainNameResolver.cpp", - "PlatformDomainNameServiceQuery.cpp", - "PlatformDomainNameAddressQuery.cpp", "StaticDomainNameResolver.cpp", "HostAddress.cpp", "HostAddressPort.cpp", + "HostNameOrAddress.cpp", "NetworkFactories.cpp", "BoostNetworkFactories.cpp", @@ -54,5 +56,13 @@ sourceList = [ ] -if myenv["PLATFORM"] == "darwin" : +if myenv.get("unbound", False) : + myenv.Append(CPPDEFINES = "USE_UNBOUND") + sourceList.append("UnboundDomainNameResolver.cpp") +else : + sourceList.append("PlatformDomainNameResolver.cpp") + sourceList.append("PlatformDomainNameServiceQuery.cpp") + sourceList.append("PlatformDomainNameAddressQuery.cpp") + +if myenv["PLATFORM"] == "darwin" and myenv["target"] != "android": myenv.Append(FRAMEWORKS = ["CoreServices", "SystemConfiguration"]) sourceList += [ "MacOSXProxyProvider.cpp" ] @@ -61,4 +71,8 @@ elif myenv["PLATFORM"] == "win32" : sourceList += [ "WindowsProxyProvider.cpp" ] sourceList += [ "WindowsNetworkEnvironment.cpp" ] +elif myenv["PLATFORM"] == "sunos" : + sourceList += [ "UnixProxyProvider.cpp" ] + sourceList += [ "SolarisNetworkEnvironment.cpp" ] + sourceList += [ "EnvironmentProxyProvider.cpp" ] else : sourceList += [ "UnixNetworkEnvironment.cpp" ] @@ -72,8 +86,10 @@ else : objects = myenv.SwiftenObject(sourceList) -if myenv["experimental"] : +if myenv["experimental_ft"] : # LibNATPMP classes + if myenv.get("HAVE_LIBNATPMP", False) : natpmp_env = myenv.Clone() natpmp_env.Append(CPPDEFINES = natpmp_env["LIBNATPMP_FLAGS"].get("INTERNAL_CPPDEFINES", [])) + myenv.Append(CPPDEFINES = ["HAVE_LIBNATPMP"]) objects += natpmp_env.SwiftenObject([ "NATPMPInterface.cpp", @@ -81,6 +97,8 @@ if myenv["experimental"] : # LibMINIUPnP classes + if myenv.get("HAVE_LIBMINIUPNPC", False) : upnp_env = myenv.Clone() upnp_env.Append(CPPDEFINES = upnp_env["LIBMINIUPNPC_FLAGS"].get("INTERNAL_CPPDEFINES", [])) + myenv.Append(CPPDEFINES = ["HAVE_LIBMINIUPNPC"]) objects += upnp_env.SwiftenObject([ "MiniUPnPInterface.cpp", diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp index 163e23a..3fd8184 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + #include <Swiften/Network/SOCKS5ProxiedConnection.h> @@ -19,57 +25,15 @@ using namespace Swift; -SOCKS5ProxiedConnection::SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) { - connected_ = false; -} - -SOCKS5ProxiedConnection::~SOCKS5ProxiedConnection() { - if (connection_) { - connection_->onDataRead.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); - } - - if (connected_) { - std::cerr << "Warning: Connection was still established." << std::endl; - } -} - -void SOCKS5ProxiedConnection::connect(const HostAddressPort& server) { - server_ = server; - connection_ = connectionFactory_->createConnection(); - connection_->onConnectFinished.connect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - connection_->onDataRead.connect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); - connection_->onDisconnected.connect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); - SWIFT_LOG(debug) << "Trying to connect via proxy " << proxy_.getAddress().toString() << ":" << proxy_.getPort() << std::endl; - SWIFT_LOG(debug) << "to server " << server.getAddress().toString() << ":" << server.getPort() << std::endl; - connection_->connect(proxy_); -} - -void SOCKS5ProxiedConnection::listen() { - assert(false); - connection_->listen(); -} - -void SOCKS5ProxiedConnection::disconnect() { - connected_ = false; - if (connection_) { - connection_->disconnect(); - } -} - -void SOCKS5ProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { - onDisconnected(error); +SOCKS5ProxiedConnection::SOCKS5ProxiedConnection( + DomainNameResolver* resolver, + ConnectionFactory* connectionFactory, + TimerFactory* timerFactory, + const std::string& proxyHost, + int proxyPort) : + ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort), + proxyState_(Initial) { } -void SOCKS5ProxiedConnection::write(const SafeByteArray& data) { - if (connection_) { - connection_->write(data); - } -} - -void SOCKS5ProxiedConnection::handleConnectionConnectFinished(bool error) { - connection_->onConnectFinished.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); - if (!error) { - SWIFT_LOG(debug) << "Connection to proxy established, now connect to the server via it." << std::endl; - +void SOCKS5ProxiedConnection::initializeProxy() { proxyState_ = ProxyAuthenticating; SafeByteArray socksConnect; @@ -80,16 +44,12 @@ void SOCKS5ProxiedConnection::handleConnectionConnectFinished(bool error) { // buffer.push_back(0x02); // 0x02 == Username/Password // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928) - connection_->write(socksConnect); - } - else { - onConnectFinished(true); - } + write(socksConnect); } -void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { +void SOCKS5ProxiedConnection::handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data) { SafeByteArray socksConnect; - boost::asio::ip::address rawAddress = server_.getAddress().getRawAddress(); + boost::asio::ip::address rawAddress = getServer().getAddress().getRawAddress(); assert(rawAddress.is_v4() || rawAddress.is_v6()); - if (!connected_) { + if (proxyState_ == ProxyAuthenticating) { SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs" << std::endl; @@ -113,10 +73,10 @@ void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> da uc = rawAddress.to_v6().to_bytes()[s]; // the address. } - socksConnect.push_back(static_cast<char>(uc)); + socksConnect.push_back(uc); } - socksConnect.push_back(static_cast<unsigned char> ((server_.getPort() >> 8) & 0xFF)); // highbyte of the port. - socksConnect.push_back(static_cast<unsigned char> (server_.getPort() & 0xFF)); // lowbyte of the port. - connection_->write(socksConnect); + socksConnect.push_back(static_cast<unsigned char> ((getServer().getPort() >> 8) & 0xFF)); // highbyte of the port. + socksConnect.push_back(static_cast<unsigned char> (getServer().getPort() & 0xFF)); // lowbyte of the port. + write(socksConnect); return; } @@ -124,12 +84,13 @@ void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> da std::cerr << "exception caught" << std::endl; } - connection_->write(socksConnect); + write(socksConnect); break; default: - onConnectFinished(true); + setProxyInitializeFinished(true); break; } return; } + setProxyInitializeFinished(false); } else if (proxyState_ == ProxyConnecting) { @@ -152,23 +113,10 @@ void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> da if ((*data)[0] == 0x05 && (*data)[1] == 0x0) { SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; - connected_ = true; - onConnectFinished(false); - return; + setProxyInitializeFinished(true); } else { std::cerr << "SOCKS Proxy returned an error: " << std::hex << (*data)[1] << std::endl; + setProxyInitializeFinished(false); } - return; - } - } - else { - onDataRead(data); - return; } - disconnect(); - onConnectFinished(true); -} - -HostAddressPort SOCKS5ProxiedConnection::getLocalAddress() const { - return connection_->getLocalAddress(); } diff --git a/Swiften/Network/SOCKS5ProxiedConnection.h b/Swiften/Network/SOCKS5ProxiedConnection.h index 592ce7d..2c93468 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.h +++ b/Swiften/Network/SOCKS5ProxiedConnection.h @@ -7,53 +7,31 @@ #pragma once -#include <boost/enable_shared_from_this.hpp> - -#include <Swiften/Network/Connection.h> -#include <Swiften/Network/HostAddressPort.h> - -namespace boost { - class thread; - namespace system { - class error_code; - } -} +#include <Swiften/Network/ProxiedConnection.h> namespace Swift { class ConnectionFactory; + class DomainNameResolver; + class TimerFactory; - class SOCKS5ProxiedConnection : public Connection, public boost::enable_shared_from_this<SOCKS5ProxiedConnection> { + class SOCKS5ProxiedConnection : public ProxiedConnection { public: typedef boost::shared_ptr<SOCKS5ProxiedConnection> ref; - ~SOCKS5ProxiedConnection(); - - static ref create(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) { - return ref(new SOCKS5ProxiedConnection(connectionFactory, proxy)); + static ref create(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) { + return ref(new SOCKS5ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort)); } - virtual void listen(); - virtual void connect(const HostAddressPort& address); - virtual void disconnect(); - virtual void write(const SafeByteArray& data); - - virtual HostAddressPort getLocalAddress() const; - private: - SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + SOCKS5ProxiedConnection(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); - void handleConnectionConnectFinished(bool error); - void handleDataRead(boost::shared_ptr<SafeByteArray> data); - void handleDisconnected(const boost::optional<Error>& error); + virtual void initializeProxy(); + virtual void handleProxyInitializeData(boost::shared_ptr<SafeByteArray> data); private: enum { - ProxyAuthenticating = 0, - ProxyConnecting, + Initial = 0, + ProxyAuthenticating, + ProxyConnecting } proxyState_; - bool connected_; - ConnectionFactory* connectionFactory_; - HostAddressPort proxy_; - HostAddressPort server_; - boost::shared_ptr<Connection> connection_; }; } diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp index 272ade9..af99034 100644 --- a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp @@ -11,9 +11,9 @@ namespace Swift { -SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy) { +SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort) : resolver_(resolver), connectionFactory_(connectionFactory), timerFactory_(timerFactory), proxyHost_(proxyHost), proxyPort_(proxyPort) { } boost::shared_ptr<Connection> SOCKS5ProxiedConnectionFactory::createConnection() { - return SOCKS5ProxiedConnection::create(connectionFactory_, proxy_); + return SOCKS5ProxiedConnection::create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_); } diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h index f36d42a..4c5c585 100644 --- a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h @@ -9,15 +9,22 @@ #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/HostNameOrAddress.h> namespace Swift { + class DomainNameResolver; + class TimerFactory; + class SOCKS5ProxiedConnectionFactory : public ConnectionFactory { public: - SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + SOCKS5ProxiedConnectionFactory(DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, const std::string& proxyHost, int proxyPort); virtual boost::shared_ptr<Connection> createConnection(); private: + DomainNameResolver* resolver_; ConnectionFactory* connectionFactory_; - HostAddressPort proxy_; + TimerFactory* timerFactory_; + std::string proxyHost_; + int proxyPort_; }; } diff --git a/Swiften/Network/SolarisNetworkEnvironment.cpp b/Swiften/Network/SolarisNetworkEnvironment.cpp new file mode 100644 index 0000000..93eec32 --- /dev/null +++ b/Swiften/Network/SolarisNetworkEnvironment.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* +* Copyright (c) 2013-2014 Remko Tronçon and Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + +#include <Swiften/Network/SolarisNetworkEnvironment.h> + +#include <string> +#include <vector> +#include <map> +#include <boost/optional.hpp> + +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/sockio.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <net/if.h> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/NetworkInterface.h> + +/* + * Copyright (c) 2006 WIDE Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#undef ifa_broadaddr +#undef ifa_dstaddr +struct ifaddrs { + struct ifaddrs *ifa_next; /* Pointer to next struct */ + char *ifa_name; /* Interface name */ + uint64_t ifa_flags; /* Interface flags */ + struct sockaddr *ifa_addr; /* Interface address */ + struct sockaddr *ifa_netmask; /* Interface netmask */ + struct sockaddr *ifa_dstaddr; /* P2P interface destination */ +}; +#define ifa_broadaddr ifa_dstaddr + +static int +get_lifreq(int fd, struct lifreq **ifr_ret) +{ + struct lifnum lifn; + struct lifconf lifc; + struct lifreq *lifrp; + + lifn.lifn_family = AF_UNSPEC; + lifn.lifn_flags = 0; + if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1) + lifn.lifn_count = 16; + else + lifn.lifn_count += 16; + + for (;;) { + lifc.lifc_len = lifn.lifn_count * sizeof (*lifrp); + lifrp = (struct lifreq *) malloc(lifc.lifc_len); + if (lifrp == NULL) + return (-1); + + lifc.lifc_family = AF_UNSPEC; + lifc.lifc_flags = 0; + lifc.lifc_buf = (char *)lifrp; + if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) { + free(lifrp); + if (errno == EINVAL) { + lifn.lifn_count <<= 1; + continue; + } + (void) close(fd); + return (-1); + } + if (lifc.lifc_len < (lifn.lifn_count - 1) * sizeof (*lifrp)) + break; + free(lifrp); + lifn.lifn_count <<= 1; + } + (void) close(fd); + + *ifr_ret = lifrp; + + return (lifc.lifc_len / sizeof (*lifrp)); +} + +static size_t +nbytes(const struct lifreq *lifrp, int nlif, size_t socklen) +{ + size_t len = 0; + size_t slen; + + while (nlif > 0) { + slen = strlen(lifrp->lifr_name) + 1; + len += sizeof (struct ifaddrs) + ((slen + 3) & ~3); + len += 3 * socklen; + lifrp++; + nlif--; + } + return (len); +} + +static struct sockaddr * +addrcpy(struct sockaddr_storage *addr, char **bufp) +{ + char *buf = *bufp; + size_t len; + + len = addr->ss_family == AF_INET ? sizeof (struct sockaddr_in) : + sizeof (struct sockaddr_in6); + (void) memcpy(buf, addr, len); + *bufp = buf + len; + return ((struct sockaddr *)buf); +} + +static int +populate(struct ifaddrs *ifa, int fd, struct lifreq *lifrp, int nlif, int af, + char **bufp) +{ + char *buf = *bufp; + size_t slen; + + while (nlif > 0) { + ifa->ifa_next = (nlif > 1) ? ifa + 1 : NULL; + (void) strcpy(ifa->ifa_name = buf, lifrp->lifr_name); + slen = strlen(lifrp->lifr_name) + 1; + buf += (slen + 3) & ~3; + if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1) + ifa->ifa_flags = 0; + else + ifa->ifa_flags = lifrp->lifr_flags; + if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1) + ifa->ifa_addr = NULL; + else + ifa->ifa_addr = addrcpy(&lifrp->lifr_addr, &buf); + if (ioctl(fd, SIOCGLIFNETMASK, lifrp) == -1) + ifa->ifa_netmask = NULL; + else + ifa->ifa_netmask = addrcpy(&lifrp->lifr_addr, &buf); + if (ifa->ifa_flags & IFF_POINTOPOINT) { + if (ioctl(fd, SIOCGLIFDSTADDR, lifrp) == -1) + ifa->ifa_dstaddr = NULL; + else + ifa->ifa_dstaddr = + addrcpy(&lifrp->lifr_dstaddr, &buf); + } else if (ifa->ifa_flags & IFF_BROADCAST) { + if (ioctl(fd, SIOCGLIFBRDADDR, lifrp) == -1) + ifa->ifa_broadaddr = NULL; + else + ifa->ifa_broadaddr = + addrcpy(&lifrp->lifr_broadaddr, &buf); + } else { + ifa->ifa_dstaddr = NULL; + } + + ifa++; + nlif--; + lifrp++; + } + *bufp = buf; + return (0); +} + +static int +getifaddrs(struct ifaddrs **ifap) +{ + int fd4, fd6; + int nif4, nif6 = 0; + struct lifreq *ifr4 = NULL; + struct lifreq *ifr6 = NULL; + struct ifaddrs *ifa = NULL; + char *buf; + + if ((fd4 = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + return (-1); + if ((fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1 && + errno != EAFNOSUPPORT) { + (void) close(fd4); + return (-1); + } + + if ((nif4 = get_lifreq(fd4, &ifr4)) == -1 || + (fd6 != -1 && (nif6 = get_lifreq(fd6, &ifr6)) == -1)) + goto failure; + + if (nif4 == 0 && nif6 == 0) { + *ifap = NULL; + return (0); + } + + ifa = (struct ifaddrs *) malloc(nbytes(ifr4, nif4, sizeof (struct sockaddr_in)) + + nbytes(ifr6, nif6, sizeof (struct sockaddr_in6))); + if (ifa == NULL) + goto failure; + + buf = (char *)(ifa + nif4 + nif6); + + if (populate(ifa, fd4, ifr4, nif4, AF_INET, &buf) == -1) + goto failure; + if (nif4 > 0 && nif6 > 0) + ifa[nif4 - 1].ifa_next = ifa + nif4; + if (populate(ifa + nif4, fd6, ifr6, nif6, AF_INET6, &buf) == -1) + goto failure; + + return (0); + +failure: + free(ifa); + (void) close(fd4); + if (fd6 != -1) + (void) close(fd6); + free(ifr4); + free(ifr6); + return (-1); +} + +static void +freeifaddrs(struct ifaddrs *ifa) +{ + free(ifa); +} + +/* End WIDE Project code */ + +namespace Swift { + +std::vector<NetworkInterface> SolarisNetworkEnvironment::getNetworkInterfaces() const { + std::map<std::string, NetworkInterface> interfaces; + + ifaddrs* addrs = 0; + int ret = getifaddrs(&addrs); + if (ret != 0) { + return std::vector<NetworkInterface>(); + } + + for (ifaddrs* a = addrs; a != 0; a = a->ifa_next) { + std::string name(a->ifa_name); + boost::optional<HostAddress> address; + if (a->ifa_addr->sa_family == PF_INET) { + sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(a->ifa_addr); + address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin_addr)), 4); + } + else if (a->ifa_addr->sa_family == PF_INET6) { + sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(a->ifa_addr); + address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); + } + if (address) { + std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, a->ifa_flags & IFF_LOOPBACK))).first; + i->second.addAddress(*address); + } + } + + freeifaddrs(addrs); + + std::vector<NetworkInterface> result; + for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { + result.push_back(i->second); + } + return result; +} + +} diff --git a/Swiften/Network/SolarisNetworkEnvironment.h b/Swiften/Network/SolarisNetworkEnvironment.h new file mode 100644 index 0000000..7481ff4 --- /dev/null +++ b/Swiften/Network/SolarisNetworkEnvironment.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +/* +* Copyright (c) 2013-2014 Remko Tronçon and Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + +#pragma once + +#include <vector> + +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/Network/NetworkEnvironment.h> +#include <Swiften/Network/NetworkInterface.h> + +namespace Swift { + + class SolarisNetworkEnvironment : public NetworkEnvironment { + public: + std::vector<NetworkInterface> getNetworkInterfaces() const; + }; + +} diff --git a/Swiften/Network/StaticDomainNameResolver.cpp b/Swiften/Network/StaticDomainNameResolver.cpp index ee18ee5..17d9c3b 100644 --- a/Swiften/Network/StaticDomainNameResolver.cpp +++ b/Swiften/Network/StaticDomainNameResolver.cpp @@ -109,6 +109,6 @@ void StaticDomainNameResolver::addXMPPClientService(const std::string& domain, c } -boost::shared_ptr<DomainNameServiceQuery> StaticDomainNameResolver::createServiceQuery(const std::string& name) { - return boost::shared_ptr<DomainNameServiceQuery>(new ServiceQuery(name, this, eventLoop, owner)); +boost::shared_ptr<DomainNameServiceQuery> StaticDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + return boost::shared_ptr<DomainNameServiceQuery>(new ServiceQuery(serviceLookupPrefix + domain, this, eventLoop, owner)); } diff --git a/Swiften/Network/StaticDomainNameResolver.h b/Swiften/Network/StaticDomainNameResolver.h index 29d1629..81ff040 100644 --- a/Swiften/Network/StaticDomainNameResolver.h +++ b/Swiften/Network/StaticDomainNameResolver.h @@ -10,4 +10,5 @@ #include <map> +#include <Swiften/Base/API.h> #include <Swiften/Network/HostAddress.h> #include <Swiften/Network/HostAddressPort.h> @@ -18,5 +19,5 @@ namespace Swift { - class StaticDomainNameResolver : public DomainNameResolver { + class SWIFTEN_API StaticDomainNameResolver : public DomainNameResolver { public: typedef std::map<std::string, std::vector<HostAddress> > AddressesMap; @@ -48,5 +49,5 @@ namespace Swift { } - virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name); + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); private: diff --git a/Swiften/Network/TLSConnection.h b/Swiften/Network/TLSConnection.h index a798393..60f73ea 100644 --- a/Swiften/Network/TLSConnection.h +++ b/Swiften/Network/TLSConnection.h @@ -25,5 +25,5 @@ namespace Swift { virtual ~TLSConnection(); - virtual void listen() {assert(false);}; + virtual void listen() {assert(false);} virtual void connect(const HostAddressPort& address); virtual void disconnect(); diff --git a/Swiften/Network/Timer.h b/Swiften/Network/Timer.h index b7578f2..d08cf3c 100644 --- a/Swiften/Network/Timer.h +++ b/Swiften/Network/Timer.h @@ -8,4 +8,5 @@ #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> namespace Swift { @@ -13,5 +14,5 @@ namespace Swift { * A class for triggering an event after a given period. */ - class Timer { + class SWIFTEN_API Timer { public: typedef boost::shared_ptr<Timer> ref; diff --git a/Swiften/Network/TimerFactory.h b/Swiften/Network/TimerFactory.h index 99903c3..62850bc 100644 --- a/Swiften/Network/TimerFactory.h +++ b/Swiften/Network/TimerFactory.h @@ -9,8 +9,9 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Network/Timer.h> namespace Swift { - class TimerFactory { + class SWIFTEN_API TimerFactory { public: virtual ~TimerFactory(); diff --git a/Swiften/Network/UnboundDomainNameResolver.cpp b/Swiften/Network/UnboundDomainNameResolver.cpp new file mode 100755 index 0000000..bc280eb --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "UnboundDomainNameResolver.h" + +#include <vector> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/DomainNameResolveError.h> +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/TimerFactory.h> + +#include <arpa/inet.h> +#include <unbound.h> +#include <ldns/ldns.h> +#include <unistd.h> + +namespace Swift { + +class UnboundQuery { + public: + UnboundQuery(UnboundDomainNameResolver* resolver, ub_ctx* context) : resolver(resolver), ubContext(context) {} + virtual ~UnboundQuery() {} + virtual void handleResult(int err, ub_result* result) = 0; + protected: + UnboundDomainNameResolver* resolver; + ub_ctx* ubContext; +}; + +struct UnboundWrapperHelper { + UnboundWrapperHelper(UnboundDomainNameResolver* resolver, boost::shared_ptr<UnboundQuery> query) : resolver(resolver), query(query) {} + UnboundDomainNameResolver* resolver; + boost::shared_ptr<UnboundQuery> query; +}; + +class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameServiceQuery> { + public: + UnboundDomainNameServiceQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { + } + + virtual ~UnboundDomainNameServiceQuery() { } + + virtual void run() { + int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); + + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_SRV, + 1 /* CLASS IN (internet) */, + helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + delete helper; + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<DomainNameServiceQuery::Result> serviceRecords; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + } else { + if(result->havedata) { + ldns_pkt* replyPacket = 0; + ldns_buffer* buffer = ldns_buffer_new(1024); + if (buffer && ldns_wire2pkt(&replyPacket, static_cast<const uint8_t*>(result->answer_packet), result->answer_len) == LDNS_STATUS_OK) { + ldns_rr_list* rrList = ldns_pkt_answer(replyPacket); + for (size_t n = 0; n < ldns_rr_list_rr_count(rrList); n++) { + ldns_rr* rr = ldns_rr_list_rr(rrList, n); + if ((ldns_rr_get_type(rr) != LDNS_RR_TYPE_SRV) || + (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) || + (ldns_rr_rd_count(rr) != 4)) { + continue; + } + + DomainNameServiceQuery::Result serviceRecord; + serviceRecord.priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); + serviceRecord.weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1)); + serviceRecord.port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2)); + + ldns_buffer_rewind(buffer); + if ((ldns_rdf2buffer_str_dname(buffer, ldns_rr_rdf(rr, 3)) != LDNS_STATUS_OK) || + (ldns_buffer_position(buffer) < 2) || + !ldns_buffer_reserve(buffer, 1)) { + // either name invalid, empty or buffer to small + continue; + } + char terminator = 0; + ldns_buffer_write(buffer, &terminator, sizeof(terminator)); + + serviceRecord.hostname = std::string(reinterpret_cast<char*>(ldns_buffer_at(buffer, 0))); + serviceRecords.push_back(serviceRecord); + SWIFT_LOG(debug) << "hostname " << serviceRecord.hostname << " added" << std::endl; + } + } + if (replyPacket) ldns_pkt_free(replyPacket); + if (buffer) ldns_buffer_free(buffer); + } + } + + ub_resolve_free(result); + onResult(serviceRecords); + } + + private: + std::string name; +}; + +class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameAddressQuery> { + public: + UnboundDomainNameAddressQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { + } + + virtual ~UnboundDomainNameAddressQuery() { } + + virtual void run() { + int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); + + //FIXME: support AAAA queries in some way + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_A, + 1 /* CLASS IN (internet) */, + helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + delete helper; + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<HostAddress> addresses; + boost::optional<DomainNameResolveError> error; + SWIFT_LOG(debug) << "Result for: " << name << std::endl; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + error = DomainNameResolveError(); + } else { + if(result->havedata) { + for(int i=0; result->data[i]; i++) { + char address[100]; + const char* addressStr = 0; + if ((addressStr = inet_ntop(AF_INET, result->data[i], address, 100))) { + SWIFT_LOG(debug) << "IPv4 address: " << addressStr << std::endl; + addresses.push_back(HostAddress(std::string(addressStr))); + } else if ((addressStr = inet_ntop(AF_INET6, result->data[i], address, 100))) { + SWIFT_LOG(debug) << "IPv6 address: " << addressStr << std::endl; + addresses.push_back(HostAddress(std::string(addressStr))); + } else { + SWIFT_LOG(debug) << "inet_ntop() failed" << std::endl; + error = DomainNameResolveError(); + } + } + } else { + error = DomainNameResolveError(); + } + } + + ub_resolve_free(result); + onResult(addresses, error); + } + + private: + std::string name; +}; + +UnboundDomainNameResolver::UnboundDomainNameResolver(IDNConverter* idnConverter, boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : idnConverter(idnConverter), ioService(ioService), ubDescriptior(*ioService), eventLoop(eventLoop) { + ubContext = ub_ctx_create(); + if(!ubContext) { + SWIFT_LOG(debug) << "could not create unbound context" << std::endl; + } + eventOwner = boost::make_shared<EventOwner>(); + + ub_ctx_async(ubContext, true); + + int ret; + + /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */ + if( (ret=ub_ctx_resolvconf(ubContext, const_cast<char*>("/etc/resolv.conf"))) != 0) { + SWIFT_LOG(error) << "error reading resolv.conf: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + /* read /etc/hosts for locally supplied host addresses */ + if( (ret=ub_ctx_hosts(ubContext, const_cast<char*>("/etc/hosts"))) != 0) { + SWIFT_LOG(error) << "error reading hosts: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + + ubDescriptior.assign(ub_fd(ubContext)); + + ubDescriptior.async_read_some(boost::asio::null_buffers(), boost::bind(&UnboundDomainNameResolver::handleUBSocketReadable, this, boost::asio::placeholders::error)); +} + +UnboundDomainNameResolver::~UnboundDomainNameResolver() { + eventLoop->removeEventsFromOwner(eventOwner); + if (ubContext) { + ub_ctx_delete(ubContext); + } +} + +void UnboundDomainNameResolver::unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result) { + query->handleResult(err, result); +} + +void UnboundDomainNameResolver::unbound_callback_wrapper(void* data, int err, ub_result* result) { + UnboundWrapperHelper* helper = static_cast<UnboundWrapperHelper*>(data); + UnboundDomainNameResolver* resolver = helper->resolver; + resolver->unbound_callback(helper->query, err, result); + delete helper; +} + +void UnboundDomainNameResolver::handleUBSocketReadable(boost::system::error_code) { + eventLoop->postEvent(boost::bind(&UnboundDomainNameResolver::processData, this), eventOwner); + ubDescriptior.async_read_some(boost::asio::null_buffers(), boost::bind(&UnboundDomainNameResolver::handleUBSocketReadable, this, boost::asio::placeholders::error)); +} + +void UnboundDomainNameResolver::processData() { + if (ub_poll(ubContext)) { + int ret = ub_process(ubContext); + if(ret != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; + } + } +} + +boost::shared_ptr<DomainNameServiceQuery> UnboundDomainNameResolver::createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + boost::optional<std::string> encodedDomain = idnConverter->getIDNAEncoded(domain); + std::string result; + if (encodedDomain) { + result = serviceLookupPrefix + *encodedDomain; + } + return boost::make_shared<UnboundDomainNameServiceQuery>(this, ubContext, result); +} + +boost::shared_ptr<DomainNameAddressQuery> UnboundDomainNameResolver::createAddressQuery(const std::string& name) { + return boost::make_shared<UnboundDomainNameAddressQuery>(this, ubContext, idnConverter->getIDNAEncoded(name).get_value_or("")); +} + +} diff --git a/Swiften/Network/UnboundDomainNameResolver.h b/Swiften/Network/UnboundDomainNameResolver.h new file mode 100755 index 0000000..6b78cf3 --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/EventLoop/EventOwner.h> + +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio.hpp> + +struct ub_ctx; +struct ub_result; + +namespace Swift { + class EventLoop; + class IDNConverter; + class TimerFactory; + + class UnboundDomainNameResolver; + class UnboundQuery; + + class UnboundDomainNameResolver : public DomainNameResolver, public EventOwner, public boost::enable_shared_from_this<UnboundDomainNameResolver> { + public: + UnboundDomainNameResolver(IDNConverter* idnConverter, boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop); + virtual ~UnboundDomainNameResolver(); + + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain); + virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); + + static void unbound_callback_wrapper(void* data, int err, ub_result* result); + + private: + void unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result); + + void handleUBSocketReadable(boost::system::error_code); + void processData(); + + private: + IDNConverter* idnConverter; + boost::shared_ptr<EventOwner> eventOwner; + boost::shared_ptr<boost::asio::io_service> ioService; + boost::asio::posix::stream_descriptor ubDescriptior; + EventLoop* eventLoop; + ub_ctx* ubContext; + }; + +} diff --git a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp index 82762c5..8a63fcb 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp @@ -48,5 +48,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { void setUp() { to = "wonderland.lit"; - path = "http-bind"; + path = "/http-bind"; port = "5280"; sid = "MyShinySID"; @@ -171,5 +171,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { boost::shared_ptr<MockConnection> c0; boost::shared_ptr<MockConnection> c1; - long rid = initialRID; + unsigned long long rid = initialRID; PoolRef testling = createTestling(); @@ -237,5 +237,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { to = "prosody.doomsong.co.uk"; resolver->addAddress("prosody.doomsong.co.uk", HostAddress("127.0.0.1")); - path = "http-bind/"; + path = "/http-bind/"; boshURL = URL("http", to, 5280, path); @@ -275,4 +275,22 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); + + testling->restartStream(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); + CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); + + response = "<body xmpp:version='1.0' xmlns:stream='http://etherx.jabber.org/streams' xmlns:xmpp='urn:xmpp:xbosh' inactivity='60' wait='60' polling='5' secure='true' hold='1' from='prosody.doomsong.co.uk' ver='1.6' sid='743da605-4c2e-4de1-afac-ac040dd4a940' requests='2' xmlns='http://jabber.org/protocol/httpbind'><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><required/></bind><session xmlns='urn:ietf:params:xml:ns:xmpp-session'><optional/></session><sm xmlns='urn:xmpp:sm:2'><optional/></sm></stream:features></body>"; + readResponse(response, connectionFactory->connections[0]); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(st(5), boshDataWritten.size()); /* Now we've authed (restarted) we should be keeping one query in flight so the server can reply to us at any time it wants. */ + CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); + + send = "<body rid='2821988967416214' sid='cf663f6b94279d4f' xmlns='http://jabber.org/protocol/httpbind'><iq id='session-bind' type='set'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>d5a9744036cd20a0</resource></bind></iq></body>"; + testling->write(createSafeByteArray(send)); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(st(6), boshDataWritten.size()); + CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); /* and as it keeps one in flight, it's needed to open a second to send these data */ + } @@ -444,5 +462,5 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { std::string sid; std::string initial; - long initialRID; + unsigned long long initialRID; int sessionStarted; int sessionTerminated; diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index e0dc0bf..0d06420 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -108,5 +108,5 @@ class BOSHConnectionTest : public CppUnit::TestFixture { testling->setSID("mySID"); CPPUNIT_ASSERT(testling->isReadyToSend()); - connectionFactory->connections[0]->onDisconnected(false); + connectionFactory->connections[0]->onDisconnected(boost::optional<Connection::Error>()); CPPUNIT_ASSERT(!testling->isReadyToSend()); } @@ -193,6 +193,6 @@ class BOSHConnectionTest : public CppUnit::TestFixture { BOSHConnection::ref createTestling() { resolver->addAddress("wonderland.lit", HostAddress("127.0.0.1")); - Connector::ref connector = Connector::create("wonderland.lit", resolver, connectionFactory, timerFactory, 5280); - BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "http-bind"), connector, &parserFactory); + Connector::ref connector = Connector::create("wonderland.lit", 5280, boost::optional<std::string>(), resolver, connectionFactory, timerFactory); + BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "/http-bind"), connector, &parserFactory); c->onConnectFinished.connect(boost::bind(&BOSHConnectionTest::handleConnectFinished, this, _1)); c->onDisconnected.connect(boost::bind(&BOSHConnectionTest::handleDisconnected, this, _1)); diff --git a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp index a2fceb9..9176fe7 100644 --- a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp @@ -127,5 +127,5 @@ class ChainedConnectorTest : public CppUnit::TestFixture { factories.push_back(connectionFactory1); factories.push_back(connectionFactory2); - boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", resolver, factories, timerFactory); + boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", -1, boost::optional<std::string>("_xmpp-client._tcp."), resolver, factories, timerFactory); connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; diff --git a/Swiften/Network/UnitTest/ConnectorTest.cpp b/Swiften/Network/UnitTest/ConnectorTest.cpp index 67270be..3b1d4e4 100644 --- a/Swiften/Network/UnitTest/ConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ConnectorTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -25,4 +25,6 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ConnectorTest); CPPUNIT_TEST(testConnect); + CPPUNIT_TEST(testConnect_NoServiceLookups); + CPPUNIT_TEST(testConnect_NoServiceLookups_DefaultPort); CPPUNIT_TEST(testConnect_FirstAddressHostFails); CPPUNIT_TEST(testConnect_NoSRVHost); @@ -32,6 +34,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST(testConnect_AllSRVHostsFailWithFallbackHost); CPPUNIT_TEST(testConnect_SRVAndFallbackHostsFail); - CPPUNIT_TEST(testConnect_TimeoutDuringResolve); - CPPUNIT_TEST(testConnect_TimeoutDuringConnect); + //CPPUNIT_TEST(testConnect_TimeoutDuringResolve); + CPPUNIT_TEST(testConnect_TimeoutDuringConnectToOnlyCandidate); + CPPUNIT_TEST(testConnect_TimeoutDuringConnectToCandidateFallsBack); CPPUNIT_TEST(testConnect_NoTimeout); CPPUNIT_TEST(testStop_DuringSRVQuery); @@ -72,4 +75,36 @@ class ConnectorTest : public CppUnit::TestFixture { } + void testConnect_NoServiceLookups() { + Connector::ref testling(createConnector(4321, boost::optional<std::string>())); + resolver->addXMPPClientService("foo.com", host1); + resolver->addXMPPClientService("foo.com", host2); + resolver->addAddress("foo.com", host3.getAddress()); + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(host3.getAddress() == (*(connections[0]->hostAddressPort)).getAddress()); + CPPUNIT_ASSERT(4321 == (*(connections[0]->hostAddressPort)).getPort()); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + + void testConnect_NoServiceLookups_DefaultPort() { + Connector::ref testling(createConnector(-1, boost::optional<std::string>())); + resolver->addXMPPClientService("foo.com", host1); + resolver->addXMPPClientService("foo.com", host2); + resolver->addAddress("foo.com", host3.getAddress()); + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(host3.getAddress() == (*(connections[0]->hostAddressPort)).getAddress()); + CPPUNIT_ASSERT_EQUAL(5222, (*(connections[0]->hostAddressPort)).getPort()); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + void testConnect_NoSRVHost() { Connector::ref testling(createConnector()); @@ -176,5 +211,5 @@ class ConnectorTest : public CppUnit::TestFixture { } - void testConnect_TimeoutDuringResolve() { + /*void testConnect_TimeoutDuringResolve() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); @@ -189,7 +224,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); CPPUNIT_ASSERT(!connections[0]); - } + }*/ - void testConnect_TimeoutDuringConnect() { + void testConnect_TimeoutDuringConnectToOnlyCandidate() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); @@ -207,4 +242,28 @@ class ConnectorTest : public CppUnit::TestFixture { } + void testConnect_TimeoutDuringConnectToCandidateFallsBack() { + Connector::ref testling(createConnector()); + testling->setTimeoutMilliseconds(10); + + resolver->addXMPPClientService("foo.com", "host-foo.com", 1234); + HostAddress address1("1.1.1.1"); + resolver->addAddress("host-foo.com", address1); + HostAddress address2("2.2.2.2"); + resolver->addAddress("host-foo.com", address2); + + connectionFactory->isResponsive = false; + testling->start(); + eventLoop->processEvents(); + connectionFactory->isResponsive = true; + timerFactory->setTime(10); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(HostAddressPort(address2, 1234) == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + + void testConnect_NoTimeout() { Connector::ref testling(createConnector()); @@ -254,6 +313,6 @@ class ConnectorTest : public CppUnit::TestFixture { private: - Connector::ref createConnector() { - Connector::ref connector = Connector::create("foo.com", resolver, connectionFactory, timerFactory); + Connector::ref createConnector(int port = -1, boost::optional<std::string> serviceLookupPrefix = boost::optional<std::string>("_xmpp-client._tcp.")) { + Connector::ref connector = Connector::create("foo.com", port, serviceLookupPrefix, resolver, connectionFactory, timerFactory); connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp index 347a145..134748f 100644 --- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -171,5 +171,5 @@ class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { private: HTTPConnectProxiedConnection::ref createTestling() { - boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(resolver, connectionFactory, timerFactory, eventLoop, proxyHost, proxyPort, "", ""); + boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, "", ""); c->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleConnectFinished, this, _1)); c->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDisconnected, this, _1)); diff --git a/Swiften/Network/UnixNetworkEnvironment.cpp b/Swiften/Network/UnixNetworkEnvironment.cpp index 52c5cbe..e1fdc88 100644 --- a/Swiften/Network/UnixNetworkEnvironment.cpp +++ b/Swiften/Network/UnixNetworkEnvironment.cpp @@ -15,5 +15,8 @@ #include <arpa/inet.h> #include <net/if.h> + +#ifndef __ANDROID__ #include <ifaddrs.h> +#endif #include <Swiften/Base/boost_bsignals.h> @@ -25,5 +28,5 @@ namespace Swift { std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() const { std::map<std::string, NetworkInterface> interfaces; - +#ifndef __ANDROID__ ifaddrs* addrs = 0; int ret = getifaddrs(&addrs); @@ -43,5 +46,5 @@ std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() con address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); } - if (address) { + if (address && !address->isLocalhost()) { std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, a->ifa_flags & IFF_LOOPBACK))).first; i->second.addAddress(*address); @@ -50,5 +53,5 @@ std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() con freeifaddrs(addrs); - +#endif std::vector<NetworkInterface> result; for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { diff --git a/Swiften/Network/WindowsNetworkEnvironment.cpp b/Swiften/Network/WindowsNetworkEnvironment.cpp index 20f559d..e2d1966 100644 --- a/Swiften/Network/WindowsNetworkEnvironment.cpp +++ b/Swiften/Network/WindowsNetworkEnvironment.cpp @@ -51,5 +51,5 @@ std::vector<NetworkInterface> WindowsNetworkEnvironment::getNetworkInterfaces() hostAddress = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); } - if (hostAddress) { + if (hostAddress && !hostAddress->isLocalhost()) { std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, false))).first; i->second.addAddress(*hostAddress); diff --git a/Swiften/Network/WindowsNetworkEnvironment.h b/Swiften/Network/WindowsNetworkEnvironment.h index f43b951..18996ed 100644 --- a/Swiften/Network/WindowsNetworkEnvironment.h +++ b/Swiften/Network/WindowsNetworkEnvironment.h @@ -8,10 +8,11 @@ #include <vector> -#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/NetworkEnvironment.h> namespace Swift { - class WindowsNetworkEnvironment : public NetworkEnvironment { + class SWIFTEN_API WindowsNetworkEnvironment : public NetworkEnvironment { public: std::vector<NetworkInterface> getNetworkInterfaces() const; diff --git a/Swiften/Network/WindowsProxyProvider.h b/Swiften/Network/WindowsProxyProvider.h index c2d1f51..12aa18d 100644 --- a/Swiften/Network/WindowsProxyProvider.h +++ b/Swiften/Network/WindowsProxyProvider.h @@ -6,8 +6,10 @@ #pragma once + +#include <Swiften/Base/API.h> #include <Swiften/Network/ProxyProvider.h> namespace Swift { - class WindowsProxyProvider : public ProxyProvider { + class SWIFTEN_API WindowsProxyProvider : public ProxyProvider { public: WindowsProxyProvider(); diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp index 1aeaf99..d508157 100644 --- a/Swiften/Parser/AttributeMap.cpp +++ b/Swiften/Parser/AttributeMap.cpp @@ -9,19 +9,9 @@ #include <algorithm> #include <boost/optional.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> using namespace Swift; - -namespace { - struct AttributeIs { - AttributeIs(const Attribute& attribute) : attribute(attribute) { - } - - bool operator()(const AttributeMap::Entry& o) const { - return o.getAttribute() == attribute; - } - - Attribute attribute; - }; -} +namespace lambda = boost::lambda; AttributeMap::AttributeMap() { @@ -29,5 +19,6 @@ AttributeMap::AttributeMap() { std::string AttributeMap::getAttribute(const std::string& attribute, const std::string& ns) const { - AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ns))); + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), + lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, ns)); if (i == attributes.end()) { return ""; @@ -39,5 +30,6 @@ std::string AttributeMap::getAttribute(const std::string& attribute, const std:: bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultValue) const { - AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ""))); + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), + lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, "")); if (i == attributes.end()) { return defaultValue; @@ -49,5 +41,6 @@ bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultVa boost::optional<std::string> AttributeMap::getAttributeValue(const std::string& attribute) const { - AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ""))); + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), + lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, "")); if (i == attributes.end()) { return boost::optional<std::string>(); diff --git a/Swiften/Parser/AttributeMap.h b/Swiften/Parser/AttributeMap.h index 31df606..77b9c23 100644 --- a/Swiften/Parser/AttributeMap.h +++ b/Swiften/Parser/AttributeMap.h @@ -12,8 +12,9 @@ #include <boost/optional/optional_fwd.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Parser/Attribute.h> namespace Swift { - class AttributeMap { + class SWIFTEN_API AttributeMap { public: class Entry { diff --git a/Swiften/Parser/BOSHBodyExtractor.cpp b/Swiften/Parser/BOSHBodyExtractor.cpp index eeebe8a..715a448 100644 --- a/Swiften/Parser/BOSHBodyExtractor.cpp +++ b/Swiften/Parser/BOSHBodyExtractor.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <boost/shared_ptr.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Parser/XMLParserClient.h> @@ -34,5 +35,5 @@ class BOSHBodyParserClient : public XMLParserClient { }; -inline bool isWhitespace(char c) { +inline bool isWhitespace(unsigned char c) { return c == ' ' || c == '\n' || c == '\t' || c == '\r'; } @@ -118,5 +119,7 @@ BOSHBodyExtractor::BOSHBodyExtractor(XMLParserFactory* parserFactory, const Byte body = BOSHBody(); if (!endElementSeen) { - body->content = std::string(reinterpret_cast<const char*>(vecptr(data) + std::distance(data.begin(), i)), std::distance(i, j.base())); + body->content = std::string( + reinterpret_cast<const char*>(vecptr(data) + std::distance(data.begin(), i)), + boost::numeric_cast<size_t>(std::distance(i, j.base()))); } @@ -124,5 +127,7 @@ BOSHBodyExtractor::BOSHBodyExtractor(XMLParserFactory* parserFactory, const Byte BOSHBodyParserClient parserClient(this); boost::shared_ptr<XMLParser> parser(parserFactory->createXMLParser(&parserClient)); - if (!parser->parse(std::string(reinterpret_cast<const char*>(vecptr(data)), std::distance(data.begin(), i)))) { + if (!parser->parse(std::string( + reinterpret_cast<const char*>(vecptr(data)), + boost::numeric_cast<size_t>(std::distance(data.begin(), i))))) { /* TODO: This needs to be only validating the BOSH <body> element, so that XMPP parsing errors are caught at the correct higher layer */ diff --git a/Swiften/Parser/BOSHBodyExtractor.h b/Swiften/Parser/BOSHBodyExtractor.h index 07203ae..7510761 100644 --- a/Swiften/Parser/BOSHBodyExtractor.h +++ b/Swiften/Parser/BOSHBodyExtractor.h @@ -9,4 +9,5 @@ #include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> #include <Swiften/Parser/XMLParserClient.h> @@ -15,5 +16,5 @@ namespace Swift { class XMLParserFactory; - class BOSHBodyExtractor { + class SWIFTEN_API BOSHBodyExtractor { friend class BOSHBodyParserClient; public: diff --git a/Swiften/Parser/ElementParser.h b/Swiften/Parser/ElementParser.h index a11b505..256e2dc 100644 --- a/Swiften/Parser/ElementParser.h +++ b/Swiften/Parser/ElementParser.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,9 +10,10 @@ #include <string> -#include <Swiften/Elements/Element.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Parser/AttributeMap.h> namespace Swift { - class ElementParser { + class SWIFTEN_API ElementParser { public: virtual ~ElementParser(); @@ -22,5 +23,5 @@ namespace Swift { virtual void handleCharacterData(const std::string& data) = 0; - virtual boost::shared_ptr<Element> getElement() const = 0; + virtual boost::shared_ptr<ToplevelElement> getElement() const = 0; }; } diff --git a/Swiften/Parser/EnumParser.h b/Swiften/Parser/EnumParser.h new file mode 100644 index 0000000..d7bdbbc --- /dev/null +++ b/Swiften/Parser/EnumParser.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <string> +#include <map> +#include <cassert> +#include <boost/optional.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> + +namespace Swift { + template<typename T> + class SWIFTEN_API EnumParser { + public: + EnumParser() { + } + + EnumParser& operator()(T value, const std::string& text) { + values[text] = value; + return *this; + } + + boost::optional<T> parse(const std::string& value) { + typename std::map<std::string, T>::const_iterator i = values.find(value); + return i == values.end() ? boost::optional<T>() : i->second; + } + + private: + std::map<std::string, T> values; + }; +} diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index f3b5250..8b7bf82 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp @@ -9,12 +9,20 @@ #include <iostream> #include <string> +#include <expat.h> +#include <boost/numeric/conversion/cast.hpp> #include <Swiften/Base/String.h> #include <Swiften/Parser/XMLParserClient.h> +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" + namespace Swift { static const char NAMESPACE_SEPARATOR = '\x01'; +struct ExpatParser::Private { + XML_Parser parser_; +}; + static void handleStartElement(void* parser, const XML_Char* name, const XML_Char** attributes) { std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); @@ -48,5 +56,6 @@ static void handleEndElement(void* parser, const XML_Char* name) { static void handleCharacterData(void* parser, const XML_Char* data, int len) { - static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(data, len)); + assert(len >= 0); + static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(data, static_cast<size_t>(len))); } @@ -55,28 +64,32 @@ static void handleXMLDeclaration(void*, const XML_Char*, const XML_Char*, int) { static void handleEntityDeclaration(void* parser, const XML_Char*, int, const XML_Char*, int, const XML_Char*, const XML_Char*, const XML_Char*, const XML_Char*) { - XML_StopParser(static_cast<ExpatParser*>(parser)->getParser(), static_cast<XML_Bool>(0)); + static_cast<ExpatParser*>(parser)->stopParser(); } -ExpatParser::ExpatParser(XMLParserClient* client) : XMLParser(client) { - parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR); - XML_SetUserData(parser_, this); - XML_SetElementHandler(parser_, handleStartElement, handleEndElement); - XML_SetCharacterDataHandler(parser_, handleCharacterData); - XML_SetXmlDeclHandler(parser_, handleXMLDeclaration); - XML_SetEntityDeclHandler(parser_, handleEntityDeclaration); +ExpatParser::ExpatParser(XMLParserClient* client) : XMLParser(client), p(new Private()) { + p->parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR); + XML_SetUserData(p->parser_, this); + XML_SetElementHandler(p->parser_, handleStartElement, handleEndElement); + XML_SetCharacterDataHandler(p->parser_, handleCharacterData); + XML_SetXmlDeclHandler(p->parser_, handleXMLDeclaration); + XML_SetEntityDeclHandler(p->parser_, handleEntityDeclaration); } ExpatParser::~ExpatParser() { - XML_ParserFree(parser_); + XML_ParserFree(p->parser_); } bool ExpatParser::parse(const std::string& data) { - bool success = XML_Parse(parser_, data.c_str(), data.size(), false) == XML_STATUS_OK; + bool success = XML_Parse(p->parser_, data.c_str(), boost::numeric_cast<int>(data.size()), false) == XML_STATUS_OK; /*if (!success) { - std::cout << "ERROR: " << XML_ErrorString(XML_GetErrorCode(parser_)) << " while parsing " << data << std::endl; + std::cout << "ERROR: " << XML_ErrorString(XML_GetErrorCode(p->parser_)) << " while parsing " << data << std::endl; }*/ return success; } +void ExpatParser::stopParser() { + XML_StopParser(p->parser_, static_cast<XML_Bool>(0)); +} + } diff --git a/Swiften/Parser/ExpatParser.h b/Swiften/Parser/ExpatParser.h index 359f786..dcb0915 100644 --- a/Swiften/Parser/ExpatParser.h +++ b/Swiften/Parser/ExpatParser.h @@ -7,11 +7,12 @@ #pragma once -#include <expat.h> #include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Parser/XMLParser.h> namespace Swift { - class ExpatParser : public XMLParser, public boost::noncopyable { + class SWIFTEN_API ExpatParser : public XMLParser, public boost::noncopyable { public: ExpatParser(XMLParserClient* client); @@ -20,10 +21,9 @@ namespace Swift { bool parse(const std::string& data); - XML_Parser getParser() { - return parser_; - } + void stopParser(); private: - XML_Parser parser_; + struct Private; + boost::shared_ptr<Private> p; }; } diff --git a/Swiften/Parser/GenericElementParser.h b/Swiften/Parser/GenericElementParser.h index 224c59e..4395622 100644 --- a/Swiften/Parser/GenericElementParser.h +++ b/Swiften/Parser/GenericElementParser.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -23,5 +23,5 @@ namespace Swift { } - virtual boost::shared_ptr<Element> getElement() const { + virtual boost::shared_ptr<ToplevelElement> getElement() const { return stanza_; } diff --git a/Swiften/Parser/GenericPayloadParserFactory2.h b/Swiften/Parser/GenericPayloadParserFactory2.h new file mode 100644 index 0000000..f24b64e --- /dev/null +++ b/Swiften/Parser/GenericPayloadParserFactory2.h @@ -0,0 +1,39 @@ +/* + * 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/PayloadParserFactory.h> +#include <string> + +namespace Swift { + class PayloadParserFactoryCollection; + + /** + * A generic class for PayloadParserFactories that parse a specific payload (given as the template parameter of the class). + */ + template<typename PARSER_TYPE> + class GenericPayloadParserFactory2 : public PayloadParserFactory { + public: + /** + * Construct a parser factory that can parse the given top-level tag in the given namespace. + */ + GenericPayloadParserFactory2(const std::string& tag, const std::string& xmlns, PayloadParserFactoryCollection* parsers) : tag_(tag), xmlns_(xmlns), parsers_(parsers) {} + + virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const { + return (tag_.empty() ? true : element == tag_) && (xmlns_.empty() ? true : xmlns_ == ns); + } + + virtual PayloadParser* createPayloadParser() { + return new PARSER_TYPE(parsers_); + } + + private: + std::string tag_; + std::string xmlns_; + PayloadParserFactoryCollection* parsers_; + }; +} diff --git a/Swiften/Parser/GenericStanzaParser.h b/Swiften/Parser/GenericStanzaParser.h index c756c9a..2aff4d5 100644 --- a/Swiften/Parser/GenericStanzaParser.h +++ b/Swiften/Parser/GenericStanzaParser.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -24,5 +24,5 @@ namespace Swift { } - virtual boost::shared_ptr<Element> getElement() const { + virtual boost::shared_ptr<ToplevelElement> getElement() const { return stanza_; } diff --git a/Swiften/Parser/IQParser.h b/Swiften/Parser/IQParser.h index a7aa967..9773835 100644 --- a/Swiften/Parser/IQParser.h +++ b/Swiften/Parser/IQParser.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Parser/GenericStanzaParser.h> #include <Swiften/Elements/IQ.h> namespace Swift { - class IQParser : public GenericStanzaParser<IQ> { + class SWIFTEN_API IQParser : public GenericStanzaParser<IQ> { public: IQParser(PayloadParserFactoryCollection* factories); diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index 1590262..e4938e1 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,12 +8,19 @@ #include <iostream> +#include <boost/numeric/conversion/cast.hpp> #include <cassert> #include <cstring> - +#include <libxml/parser.h> #include <string> + #include <Swiften/Parser/XMLParserClient.h> namespace Swift { +struct LibXMLParser::Private { + xmlSAXHandler handler_; + xmlParserCtxtPtr context_; +}; + static void handleStartElement(void* parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { AttributeMap attributeValues; @@ -27,5 +34,9 @@ static void handleStartElement(void* parser, const xmlChar* name, const xmlChar* attributeNS = std::string(reinterpret_cast<const char*>(attributes[i+2])); } - attributeValues.addAttribute(std::string(reinterpret_cast<const char*>(attributes[i])), attributeNS, std::string(reinterpret_cast<const char*>(attributes[i+3]), attributes[i+4]-attributes[i+3])); + attributeValues.addAttribute( + std::string(reinterpret_cast<const char*>(attributes[i])), + attributeNS, + std::string(reinterpret_cast<const char*>(attributes[i+3]), + boost::numeric_cast<size_t>(attributes[i+4]-attributes[i+3]))); } static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); @@ -37,5 +48,5 @@ static void handleEndElement(void *parser, const xmlChar* name, const xmlChar*, static void handleCharacterData(void* parser, const xmlChar* data, int len) { - static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(reinterpret_cast<const char*>(data), len)); + static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(reinterpret_cast<const char*>(data), boost::numeric_cast<size_t>(len))); } @@ -54,5 +65,5 @@ static void handleWarning(void*, const char*, ... ) { bool LibXMLParser::initialized = false; -LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client) { +LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client), p(new Private()) { // Initialize libXML for multithreaded applications if (!initialized) { @@ -61,30 +72,31 @@ LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client) { } - memset(&handler_, 0, sizeof(handler_) ); - handler_.initialized = XML_SAX2_MAGIC; - handler_.startElementNs = &handleStartElement; - handler_.endElementNs = &handleEndElement; - handler_.characters = &handleCharacterData; - handler_.warning = &handleWarning; - handler_.error = &handleError; + memset(&p->handler_, 0, sizeof(p->handler_) ); + p->handler_.initialized = XML_SAX2_MAGIC; + p->handler_.startElementNs = &handleStartElement; + p->handler_.endElementNs = &handleEndElement; + p->handler_.characters = &handleCharacterData; + p->handler_.warning = &handleWarning; + p->handler_.error = &handleError; - context_ = xmlCreatePushParserCtxt(&handler_, this, 0, 0, 0); - assert(context_); + p->context_ = xmlCreatePushParserCtxt(&p->handler_, this, 0, 0, 0); + xmlCtxtUseOptions(p->context_, XML_PARSE_NOENT); + assert(p->context_); } LibXMLParser::~LibXMLParser() { - if (context_) { - xmlFreeParserCtxt(context_); + if (p->context_) { + xmlFreeParserCtxt(p->context_); } } bool LibXMLParser::parse(const std::string& data) { - if (xmlParseChunk(context_, data.c_str(), data.size(), false) == XML_ERR_OK) { + if (xmlParseChunk(p->context_, data.c_str(), boost::numeric_cast<int>(data.size()), false) == XML_ERR_OK) { return true; } - xmlError* error = xmlCtxtGetLastError(context_); + xmlError* error = xmlCtxtGetLastError(p->context_); if (error->code == XML_WAR_NS_URI || error->code == XML_WAR_NS_URI_RELATIVE) { - xmlCtxtResetLastError(context_); - context_->errNo = XML_ERR_OK; + xmlCtxtResetLastError(p->context_); + p->context_->errNo = XML_ERR_OK; return true; } diff --git a/Swiften/Parser/LibXMLParser.h b/Swiften/Parser/LibXMLParser.h index cd73637..b8e1d7c 100644 --- a/Swiften/Parser/LibXMLParser.h +++ b/Swiften/Parser/LibXMLParser.h @@ -7,6 +7,6 @@ #pragma once -#include <libxml/parser.h> #include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> #include <Swiften/Parser/XMLParser.h> @@ -26,6 +26,7 @@ namespace Swift { private: static bool initialized; - xmlSAXHandler handler_; - xmlParserCtxtPtr context_; + + struct Private; + boost::shared_ptr<Private> p; }; } diff --git a/Swiften/Parser/MessageParser.h b/Swiften/Parser/MessageParser.h index a8aaa99..e908339 100644 --- a/Swiften/Parser/MessageParser.h +++ b/Swiften/Parser/MessageParser.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Parser/GenericStanzaParser.h> #include <Swiften/Elements/Message.h> namespace Swift { - class MessageParser : public GenericStanzaParser<Message> { + class SWIFTEN_API MessageParser : public GenericStanzaParser<Message> { public: MessageParser(PayloadParserFactoryCollection* factories); diff --git a/Swiften/Parser/PayloadParser.h b/Swiften/Parser/PayloadParser.h index 8a9a290..bb1ae3c 100644 --- a/Swiften/Parser/PayloadParser.h +++ b/Swiften/Parser/PayloadParser.h @@ -8,6 +8,8 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Parser/AttributeMap.h> + +#include <Swiften/Base/API.h> +#include <Swiften/Parser/AttributeMap.h> #include <Swiften/Elements/Payload.h> @@ -23,5 +25,5 @@ namespace Swift { * payload. */ - class PayloadParser { + class SWIFTEN_API PayloadParser { public: virtual ~PayloadParser(); diff --git a/Swiften/Parser/PayloadParserFactory.h b/Swiften/Parser/PayloadParserFactory.h index 5619d21..e265e5b 100644 --- a/Swiften/Parser/PayloadParserFactory.h +++ b/Swiften/Parser/PayloadParserFactory.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Parser/AttributeMap.h> @@ -16,5 +17,5 @@ namespace Swift { * A factory for PayloadParsers. */ - class PayloadParserFactory { + class SWIFTEN_API PayloadParserFactory { public: virtual ~PayloadParserFactory(); diff --git a/Swiften/Parser/PayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParserFactoryCollection.cpp index e3efc3d..269ac3d 100644 --- a/Swiften/Parser/PayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParserFactoryCollection.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -21,5 +21,5 @@ void PayloadParserFactoryCollection::addFactory(PayloadParserFactory* factory) { void PayloadParserFactoryCollection::removeFactory(PayloadParserFactory* factory) { - factories_.erase(remove(factories_.begin(), factories_.end(), factory), factories_.end()); + factories_.erase(std::remove(factories_.begin(), factories_.end(), factory), factories_.end()); } diff --git a/Swiften/Parser/PayloadParserFactoryCollection.h b/Swiften/Parser/PayloadParserFactoryCollection.h index 6407641..1dbdd32 100644 --- a/Swiften/Parser/PayloadParserFactoryCollection.h +++ b/Swiften/Parser/PayloadParserFactoryCollection.h @@ -10,9 +10,10 @@ #include <Swiften/Parser/AttributeMap.h> +#include <Swiften/Base/API.h> namespace Swift { class PayloadParserFactory; - class PayloadParserFactoryCollection { + class SWIFTEN_API PayloadParserFactoryCollection { public: PayloadParserFactoryCollection(); diff --git a/Swiften/Parser/PayloadParsers/BlockParser.h b/Swiften/Parser/PayloadParsers/BlockParser.h index cd727ad..6ee47a2 100644 --- a/Swiften/Parser/PayloadParsers/BlockParser.h +++ b/Swiften/Parser/PayloadParsers/BlockParser.h @@ -8,4 +8,5 @@ #include <Swiften/Elements/Nickname.h> +#include <Swiften/JID/JID.h> #include <Swiften/Parser/GenericPayloadParser.h> @@ -14,5 +15,5 @@ namespace Swift { class BlockParser : public GenericPayloadParser<BLOCK_ELEMENT> { public: - BlockParser() : GenericPayloadParser<BLOCK_ELEMENT>() { + BlockParser() : GenericPayloadParser<BLOCK_ELEMENT>(), level(0) { } diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.h b/Swiften/Parser/PayloadParsers/BytestreamsParser.h index 4785913..5c151c2 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParser.h +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.h @@ -25,5 +25,5 @@ namespace Swift { enum Level { TopLevel = 0, - PayloadLevel = 1, + PayloadLevel = 1 }; int level; diff --git a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp index 14ff79d..aeb0db8 100644 --- a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp +++ b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp @@ -6,4 +6,6 @@ #include <Swiften/Parser/PayloadParsers/DiscoInfoParser.h> + +#include <boost/optional.hpp> #include <Swiften/Parser/PayloadParsers/FormParser.h> @@ -14,5 +16,10 @@ DiscoInfoParser::DiscoInfoParser() : level_(TopLevel), formParser_(NULL) { void DiscoInfoParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { - if (level_ == PayloadLevel) { + if (level_ == TopLevel) { + if (attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributes.getAttributeValue("node")); + } + } + else if (level_ == PayloadLevel) { if (element == "identity") { getPayloadInternal()->addIdentity(DiscoInfo::Identity(attributes.getAttribute("name"), attributes.getAttribute("category"), attributes.getAttribute("type"), attributes.getAttribute("lang", "http://www.w3.org/XML/1998/namespace"))); diff --git a/Swiften/Parser/PayloadParsers/DiscoInfoParser.h b/Swiften/Parser/PayloadParsers/DiscoInfoParser.h index df1441c..1f93a88 100644 --- a/Swiften/Parser/PayloadParsers/DiscoInfoParser.h +++ b/Swiften/Parser/PayloadParsers/DiscoInfoParser.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { - class DiscoInfoParser : public GenericPayloadParser<DiscoInfo> { + class SWIFTEN_API DiscoInfoParser : public GenericPayloadParser<DiscoInfo> { public: DiscoInfoParser(); diff --git a/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp b/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp index d6ac94d..a56dc5a 100644 --- a/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp +++ b/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp @@ -18,4 +18,9 @@ void DiscoItemsParser::handleStartElement(const std::string& element, const std: } } + else if (level_ == TopLevel) { + if (element == "query") { + getPayloadInternal()->setNode(attributes.getAttribute("node")); + } + } ++level_; } diff --git a/Swiften/Parser/PayloadParsers/FormParser.cpp b/Swiften/Parser/PayloadParsers/FormParser.cpp index 2df0a85..7c29189 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.cpp +++ b/Swiften/Parser/PayloadParsers/FormParser.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,5 +11,5 @@ namespace Swift { -FormParser::FormParser() : level_(TopLevel), parsingItem_(false), parsingReported_(false) { +FormParser::FormParser() : level_(TopLevel), parsingItem_(false), parsingReported_(false), parsingOption_(false) { } @@ -37,65 +37,60 @@ void FormParser::handleStartElement(const std::string& element, const std::strin currentText_.clear(); } - else if (element == "field") { - std::string type; - FormField::ref correspondingReportedField; - if (!parsingItem_) { - type = attributes.getAttribute("type"); - } else { - foreach(FormField::ref field, getPayloadInternal()->getReportedFields()) { - if (field->getName() == attributes.getAttribute("var")) { - correspondingReportedField = field; - break; + else if (element == "reported") { + parsingReported_ = true; } + else if (element == "item") { + parsingItem_ = true; } } - if (type == "boolean" || boost::dynamic_pointer_cast<BooleanFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = BooleanFormFieldParseHelper::create(); + else if (level_ == FieldLevel && currentField_) { + currentText_.clear(); + if (element == "option") { + currentOptionLabel_ = attributes.getAttribute("label"); + currentOptionValue_ = ""; + parsingOption_ = true; } - else if (type == "fixed" || boost::dynamic_pointer_cast<FixedFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = FixedFormFieldParseHelper::create(); } - else if (type == "hidden" || boost::dynamic_pointer_cast<HiddenFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = HiddenFormFieldParseHelper::create(); + if (level_ >= PayloadLevel) { + if (element == "field") { + currentField_ = boost::make_shared<FormField>(); + std::string type = attributes.getAttribute("type"); + FormField::Type fieldType = FormField::UnknownType; + if (type == "boolean") { + fieldType = FormField::BooleanType; } - else if (type == "jid-multi" || boost::dynamic_pointer_cast<JIDMultiFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = JIDMultiFormFieldParseHelper::create(); + if (type == "fixed") { + fieldType = FormField::FixedType; } - else if (type == "jid-single" || boost::dynamic_pointer_cast<JIDSingleFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = JIDSingleFormFieldParseHelper::create(); + if (type == "hidden") { + fieldType = FormField::HiddenType; } - else if (type == "list-multi" || boost::dynamic_pointer_cast<ListMultiFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = ListMultiFormFieldParseHelper::create(); + if (type == "list-single") { + fieldType = FormField::ListSingleType; } - else if (type == "list-single" || boost::dynamic_pointer_cast<ListSingleFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = ListSingleFormFieldParseHelper::create(); + if (type == "text-multi") { + fieldType = FormField::TextMultiType; } - else if (type == "text-multi" || boost::dynamic_pointer_cast<TextMultiFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = TextMultiFormFieldParseHelper::create(); + if (type == "text-private") { + fieldType = FormField::TextPrivateType; } - else if (type == "text-private" || boost::dynamic_pointer_cast<TextPrivateFormField>(correspondingReportedField)) { - currentFieldParseHelper_ = TextPrivateFormFieldParseHelper::create(); + if (type == "text-single") { + fieldType = FormField::TextSingleType; } - else /*if (type == "text-single") || undefined */ { - currentFieldParseHelper_ = TextSingleFormFieldParseHelper::create(); + if (type == "jid-single") { + fieldType = FormField::JIDSingleType; } - if (currentFieldParseHelper_) { - currentFieldParseHelper_->getField()->setName(attributes.getAttribute("var")); - currentFieldParseHelper_->getField()->setLabel(attributes.getAttribute("label")); + if (type == "jid-multi") { + fieldType = FormField::JIDMultiType; } + if (type == "list-multi") { + fieldType = FormField::ListMultiType; } - else if (element == "reported") { - parsingReported_ = true; - level_ = PayloadLevel - 1; + currentField_->setType(fieldType); + currentField_->setName(attributes.getAttribute("var")); + currentField_->setLabel(attributes.getAttribute("label")); } - else if (element == "item") { - parsingItem_ = true; - level_ = PayloadLevel - 1; - } - } - else if (level_ == FieldLevel && currentFieldParseHelper_) { + else if (element == "value") { currentText_.clear(); - if (element == "option") { - currentOptionLabel_ = attributes.getAttribute("label"); } } @@ -124,40 +119,46 @@ void FormParser::handleEndElement(const std::string& element, const std::string& } } - else if (element == "field") { - if (currentFieldParseHelper_) { - if (parsingReported_) { - getPayloadInternal()->addReportedField(currentFieldParseHelper_->getField()); - } else if (parsingItem_) { - currentFields_.push_back(currentFieldParseHelper_->getField()); - } else { - getPayloadInternal()->addField(currentFieldParseHelper_->getField()); - } - currentFieldParseHelper_.reset(); + else if (element == "reported") { + parsingReported_ = false; } + else if (element == "item") { + parsingItem_ = false; + getPayloadInternal()->addItem(currentFields_); + currentFields_.clear(); } } - else if (level_ == FieldLevel && currentFieldParseHelper_) { + else if (currentField_) { if (element == "required") { - currentFieldParseHelper_->getField()->setRequired(true); + currentField_->setRequired(true); } else if (element == "desc") { - currentFieldParseHelper_->getField()->setDescription(currentText_); + currentField_->setDescription(currentText_); } else if (element == "option") { - currentFieldParseHelper_->getField()->addOption(FormField::Option(currentOptionLabel_, currentText_)); + currentField_->addOption(FormField::Option(currentOptionLabel_, currentOptionValue_)); + parsingOption_ = false; } else if (element == "value") { - currentFieldParseHelper_->addValue(currentText_); + if (parsingOption_) { + currentOptionValue_ = currentText_; } + else { + currentField_->addValue(currentText_); } - if (element == "reported") { - parsingReported_ = false; - level_++; } - else if (element == "item") { - parsingItem_ = false; - level_++; - getPayloadInternal()->addItem(currentFields_); - currentFields_.clear(); + } + if (level_ >= PayloadLevel && currentField_) { + if (element == "field") { + if (parsingReported_) { + getPayloadInternal()->addReportedField(currentField_); + } + else if (parsingItem_) { + currentFields_.push_back(currentField_); + } + else { + getPayloadInternal()->addField(currentField_); + } + currentField_.reset(); + } } } diff --git a/Swiften/Parser/PayloadParsers/FormParser.h b/Swiften/Parser/PayloadParsers/FormParser.h index a3e2524..0b23a81 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.h +++ b/Swiften/Parser/PayloadParsers/FormParser.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,84 +19,4 @@ namespace Swift { virtual void handleCharacterData(const std::string& data); - private: - class FieldParseHelper { - public: - virtual ~FieldParseHelper() {} - virtual void addValue(const std::string&) = 0; - virtual boost::shared_ptr<FormField> getField() const { - return field; - } - protected: - boost::shared_ptr<FormField> field; - }; - class BoolFieldParseHelper : public FieldParseHelper { - virtual void addValue(const std::string& s) { - boost::dynamic_pointer_cast< GenericFormField<bool> >(getField())->setValue(s == "1" || s == "true"); - getField()->addRawValue(s); - } - }; - class StringFieldParseHelper : public FieldParseHelper { - virtual void addValue(const std::string& s) { - boost::shared_ptr<GenericFormField<std::string> > field = boost::dynamic_pointer_cast< GenericFormField<std::string> >(getField()); - if (field->getValue().empty()) { - field->setValue(s); - } - else { - field->setValue(field->getValue() + "\n" + s); - } - getField()->addRawValue(s); - } - }; - class JIDFieldParseHelper : public FieldParseHelper { - virtual void addValue(const std::string& s) { - getField()->addRawValue(s); - boost::dynamic_pointer_cast< GenericFormField<JID> >(getField())->setValue(JID(s)); - } - }; - class StringListFieldParseHelper : public FieldParseHelper { - virtual void addValue(const std::string& s) { - // FIXME: Inefficient, but too much hassle to do efficiently - boost::shared_ptr<GenericFormField< std::vector<std::string> > > field = boost::dynamic_pointer_cast< GenericFormField<std::vector<std::string > > >(getField()); - std::vector<std::string> l = field->getValue(); - l.push_back(s); - field->setValue(l); - getField()->addRawValue(s); - } - }; - class JIDListFieldParseHelper : public FieldParseHelper { - virtual void addValue(const std::string& s) { - // FIXME: Inefficient, but too much hassle to do efficiently - boost::shared_ptr< GenericFormField< std::vector<JID> > > field = boost::dynamic_pointer_cast< GenericFormField<std::vector<JID > > >(getField()); - std::vector<JID> l = field->getValue(); - l.push_back(JID(s)); - field->setValue(l); - getField()->addRawValue(s); - } - }; - -#define SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(name, baseParser) \ - class name##FormFieldParseHelper : public baseParser##FieldParseHelper { \ - public: \ - typedef boost::shared_ptr<name##FormFieldParseHelper> ref; \ - static ref create() { \ - return ref(new name##FormFieldParseHelper()); \ - } \ - private: \ - name##FormFieldParseHelper() : baseParser##FieldParseHelper() { \ - field = name##FormField::create(); \ - } \ - }; - - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Boolean, Bool); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Fixed, String); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Hidden, String); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(ListSingle, String); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(TextMulti, String); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(TextPrivate, String); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(TextSingle, String); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDSingle, JID); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDMulti, JIDList); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(ListMulti, StringList); - enum Level { TopLevel = 0, @@ -107,7 +27,9 @@ namespace Swift { std::string currentText_; std::string currentOptionLabel_; - boost::shared_ptr<FieldParseHelper> currentFieldParseHelper_; + std::string currentOptionValue_; bool parsingItem_; bool parsingReported_; + bool parsingOption_; + FormField::ref currentField_; std::vector<FormField::ref> currentFields_; }; diff --git a/Swiften/Parser/PayloadParsers/ForwardedParser.cpp b/Swiften/Parser/PayloadParsers/ForwardedParser.cpp new file mode 100644 index 0000000..6625e77 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ForwardedParser.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/IQParser.h> +#include <Swiften/Parser/MessageParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/DelayParser.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> +#include <Swiften/Parser/PresenceParser.h> + + +using namespace Swift; + +ForwardedParser::ForwardedParser(PayloadParserFactoryCollection* factories) : factories_(factories), level_(TopLevel) { +} + +void ForwardedParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == PayloadLevel) { + if (element == "iq" && ns == "jabber:client") { /* begin parsing a nested stanza? */ + childParser_ = boost::dynamic_pointer_cast<StanzaParser>(boost::make_shared<IQParser>(factories_)); + } else if (element == "message" && ns == "jabber:client") { + childParser_ = boost::dynamic_pointer_cast<StanzaParser>(boost::make_shared<MessageParser>(factories_)); + } else if (element == "presence" && ns == "jabber:client") { + childParser_ = boost::dynamic_pointer_cast<StanzaParser>(boost::make_shared<PresenceParser>(factories_)); + } else if (element == "delay" && ns == "urn:xmpp:delay") { /* nested delay payload */ + delayParser_ = boost::make_shared<DelayParser>(); + } + } + if (childParser_) { /* parsing a nested stanza? */ + childParser_->handleStartElement(element, ns, attributes); + } + if (delayParser_) { /* parsing a nested delay payload? */ + delayParser_->handleStartElement(element, ns, attributes); + } + ++level_; +} + +void ForwardedParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + if (childParser_ && level_ >= PayloadLevel) { + childParser_->handleEndElement(element, ns); + } + if (childParser_ && level_ == PayloadLevel) { + /* done parsing nested stanza */ + getPayloadInternal()->setStanza(childParser_->getStanza()); + childParser_.reset(); + } + if (delayParser_ && level_ >= PayloadLevel) { + delayParser_->handleEndElement(element, ns); + } + if (delayParser_ && level_ == PayloadLevel) { + /* done parsing nested delay payload */ + getPayloadInternal()->setDelay(boost::dynamic_pointer_cast<Delay>(delayParser_->getPayload())); + delayParser_.reset(); + } +} + +void ForwardedParser::handleCharacterData(const std::string& data) { + if (childParser_) { + childParser_->handleCharacterData(data); + } + if (delayParser_) { + delayParser_->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/ForwardedParser.h b/Swiften/Parser/PayloadParsers/ForwardedParser.h new file mode 100644 index 0000000..14117ae --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ForwardedParser.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class StanzaParser; + class DelayParser; + + class SWIFTEN_API ForwardedParser : public GenericPayloadParser<Forwarded> { + public: + ForwardedParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + PayloadParserFactoryCollection* factories_; + boost::shared_ptr<StanzaParser> childParser_; + boost::shared_ptr<DelayParser> delayParser_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index 01addf5..49dd1e3 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -6,65 +6,84 @@ #include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> + #include <Swiften/Base/foreach.h> + +#include <Swiften/Elements/BlockListPayload.h> #include <Swiften/Elements/BlockPayload.h> #include <Swiften/Elements/UnblockPayload.h> -#include <Swiften/Elements/BlockListPayload.h> + #include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/GenericPayloadParserFactory2.h> #include <Swiften/Parser/PayloadParserFactory.h> -#include <Swiften/Parser/PayloadParsers/ErrorParser.h> -#include <Swiften/Parser/PayloadParsers/ErrorParserFactory.h> -#include <Swiften/Parser/PayloadParsers/BodyParser.h> #include <Swiften/Parser/PayloadParsers/BlockParser.h> -#include <Swiften/Parser/PayloadParsers/SubjectParser.h> +#include <Swiften/Parser/PayloadParsers/BodyParser.h> +#include <Swiften/Parser/PayloadParsers/BytestreamsParser.h> +#include <Swiften/Parser/PayloadParsers/CapsInfoParser.h> #include <Swiften/Parser/PayloadParsers/ChatStateParserFactory.h> -#include <Swiften/Parser/PayloadParsers/PriorityParser.h> -#include <Swiften/Parser/PayloadParsers/ResourceBindParser.h> -#include <Swiften/Parser/PayloadParsers/StartSessionParser.h> -#include <Swiften/Parser/PayloadParsers/StatusParser.h> -#include <Swiften/Parser/PayloadParsers/StatusShowParser.h> -#include <Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h> -#include <Swiften/Parser/PayloadParsers/RosterParser.h> -#include <Swiften/Parser/PayloadParsers/SoftwareVersionParser.h> -#include <Swiften/Parser/PayloadParsers/StorageParser.h> +#include <Swiften/Parser/PayloadParsers/CommandParser.h> +#include <Swiften/Parser/PayloadParsers/DelayParser.h> +#include <Swiften/Parser/PayloadParsers/DeliveryReceiptParserFactory.h> +#include <Swiften/Parser/PayloadParsers/DeliveryReceiptRequestParserFactory.h> #include <Swiften/Parser/PayloadParsers/DiscoInfoParser.h> #include <Swiften/Parser/PayloadParsers/DiscoItemsParser.h> -#include <Swiften/Parser/PayloadParsers/CapsInfoParser.h> -#include <Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h> -#include <Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h> +#include <Swiften/Parser/PayloadParsers/ErrorParser.h> +#include <Swiften/Parser/PayloadParsers/ErrorParserFactory.h> #include <Swiften/Parser/PayloadParsers/FormParserFactory.h> -#include <Swiften/Parser/PayloadParsers/CommandParser.h> -#include <Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h> -#include <Swiften/Parser/PayloadParsers/SearchPayloadParser.h> -#include <Swiften/Parser/PayloadParsers/StreamInitiationParser.h> -#include <Swiften/Parser/PayloadParsers/BytestreamsParser.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> #include <Swiften/Parser/PayloadParsers/IBBParser.h> -#include <Swiften/Parser/PayloadParsers/VCardUpdateParser.h> -#include <Swiften/Parser/PayloadParsers/VCardParser.h> -#include <Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h> -#include <Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h> -#include <Swiften/Parser/PayloadParsers/DelayParser.h> -#include <Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/IdleParser.h> +#include <Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.h> +#include <Swiften/Parser/PayloadParsers/JingleContentPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h> +#include <Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/JingleParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleReasonParser.h> +#include <Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/LastParser.h> +#include <Swiften/Parser/PayloadParsers/MAMArchivedParser.h> +#include <Swiften/Parser/PayloadParsers/MAMQueryParser.h> +#include <Swiften/Parser/PayloadParsers/MAMResultParser.h> #include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h> -#include <Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h> #include <Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.h> #include <Swiften/Parser/PayloadParsers/MUCInvitationPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h> #include <Swiften/Parser/PayloadParsers/MUCOwnerPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h> #include <Swiften/Parser/PayloadParsers/NicknameParser.h> +#include <Swiften/Parser/PayloadParsers/PriorityParser.h> +#include <Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubParser.h> +#include <Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h> #include <Swiften/Parser/PayloadParsers/ReplaceParser.h> -#include <Swiften/Parser/PayloadParsers/LastParser.h> -#include <Swiften/Parser/PayloadParsers/JingleParserFactory.h> -#include <Swiften/Parser/PayloadParsers/JingleReasonParser.h> -#include <Swiften/Parser/PayloadParsers/JingleContentPayloadParserFactory.h> -#include <Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h> -#include <Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h> -#include <Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h> -#include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> -#include <Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h> -#include <Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h> +#include <Swiften/Parser/PayloadParsers/ResourceBindParser.h> +#include <Swiften/Parser/PayloadParsers/ResultSetParser.h> +#include <Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h> +#include <Swiften/Parser/PayloadParsers/RosterParser.h> #include <Swiften/Parser/PayloadParsers/S5BProxyRequestParser.h> -#include <Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h> -#include <Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h> -#include <Swiften/Parser/PayloadParsers/DeliveryReceiptParserFactory.h> -#include <Swiften/Parser/PayloadParsers/DeliveryReceiptRequestParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SearchPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h> +#include <Swiften/Parser/PayloadParsers/SoftwareVersionParser.h> +#include <Swiften/Parser/PayloadParsers/StartSessionParser.h> +#include <Swiften/Parser/PayloadParsers/StatusParser.h> +#include <Swiften/Parser/PayloadParsers/StatusShowParser.h> +#include <Swiften/Parser/PayloadParsers/StorageParser.h> +#include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> +#include <Swiften/Parser/PayloadParsers/StreamInitiationParser.h> +#include <Swiften/Parser/PayloadParsers/SubjectParser.h> +#include <Swiften/Parser/PayloadParsers/UserLocationParser.h> +#include <Swiften/Parser/PayloadParsers/UserTuneParser.h> +#include <Swiften/Parser/PayloadParsers/VCardParser.h> +#include <Swiften/Parser/PayloadParsers/VCardUpdateParser.h> +#include <Swiften/Parser/PayloadParsers/WhiteboardParser.h> using namespace boost; @@ -77,4 +96,5 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(boost::make_shared<GenericPayloadParserFactory<StatusParser> >("status")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<ReplaceParser> >("replace", "http://swift.im/protocol/replace")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<ReplaceParser> >("replace", "urn:xmpp:message-correct:0")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<LastParser> >("query", "jabber:iq:last")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<BodyParser> >("body")); @@ -124,6 +144,20 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(boost::make_shared<GenericPayloadParserFactory<JingleFileTransferHashParser> >("checksum")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<S5BProxyRequestParser> >("query", "http://jabber.org/protocol/bytestreams")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<WhiteboardParser> >("wb", "http://swift.im/whiteboard")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<UserLocationParser> >("geoloc", "http://jabber.org/protocol/geoloc")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<UserTuneParser> >("tune", "http://jabber.org/protocol/tune")); factories_.push_back(boost::make_shared<DeliveryReceiptParserFactory>()); factories_.push_back(boost::make_shared<DeliveryReceiptRequestParserFactory>()); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<IdleParser> >("idle", "urn:xmpp:idle:1")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubParser> >("pubsub", "http://jabber.org/protocol/pubsub", this)); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubOwnerPubSubParser> >("pubsub", "http://jabber.org/protocol/pubsub#owner", this)); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<PubSubEventParser> >("event", "http://jabber.org/protocol/pubsub#event", this)); + factories_.push_back(boost::make_shared<PubSubErrorParserFactory>()); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<ResultSetParser> >("set", "http://jabber.org/protocol/rsm")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<ForwardedParser> >("forwarded", "urn:xmpp:forward:0", this)); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<MAMResultParser> >("result", "urn:xmpp:mam:0", this)); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<MAMQueryParser> >("query", "urn:xmpp:mam:0")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<MAMArchivedParser> >("archived", "urn:xmpp:mam:0")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory2<IsodeIQDelegationParser> >("delegate", "http://isode.com/iq_delegation", this)); foreach(shared_ptr<PayloadParserFactory> factory, factories_) { diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h index 46b692b..91302b1 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h @@ -10,9 +10,10 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Parser/PayloadParserFactoryCollection.h> #include <Swiften/Parser/PayloadParserFactory.h> namespace Swift { - class FullPayloadParserFactoryCollection : public PayloadParserFactoryCollection { + class SWIFTEN_API FullPayloadParserFactoryCollection : public PayloadParserFactoryCollection { public: FullPayloadParserFactoryCollection(); diff --git a/Swiften/Parser/PayloadParsers/IBBParser.h b/Swiften/Parser/PayloadParsers/IBBParser.h index d899475..59011b4 100644 --- a/Swiften/Parser/PayloadParsers/IBBParser.h +++ b/Swiften/Parser/PayloadParsers/IBBParser.h @@ -24,5 +24,5 @@ namespace Swift { private: enum Level { - TopLevel = 0, + TopLevel = 0 }; int level; diff --git a/Swiften/Parser/PayloadParsers/IdleParser.cpp b/Swiften/Parser/PayloadParsers/IdleParser.cpp new file mode 100644 index 0000000..51aa34b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/IdleParser.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/IdleParser.h> + +#include <Swiften/Base/DateTime.h> + +namespace Swift { + +IdleParser::IdleParser() : level_(0) { +} + +void IdleParser::handleStartElement(const std::string& /*element*/, const std::string& /*ns*/, const AttributeMap& attributes) { + if (level_ == 0) { + boost::posix_time::ptime since = stringToDateTime(attributes.getAttribute("since")); + getPayloadInternal()->setSince(since); + } + ++level_; +} + +void IdleParser::handleEndElement(const std::string&, const std::string&) { + --level_; +} + +void IdleParser::handleCharacterData(const std::string&) { + +} + +} diff --git a/Swiften/Parser/PayloadParsers/IdleParser.h b/Swiften/Parser/PayloadParsers/IdleParser.h new file mode 100644 index 0000000..38001b2 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/IdleParser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Idle.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class IdleParser : public GenericPayloadParser<Idle> { + public: + IdleParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h index ae8d36c..1f85c85 100644 --- a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h +++ b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h @@ -28,5 +28,5 @@ namespace Swift { enum Level { TopLevel = 0, - PayloadLevel = 1, + PayloadLevel = 1 }; int level; diff --git a/Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.cpp b/Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.cpp new file mode 100644 index 0000000..d085d09 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Remko Tronçon and Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +IsodeIQDelegationParser::IsodeIQDelegationParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +IsodeIQDelegationParser::~IsodeIQDelegationParser() { +} + +void IsodeIQDelegationParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + + + if (level == 1) { + if (PayloadParserFactory* factory = parsers->getPayloadParserFactory(element, ns, attributes)) { + currentPayloadParser.reset(factory->createPayloadParser()); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void IsodeIQDelegationParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + getPayloadInternal()->setForward(boost::dynamic_pointer_cast<Forwarded>(currentPayloadParser->getPayload())); + currentPayloadParser.reset(); + } + } +} + +void IsodeIQDelegationParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.h b/Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.h new file mode 100644 index 0000000..83bf95e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/IsodeIQDelegationParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Remko Tronçon and Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/IsodeIQDelegation.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API IsodeIQDelegationParser : public GenericPayloadParser<IsodeIQDelegation> { + public: + IsodeIQDelegationParser(PayloadParserFactoryCollection* parsers); + virtual ~IsodeIQDelegationParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h index 93560c6..7ea22b4 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h @@ -27,5 +27,5 @@ class JingleFileTransferDescriptionParser : public GenericPayloadParser<JingleFi UnknownElement, RequestElement, - OfferElement, + OfferElement }; diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.cpp b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.cpp index 20ad73e..ae56981 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.cpp +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.cpp @@ -5,9 +5,9 @@ */ -#include "JingleFileTransferReceivedParser.h" -#include "StreamInitiationFileInfoParser.h" +#include <Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h> #include <boost/shared_ptr.hpp> #include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> +#include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> #include <Swiften/Parser/GenericPayloadParserFactory.h> #include <Swiften/Parser/PayloadParserFactory.h> diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h index 824b06d..d5333ad 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h @@ -26,2 +26,3 @@ private: } + diff --git a/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp index a3dfd12..d140368 100644 --- a/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include <boost/lexical_cast.hpp> #include <boost/optional.hpp> @@ -19,7 +25,10 @@ namespace Swift { void JingleIBBTransportMethodPayloadParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { try { - getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttributeValue("block-size").get_value_or("0"))); - } catch (boost::bad_lexical_cast &) { - getPayloadInternal()->setBlockSize(0); + boost::optional<std::string> blockSize = attributes.getAttributeValue("block-size"); + if (blockSize) { + getPayloadInternal()->setBlockSize(boost::lexical_cast<unsigned int>(*blockSize)); + } + } + catch (boost::bad_lexical_cast &) { } getPayloadInternal()->setSessionID(attributes.getAttributeValue("sid").get_value_or("")); diff --git a/Swiften/Parser/PayloadParsers/JingleParser.h b/Swiften/Parser/PayloadParsers/JingleParser.h index ecaca3c..c7bd58c 100644 --- a/Swiften/Parser/PayloadParsers/JingleParser.h +++ b/Swiften/Parser/PayloadParsers/JingleParser.h @@ -30,3 +30,4 @@ class JingleParser : public GenericPayloadParser<JinglePayload> { }; -};
\ No newline at end of file +} + diff --git a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp index 14a80e6..7be4c26 100644 --- a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp @@ -5,4 +5,10 @@ */ +/* +* Copyright (c) 2014 Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + #include <boost/lexical_cast.hpp> #include <boost/optional.hpp> @@ -26,5 +32,5 @@ namespace Swift { getPayloadInternal()->setMode(JingleS5BTransportPayload::UDPMode); } else { - std::cerr << "Unknown S5B mode; falling back to defaul!" << std::endl; + SWIFT_LOG(warning) << "Unknown S5B mode; falling back to defaul!"; getPayloadInternal()->setMode(JingleS5BTransportPayload::TCPMode); } @@ -82,5 +88,5 @@ namespace Swift { return JingleS5BTransportPayload::Candidate::ProxyType; } else { - std::cerr << "Unknown candidate type; falling back to default!" << std::endl; + SWIFT_LOG(warning) << "Unknown candidate type; falling back to default!"; return JingleS5BTransportPayload::Candidate::DirectType; } diff --git a/Swiften/Parser/PayloadParsers/MAMArchivedParser.cpp b/Swiften/Parser/PayloadParsers/MAMArchivedParser.cpp new file mode 100644 index 0000000..616d41a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMArchivedParser.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/MAMArchivedParser.h> + +using namespace Swift; + +MAMArchivedParser::MAMArchivedParser() : level_(TopLevel) { +} + +void MAMArchivedParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level_ == TopLevel) { + boost::optional<std::string> attributeValue; + if ((attributeValue = attributes.getAttributeValue("by"))) { + getPayloadInternal()->setBy(*attributeValue); + } + if ((attributeValue = attributes.getAttributeValue("id"))) { + getPayloadInternal()->setID(*attributeValue); + } + } + + ++level_; +} + +void MAMArchivedParser::handleEndElement(const std::string&, const std::string&) { + --level_; +} + +void MAMArchivedParser::handleCharacterData(const std::string&) { +} diff --git a/Swiften/Parser/PayloadParsers/MAMArchivedParser.h b/Swiften/Parser/PayloadParsers/MAMArchivedParser.h new file mode 100644 index 0000000..b92b41a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMArchivedParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMArchived.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + + class SWIFTEN_API MAMArchivedParser : public GenericPayloadParser<MAMArchived> { + public: + MAMArchivedParser(); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0 + }; + + private: + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/MAMQueryParser.cpp b/Swiften/Parser/PayloadParsers/MAMQueryParser.cpp new file mode 100644 index 0000000..9ae8e41 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMQueryParser.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> +#include <Swiften/Parser/PayloadParsers/ResultSetParser.h> +#include <Swiften/Parser/PayloadParsers/MAMQueryParser.h> + +using namespace Swift; + +MAMQueryParser::MAMQueryParser() : level_(TopLevel) { +} + +void MAMQueryParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == TopLevel) { + boost::optional<std::string> attributeValue; + if ((attributeValue = attributes.getAttributeValue("queryid"))) { + getPayloadInternal()->setQueryID(*attributeValue); + } + } else if (level_ == PayloadLevel) { + if (element == "x" && ns == "jabber:x:data") { + formParser_ = boost::make_shared<FormParser>(); + } else if (element == "set" && ns == "http://jabber.org/protocol/rsm") { + resultSetParser_ = boost::make_shared<ResultSetParser>(); + } + } + + if (formParser_) { /* parsing a nested Form */ + formParser_->handleStartElement(element, ns, attributes); + } + + if (resultSetParser_) { /* parsing a nested ResultSet */ + resultSetParser_->handleStartElement(element, ns, attributes); + } + + ++level_; +} + +void MAMQueryParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + + if (formParser_ && level_ >= PayloadLevel) { + formParser_->handleEndElement(element, ns); + } + if (formParser_ && level_ == PayloadLevel) { + /* done parsing nested Form */ + getPayloadInternal()->setForm(boost::dynamic_pointer_cast<Form>(formParser_->getPayload())); + formParser_.reset(); + } + + if (resultSetParser_ && level_ >= PayloadLevel) { + resultSetParser_->handleEndElement(element, ns); + } + if (resultSetParser_ && level_ == PayloadLevel) { + /* done parsing nested ResultSet */ + getPayloadInternal()->setResultSet(boost::dynamic_pointer_cast<ResultSet>(resultSetParser_->getPayload())); + resultSetParser_.reset(); + } +} + +void MAMQueryParser::handleCharacterData(const std::string& data) { + if (formParser_) { + formParser_->handleCharacterData(data); + } + if (resultSetParser_) { + resultSetParser_->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/MAMQueryParser.h b/Swiften/Parser/PayloadParsers/MAMQueryParser.h new file mode 100644 index 0000000..7bbdacb --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMQueryParser.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMQuery.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class ResultSetParser; + class FormParser; + + class SWIFTEN_API MAMQueryParser : public GenericPayloadParser<MAMQuery> { + public: + MAMQueryParser(); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + boost::shared_ptr<FormParser> formParser_; + boost::shared_ptr<ResultSetParser> resultSetParser_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/MAMResultParser.cpp b/Swiften/Parser/PayloadParsers/MAMResultParser.cpp new file mode 100644 index 0000000..e4eec3b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMResultParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> +#include <Swiften/Parser/PayloadParsers/MAMResultParser.h> + +using namespace Swift; + +MAMResultParser::MAMResultParser(PayloadParserFactoryCollection* factories) : factories_(factories), level_(TopLevel) { +} + +void MAMResultParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == TopLevel) { + boost::optional<std::string> attributeValue; + if ((attributeValue = attributes.getAttributeValue("id"))) { + getPayloadInternal()->setID(*attributeValue); + } + if ((attributeValue = attributes.getAttributeValue("queryid"))) { + getPayloadInternal()->setQueryID(*attributeValue); + } + } else if (level_ == PayloadLevel) { + if (element == "forwarded" && ns == "urn:xmpp:forward:0") { + payloadParser_ = boost::make_shared<ForwardedParser>(factories_); + } + } + + if (payloadParser_) { + /* parsing a nested payload */ + payloadParser_->handleStartElement(element, ns, attributes); + } + + ++level_; +} + +void MAMResultParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + if (payloadParser_ && level_ >= PayloadLevel) { + payloadParser_->handleEndElement(element, ns); + } + if (payloadParser_ && level_ == PayloadLevel) { + /* done parsing nested stanza */ + getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<Forwarded>(payloadParser_->getPayload())); + payloadParser_.reset(); + } +} + +void MAMResultParser::handleCharacterData(const std::string& data) { + if (payloadParser_) { + payloadParser_->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/MAMResultParser.h b/Swiften/Parser/PayloadParsers/MAMResultParser.h new file mode 100644 index 0000000..39ff20a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MAMResultParser.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class ForwardedParser; + + class SWIFTEN_API MAMResultParser : public GenericPayloadParser<MAMResult> { + public: + MAMResultParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + boost::shared_ptr<ForwardedParser> payloadParser_; + PayloadParserFactoryCollection* factories_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/MUCInvitationPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCInvitationPayloadParser.cpp index fa95af7..90590ee 100644 --- a/Swiften/Parser/PayloadParsers/MUCInvitationPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/MUCInvitationPayloadParser.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -6,6 +6,5 @@ #include <Swiften/Parser/PayloadParsers/MUCInvitationPayloadParser.h> - - +#include <Swiften/Parser/Tree/NullParserElement.h> namespace Swift { @@ -18,4 +17,6 @@ void MUCInvitationPayloadParser::handleTree(ParserElement::ref root) { invite->setReason(root->getAttributes().getAttribute("reason")); invite->setThread(root->getAttributes().getAttribute("thread")); + ParserElement::ref impromptuNode = root->getChild("impromptu", "http://swift.im/impromptu"); + invite->setIsImpromptu(!boost::dynamic_pointer_cast<NullParserElement>(impromptuNode)); } diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.cpp b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.cpp new file mode 100644 index 0000000..044aea9 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/EnumParser.h> + +using namespace Swift; + +PubSubAffiliationParser::PubSubAffiliationParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubAffiliationParser::~PubSubAffiliationParser() { +} + +void PubSubAffiliationParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("affiliation")) { + if (boost::optional<PubSubAffiliation::Type> value = EnumParser<PubSubAffiliation::Type>()(PubSubAffiliation::None, "none")(PubSubAffiliation::Member, "member")(PubSubAffiliation::Outcast, "outcast")(PubSubAffiliation::Owner, "owner")(PubSubAffiliation::Publisher, "publisher")(PubSubAffiliation::PublishOnly, "publish-only").parse(*attributeValue)) { + getPayloadInternal()->setType(*value); + } + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubAffiliationParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubAffiliationParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h new file mode 100644 index 0000000..82d4fac --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubAffiliation.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubAffiliationParser : public GenericPayloadParser<PubSubAffiliation> { + public: + PubSubAffiliationParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubAffiliationParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.cpp new file mode 100644 index 0000000..7b35b33 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubAffiliationParser.h> + +using namespace Swift; + +PubSubAffiliationsParser::PubSubAffiliationsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubAffiliationsParser::~PubSubAffiliationsParser() { +} + +void PubSubAffiliationsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubAffiliationParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubAffiliationsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub") { + getPayloadInternal()->addAffiliation(boost::dynamic_pointer_cast<PubSubAffiliation>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubAffiliationsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h new file mode 100644 index 0000000..c730a1b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubAffiliations.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubAffiliationsParser : public GenericPayloadParser<PubSubAffiliations> { + public: + PubSubAffiliationsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubAffiliationsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubConfigureParser.cpp b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.cpp new file mode 100644 index 0000000..b6099b4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubConfigureParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> + +using namespace Swift; + +PubSubConfigureParser::PubSubConfigureParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubConfigureParser::~PubSubConfigureParser() { +} + +void PubSubConfigureParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + currentPayloadParser = boost::make_shared<FormParser>(); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubConfigureParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubConfigureParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubConfigureParser.h b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.h new file mode 100644 index 0000000..8d58129 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubConfigureParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubConfigure.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubConfigureParser : public GenericPayloadParser<PubSubConfigure> { + public: + PubSubConfigureParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubConfigureParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubCreateParser.cpp b/Swiften/Parser/PayloadParsers/PubSubCreateParser.cpp new file mode 100644 index 0000000..3c81a6f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubCreateParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubCreateParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubCreateParser::PubSubCreateParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubCreateParser::~PubSubCreateParser() { +} + +void PubSubCreateParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubCreateParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubCreateParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubCreateParser.h b/Swiften/Parser/PayloadParsers/PubSubCreateParser.h new file mode 100644 index 0000000..2ddc80f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubCreateParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubCreate.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubCreateParser : public GenericPayloadParser<PubSubCreate> { + public: + PubSubCreateParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubCreateParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubDefaultParser.cpp b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.cpp new file mode 100644 index 0000000..a82c8b0 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubDefaultParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/EnumParser.h> + +using namespace Swift; + +PubSubDefaultParser::PubSubDefaultParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubDefaultParser::~PubSubDefaultParser() { +} + +void PubSubDefaultParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("type")) { + if (boost::optional<PubSubDefault::Type> value = EnumParser<PubSubDefault::Type>()(PubSubDefault::None, "none")(PubSubDefault::Collection, "collection")(PubSubDefault::Leaf, "leaf").parse(*attributeValue)) { + getPayloadInternal()->setType(*value); + } + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubDefaultParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubDefaultParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubDefaultParser.h b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.h new file mode 100644 index 0000000..ee56e73 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubDefaultParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubDefault.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubDefaultParser : public GenericPayloadParser<PubSubDefault> { + public: + PubSubDefaultParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubDefaultParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParser.cpp b/Swiften/Parser/PayloadParsers/PubSubErrorParser.cpp new file mode 100644 index 0000000..9752cd2 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubErrorParser.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/PubSubErrorParser.h> + +using namespace Swift; + +PubSubErrorParser::PubSubErrorParser() : level(0) { + typeParser + (PubSubError::ClosedNode, "closed-node") + (PubSubError::ConfigurationRequired, "configuration-required") + (PubSubError::InvalidJID, "invalid-jid") + (PubSubError::InvalidOptions, "invalid-options") + (PubSubError::InvalidPayload, "invalid-payload") + (PubSubError::InvalidSubscriptionID, "invalid-subid") + (PubSubError::ItemForbidden, "item-forbidden") + (PubSubError::ItemRequired, "item-required") + (PubSubError::JIDRequired, "jid-required") + (PubSubError::MaximumItemsExceeded, "max-items-exceeded") + (PubSubError::MaximumNodesExceeded, "max-nodes-exceeded") + (PubSubError::NodeIDRequired, "nodeid-required") + (PubSubError::NotInRosterGroup, "not-in-roster-group") + (PubSubError::NotSubscribed, "not-subscribed") + (PubSubError::PayloadTooBig, "payload-too-big") + (PubSubError::PayloadRequired, "payload-required") + (PubSubError::PendingSubscription, "pending-subscription") + (PubSubError::PresenceSubscriptionRequired, "presence-subscription-required") + (PubSubError::SubscriptionIDRequired, "subid-required") + (PubSubError::TooManySubscriptions, "too-many-subscriptions") + (PubSubError::Unsupported, "unsupported") + (PubSubError::UnsupportedAccessModel, "unsupported-access-model"); + unsupportedTypeParser + (PubSubError::AccessAuthorize, "access-authorize") + (PubSubError::AccessOpen, "access-open") + (PubSubError::AccessPresence, "access-presence") + (PubSubError::AccessRoster, "access-roster") + (PubSubError::AccessWhitelist, "access-whitelist") + (PubSubError::AutoCreate, "auto-create") + (PubSubError::AutoSubscribe, "auto-subscribe") + (PubSubError::Collections, "collections") + (PubSubError::ConfigNode, "config-node") + (PubSubError::CreateAndConfigure, "create-and-configure") + (PubSubError::CreateNodes, "create-nodes") + (PubSubError::DeleteItems, "delete-items") + (PubSubError::DeleteNodes, "delete-nodes") + (PubSubError::FilteredNotifications, "filtered-notifications") + (PubSubError::GetPending, "get-pending") + (PubSubError::InstantNodes, "instant-nodes") + (PubSubError::ItemIDs, "item-ids") + (PubSubError::LastPublished, "last-published") + (PubSubError::LeasedSubscription, "leased-subscription") + (PubSubError::ManageSubscriptions, "manage-subscriptions") + (PubSubError::MemberAffiliation, "member-affiliation") + (PubSubError::MetaData, "meta-data") + (PubSubError::ModifyAffiliations, "modify-affiliations") + (PubSubError::MultiCollection, "multi-collection") + (PubSubError::MultiSubscribe, "multi-subscribe") + (PubSubError::OutcastAffiliation, "outcast-affiliation") + (PubSubError::PersistentItems, "persistent-items") + (PubSubError::PresenceNotifications, "presence-notifications") + (PubSubError::PresenceSubscribe, "presence-subscribe") + (PubSubError::Publish, "publish") + (PubSubError::PublishOptions, "publish-options") + (PubSubError::PublishOnlyAffiliation, "publish-only-affiliation") + (PubSubError::PublisherAffiliation, "publisher-affiliation") + (PubSubError::PurgeNodes, "purge-nodes") + (PubSubError::RetractItems, "retract-items") + (PubSubError::RetrieveAffiliations, "retrieve-affiliations") + (PubSubError::RetrieveDefault, "retrieve-default") + (PubSubError::RetrieveItems, "retrieve-items") + (PubSubError::RetrieveSubscriptions, "retrieve-subscriptions") + (PubSubError::Subscribe, "subscribe") + (PubSubError::SubscriptionOptions, "subscription-options") + (PubSubError::SubscriptionNotifications, "subscription-notifications"); +} + +PubSubErrorParser::~PubSubErrorParser() { +} + +void PubSubErrorParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (level == 1) { + if (boost::optional<PubSubError::Type> type = typeParser.parse(element)) { + getPayloadInternal()->setType(*type); + if (type == PubSubError::Unsupported) { + if (boost::optional<std::string> feature = attributes.getAttributeValue("feature")) { + if (boost::optional<PubSubError::UnsupportedFeatureType> unsupportedType = unsupportedTypeParser.parse(*feature)) { + getPayloadInternal()->setUnsupportedFeatureType(*unsupportedType); + } + } + } + } + } + ++level; +} + +void PubSubErrorParser::handleEndElement(const std::string&, const std::string&) { + --level; +} + +void PubSubErrorParser::handleCharacterData(const std::string&) { +} diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParser.h b/Swiften/Parser/PayloadParsers/PubSubErrorParser.h new file mode 100644 index 0000000..eb7dcfe --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubErrorParser.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubError.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/EnumParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubErrorParser : public GenericPayloadParser<PubSubError> { + public: + PubSubErrorParser(); + virtual ~PubSubErrorParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + int level; + EnumParser<PubSubError::Type> typeParser; + EnumParser<PubSubError::UnsupportedFeatureType> unsupportedTypeParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.cpp b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.cpp new file mode 100644 index 0000000..10dfd63 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h> + +using namespace Swift; + +PubSubErrorParserFactory::~PubSubErrorParserFactory() { +} diff --git a/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h new file mode 100644 index 0000000..e2386da --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubErrorParser.h> + +namespace Swift { + class PubSubErrorParserFactory : public PayloadParserFactory { + public: + PubSubErrorParserFactory() { + } + ~PubSubErrorParserFactory(); + + virtual bool canParse(const std::string&, const std::string& ns, const AttributeMap&) const { + return ns == "http://jabber.org/protocol/pubsub#errors"; + } + + virtual PayloadParser* createPayloadParser() { + return new PubSubErrorParser(); + } + }; +} + + diff --git a/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.cpp new file mode 100644 index 0000000..cff6f22 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubEventAssociateParser::PubSubEventAssociateParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventAssociateParser::~PubSubEventAssociateParser() { +} + +void PubSubEventAssociateParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventAssociateParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubEventAssociateParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h new file mode 100644 index 0000000..97db1b3 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventAssociate.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventAssociateParser : public GenericPayloadParser<PubSubEventAssociate> { + public: + PubSubEventAssociateParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventAssociateParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.cpp new file mode 100644 index 0000000..e9ecdc8 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventAssociateParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h> + +using namespace Swift; + +PubSubEventCollectionParser::PubSubEventCollectionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventCollectionParser::~PubSubEventCollectionParser() { +} + +void PubSubEventCollectionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "disassociate" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventDisassociateParser>(parsers); + } + if (element == "associate" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventAssociateParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventCollectionParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "disassociate" && ns == "http://jabber.org/protocol/pubsub#event") { + getPayloadInternal()->setDisassociate(boost::dynamic_pointer_cast<PubSubEventDisassociate>(currentPayloadParser->getPayload())); + } + if (element == "associate" && ns == "http://jabber.org/protocol/pubsub#event") { + getPayloadInternal()->setAssociate(boost::dynamic_pointer_cast<PubSubEventAssociate>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubEventCollectionParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h new file mode 100644 index 0000000..05e780b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventCollection.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventCollectionParser : public GenericPayloadParser<PubSubEventCollection> { + public: + PubSubEventCollectionParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventCollectionParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.cpp new file mode 100644 index 0000000..cb9c752 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> + +using namespace Swift; + +PubSubEventConfigurationParser::PubSubEventConfigurationParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventConfigurationParser::~PubSubEventConfigurationParser() { +} + +void PubSubEventConfigurationParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + currentPayloadParser = boost::make_shared<FormParser>(); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventConfigurationParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubEventConfigurationParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h new file mode 100644 index 0000000..49373b9 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventConfiguration.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventConfigurationParser : public GenericPayloadParser<PubSubEventConfiguration> { + public: + PubSubEventConfigurationParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventConfigurationParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.cpp new file mode 100644 index 0000000..258d8bc --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h> + +using namespace Swift; + +PubSubEventDeleteParser::PubSubEventDeleteParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventDeleteParser::~PubSubEventDeleteParser() { +} + +void PubSubEventDeleteParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventRedirectParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventDeleteParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#event") { + getPayloadInternal()->setRedirects(boost::dynamic_pointer_cast<PubSubEventRedirect>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubEventDeleteParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h new file mode 100644 index 0000000..415f496 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventDelete.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventDeleteParser : public GenericPayloadParser<PubSubEventDelete> { + public: + PubSubEventDeleteParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventDeleteParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.cpp new file mode 100644 index 0000000..e492805 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubEventDisassociateParser::PubSubEventDisassociateParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventDisassociateParser::~PubSubEventDisassociateParser() { +} + +void PubSubEventDisassociateParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventDisassociateParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubEventDisassociateParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h new file mode 100644 index 0000000..9bebd39 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventDisassociateParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventDisassociate.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventDisassociateParser : public GenericPayloadParser<PubSubEventDisassociate> { + public: + PubSubEventDisassociateParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventDisassociateParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.cpp new file mode 100644 index 0000000..664028b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventItemParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubEventItemParser::PubSubEventItemParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventItemParser::~PubSubEventItemParser() { +} + +void PubSubEventItemParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("publisher")) { + getPayloadInternal()->setPublisher(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("id")) { + getPayloadInternal()->setID(*attributeValue); + } + } + + if (level == 1) { + if (PayloadParserFactory* factory = parsers->getPayloadParserFactory(element, ns, attributes)) { + currentPayloadParser.reset(factory->createPayloadParser()); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventItemParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + getPayloadInternal()->addData(currentPayloadParser->getPayload()); + currentPayloadParser.reset(); + } + } +} + +void PubSubEventItemParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemParser.h b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.h new file mode 100644 index 0000000..09fbc0e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventItemParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventItem.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventItemParser : public GenericPayloadParser<PubSubEventItem> { + public: + PubSubEventItemParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventItemParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.cpp new file mode 100644 index 0000000..aa1da86 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventItemParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h> + +using namespace Swift; + +PubSubEventItemsParser::PubSubEventItemsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventItemsParser::~PubSubEventItemsParser() { +} + +void PubSubEventItemsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventItemParser>(parsers); + } + if (element == "retract" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventRetractParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventItemsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub#event") { + getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubEventItem>(currentPayloadParser->getPayload())); + } + if (element == "retract" && ns == "http://jabber.org/protocol/pubsub#event") { + getPayloadInternal()->addRetract(boost::dynamic_pointer_cast<PubSubEventRetract>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubEventItemsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h new file mode 100644 index 0000000..a379b42 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventItems.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventItemsParser : public GenericPayloadParser<PubSubEventItems> { + public: + PubSubEventItemsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventItemsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventParser.cpp new file mode 100644 index 0000000..c4406a9 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventParser.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventItemsParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventDeleteParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventCollectionParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubEventConfigurationParser.h> + +using namespace Swift; + +PubSubEventParser::PubSubEventParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventParser::~PubSubEventParser() { +} + +void PubSubEventParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + + + if (level == 1) { + if (element == "items" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventItemsParser>(parsers); + } + if (element == "collection" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventCollectionParser>(parsers); + } + if (element == "purge" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventPurgeParser>(parsers); + } + if (element == "configuration" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventConfigurationParser>(parsers); + } + if (element == "delete" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventDeleteParser>(parsers); + } + if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub#event") { + currentPayloadParser = boost::make_shared<PubSubEventSubscriptionParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (currentPayloadParser) { + getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<PubSubEventPayload>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubEventParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventParser.h b/Swiften/Parser/PayloadParsers/PubSubEventParser.h new file mode 100644 index 0000000..1042e75 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEvent.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventParser : public GenericPayloadParser<PubSubEvent> { + public: + PubSubEventParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.cpp new file mode 100644 index 0000000..936766e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubEventPurgeParser::PubSubEventPurgeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventPurgeParser::~PubSubEventPurgeParser() { +} + +void PubSubEventPurgeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventPurgeParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubEventPurgeParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h new file mode 100644 index 0000000..edc386c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventPurgeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventPurge.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventPurgeParser : public GenericPayloadParser<PubSubEventPurge> { + public: + PubSubEventPurgeParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventPurgeParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.cpp new file mode 100644 index 0000000..971f5d6 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubEventRedirectParser::PubSubEventRedirectParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventRedirectParser::~PubSubEventRedirectParser() { +} + +void PubSubEventRedirectParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("uri")) { + getPayloadInternal()->setURI(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventRedirectParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubEventRedirectParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h new file mode 100644 index 0000000..5ead4d5 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventRedirectParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventRedirect.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventRedirectParser : public GenericPayloadParser<PubSubEventRedirect> { + public: + PubSubEventRedirectParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventRedirectParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.cpp new file mode 100644 index 0000000..c94f6bd --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubEventRetractParser::PubSubEventRetractParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventRetractParser::~PubSubEventRetractParser() { +} + +void PubSubEventRetractParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("id")) { + getPayloadInternal()->setID(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventRetractParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubEventRetractParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h new file mode 100644 index 0000000..98f460e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventRetractParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventRetract.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventRetractParser : public GenericPayloadParser<PubSubEventRetract> { + public: + PubSubEventRetractParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventRetractParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.cpp new file mode 100644 index 0000000..818ea2e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Parser/EnumParser.h> + +using namespace Swift; + +PubSubEventSubscriptionParser::PubSubEventSubscriptionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubEventSubscriptionParser::~PubSubEventSubscriptionParser() { +} + +void PubSubEventSubscriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) { + if (boost::optional<JID> jid = JID::parse(*attributeValue)) { + getPayloadInternal()->setJID(*jid); + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subscription")) { + if (boost::optional<PubSubEventSubscription::SubscriptionType> value = EnumParser<PubSubEventSubscription::SubscriptionType>()(PubSubEventSubscription::None, "none")(PubSubEventSubscription::Pending, "pending")(PubSubEventSubscription::Subscribed, "subscribed")(PubSubEventSubscription::Unconfigured, "unconfigured").parse(*attributeValue)) { + getPayloadInternal()->setSubscription(*value); + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) { + getPayloadInternal()->setSubscriptionID(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("expiry")) { + getPayloadInternal()->setExpiry(stringToDateTime(*attributeValue)); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubEventSubscriptionParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubEventSubscriptionParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h new file mode 100644 index 0000000..3b7d348 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubEventSubscriptionParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubEventSubscription.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubEventSubscriptionParser : public GenericPayloadParser<PubSubEventSubscription> { + public: + PubSubEventSubscriptionParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubEventSubscriptionParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp b/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp new file mode 100644 index 0000000..6f5cac4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubItemParser::PubSubItemParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubItemParser::~PubSubItemParser() { +} + +void PubSubItemParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("id")) { + getPayloadInternal()->setID(*attributeValue); + } + } + + if (level == 1) { + if (PayloadParserFactory* factory = parsers->getPayloadParserFactory(element, ns, attributes)) { + currentPayloadParser.reset(factory->createPayloadParser()); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubItemParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + getPayloadInternal()->addData(currentPayloadParser->getPayload()); + currentPayloadParser.reset(); + } + } +} + +void PubSubItemParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubItemParser.h b/Swiften/Parser/PayloadParsers/PubSubItemParser.h new file mode 100644 index 0000000..1382011 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubItemParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubItem.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubItemParser : public GenericPayloadParser<PubSubItem> { + public: + PubSubItemParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubItemParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubItemsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubItemsParser.cpp new file mode 100644 index 0000000..277d120 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubItemsParser.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubItemsParser.h> + +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h> + +using namespace Swift; + +PubSubItemsParser::PubSubItemsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubItemsParser::~PubSubItemsParser() { +} + +void PubSubItemsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("max_items")) { + try { + getPayloadInternal()->setMaximumItems(boost::lexical_cast<unsigned int>(*attributeValue)); + } + catch (boost::bad_lexical_cast&) { + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) { + getPayloadInternal()->setSubscriptionID(*attributeValue); + } + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubItemParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubItemsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub") { + getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubItem>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubItemsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubItemsParser.h b/Swiften/Parser/PayloadParsers/PubSubItemsParser.h new file mode 100644 index 0000000..49d8520 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubItemsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubItems.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubItemsParser : public GenericPayloadParser<PubSubItems> { + public: + PubSubItemsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubItemsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.cpp new file mode 100644 index 0000000..583dc10 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOptionsParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> + +using namespace Swift; + +PubSubOptionsParser::PubSubOptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOptionsParser::~PubSubOptionsParser() { +} + +void PubSubOptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) { + if (boost::optional<JID> jid = JID::parse(*attributeValue)) { + getPayloadInternal()->setJID(*jid); + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) { + getPayloadInternal()->setSubscriptionID(*attributeValue); + } + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + currentPayloadParser = boost::make_shared<FormParser>(); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOptionsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubOptionsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.h new file mode 100644 index 0000000..713901d --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOptionsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOptions.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOptionsParser : public GenericPayloadParser<PubSubOptions> { + public: + PubSubOptionsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOptionsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.cpp new file mode 100644 index 0000000..eeed548 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/EnumParser.h> + +using namespace Swift; + +PubSubOwnerAffiliationParser::PubSubOwnerAffiliationParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerAffiliationParser::~PubSubOwnerAffiliationParser() { +} + +void PubSubOwnerAffiliationParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) { + if (boost::optional<JID> jid = JID::parse(*attributeValue)) { + getPayloadInternal()->setJID(*jid); + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("affiliation")) { + if (boost::optional<PubSubOwnerAffiliation::Type> value = EnumParser<PubSubOwnerAffiliation::Type>()(PubSubOwnerAffiliation::None, "none")(PubSubOwnerAffiliation::Member, "member")(PubSubOwnerAffiliation::Outcast, "outcast")(PubSubOwnerAffiliation::Owner, "owner")(PubSubOwnerAffiliation::Publisher, "publisher")(PubSubOwnerAffiliation::PublishOnly, "publish-only").parse(*attributeValue)) { + getPayloadInternal()->setType(*value); + } + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerAffiliationParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerAffiliationParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h new file mode 100644 index 0000000..6fb6772 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerAffiliation.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerAffiliationParser : public GenericPayloadParser<PubSubOwnerAffiliation> { + public: + PubSubOwnerAffiliationParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerAffiliationParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.cpp new file mode 100644 index 0000000..d16db71 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationParser.h> + +using namespace Swift; + +PubSubOwnerAffiliationsParser::PubSubOwnerAffiliationsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerAffiliationsParser::~PubSubOwnerAffiliationsParser() { +} + +void PubSubOwnerAffiliationsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerAffiliationParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerAffiliationsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "affiliation" && ns == "http://jabber.org/protocol/pubsub#owner") { + getPayloadInternal()->addAffiliation(boost::dynamic_pointer_cast<PubSubOwnerAffiliation>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerAffiliationsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h new file mode 100644 index 0000000..2e2cd26 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerAffiliations.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerAffiliationsParser : public GenericPayloadParser<PubSubOwnerAffiliations> { + public: + PubSubOwnerAffiliationsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerAffiliationsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.cpp new file mode 100644 index 0000000..a90610e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> + +using namespace Swift; + +PubSubOwnerConfigureParser::PubSubOwnerConfigureParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerConfigureParser::~PubSubOwnerConfigureParser() { +} + +void PubSubOwnerConfigureParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + currentPayloadParser = boost::make_shared<FormParser>(); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerConfigureParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerConfigureParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h new file mode 100644 index 0000000..404954f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerConfigure.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerConfigureParser : public GenericPayloadParser<PubSubOwnerConfigure> { + public: + PubSubOwnerConfigureParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerConfigureParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.cpp new file mode 100644 index 0000000..55e6660 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> + +using namespace Swift; + +PubSubOwnerDefaultParser::PubSubOwnerDefaultParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerDefaultParser::~PubSubOwnerDefaultParser() { +} + +void PubSubOwnerDefaultParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + currentPayloadParser = boost::make_shared<FormParser>(); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerDefaultParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "x" && ns == "jabber:x:data") { + getPayloadInternal()->setData(boost::dynamic_pointer_cast<Form>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerDefaultParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h new file mode 100644 index 0000000..dba021a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerDefault.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerDefaultParser : public GenericPayloadParser<PubSubOwnerDefault> { + public: + PubSubOwnerDefaultParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerDefaultParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.cpp new file mode 100644 index 0000000..b8bc371 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h> + +using namespace Swift; + +PubSubOwnerDeleteParser::PubSubOwnerDeleteParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerDeleteParser::~PubSubOwnerDeleteParser() { +} + +void PubSubOwnerDeleteParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerRedirectParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerDeleteParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "redirect" && ns == "http://jabber.org/protocol/pubsub#owner") { + getPayloadInternal()->setRedirect(boost::dynamic_pointer_cast<PubSubOwnerRedirect>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerDeleteParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h new file mode 100644 index 0000000..4cf67e9 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerDelete.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerDeleteParser : public GenericPayloadParser<PubSubOwnerDelete> { + public: + PubSubOwnerDeleteParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerDeleteParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.cpp new file mode 100644 index 0000000..5262997 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerDefaultParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerDeleteParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerConfigureParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerAffiliationsParser.h> + +using namespace Swift; + +PubSubOwnerPubSubParser::PubSubOwnerPubSubParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerPubSubParser::~PubSubOwnerPubSubParser() { +} + +void PubSubOwnerPubSubParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + + + if (level == 1) { + if (element == "configure" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerConfigureParser>(parsers); + } + if (element == "subscriptions" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerSubscriptionsParser>(parsers); + } + if (element == "default" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerDefaultParser>(parsers); + } + if (element == "purge" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerPurgeParser>(parsers); + } + if (element == "affiliations" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerAffiliationsParser>(parsers); + } + if (element == "delete" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerDeleteParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerPubSubParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (currentPayloadParser) { + getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<PubSubOwnerPayload>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerPubSubParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h new file mode 100644 index 0000000..25fee8a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerPubSub.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerPubSubParser : public GenericPayloadParser<PubSubOwnerPubSub> { + public: + PubSubOwnerPubSubParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerPubSubParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.cpp new file mode 100644 index 0000000..8fc32dd --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubOwnerPurgeParser::PubSubOwnerPurgeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerPurgeParser::~PubSubOwnerPurgeParser() { +} + +void PubSubOwnerPurgeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerPurgeParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerPurgeParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h new file mode 100644 index 0000000..6f38fe6 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerPurgeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerPurge.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerPurgeParser : public GenericPayloadParser<PubSubOwnerPurge> { + public: + PubSubOwnerPurgeParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerPurgeParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.cpp new file mode 100644 index 0000000..132281a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubOwnerRedirectParser::PubSubOwnerRedirectParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerRedirectParser::~PubSubOwnerRedirectParser() { +} + +void PubSubOwnerRedirectParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("uri")) { + getPayloadInternal()->setURI(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerRedirectParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerRedirectParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h new file mode 100644 index 0000000..fd14760 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerRedirectParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerRedirect.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerRedirectParser : public GenericPayloadParser<PubSubOwnerRedirect> { + public: + PubSubOwnerRedirectParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerRedirectParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.cpp new file mode 100644 index 0000000..629249c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/EnumParser.h> + +using namespace Swift; + +PubSubOwnerSubscriptionParser::PubSubOwnerSubscriptionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerSubscriptionParser::~PubSubOwnerSubscriptionParser() { +} + +void PubSubOwnerSubscriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) { + if (boost::optional<JID> jid = JID::parse(*attributeValue)) { + getPayloadInternal()->setJID(*jid); + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subscription")) { + if (boost::optional<PubSubOwnerSubscription::SubscriptionType> value = EnumParser<PubSubOwnerSubscription::SubscriptionType>()(PubSubOwnerSubscription::None, "none")(PubSubOwnerSubscription::Pending, "pending")(PubSubOwnerSubscription::Subscribed, "subscribed")(PubSubOwnerSubscription::Unconfigured, "unconfigured").parse(*attributeValue)) { + getPayloadInternal()->setSubscription(*value); + } + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerSubscriptionParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerSubscriptionParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h new file mode 100644 index 0000000..53916f9 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerSubscription.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerSubscriptionParser : public GenericPayloadParser<PubSubOwnerSubscription> { + public: + PubSubOwnerSubscriptionParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerSubscriptionParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.cpp new file mode 100644 index 0000000..d322bef --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionParser.h> + +using namespace Swift; + +PubSubOwnerSubscriptionsParser::PubSubOwnerSubscriptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubOwnerSubscriptionsParser::~PubSubOwnerSubscriptionsParser() { +} + +void PubSubOwnerSubscriptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub#owner") { + currentPayloadParser = boost::make_shared<PubSubOwnerSubscriptionParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubOwnerSubscriptionsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub#owner") { + getPayloadInternal()->addSubscription(boost::dynamic_pointer_cast<PubSubOwnerSubscription>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubOwnerSubscriptionsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h new file mode 100644 index 0000000..48198db --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubOwnerSubscriptionsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubOwnerSubscriptions.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubOwnerSubscriptionsParser : public GenericPayloadParser<PubSubOwnerSubscriptions> { + public: + PubSubOwnerSubscriptionsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubOwnerSubscriptionsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubParser.cpp b/Swiften/Parser/PayloadParsers/PubSubParser.cpp new file mode 100644 index 0000000..5b1462b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubParser.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubConfigureParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubDefaultParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubCreateParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubAffiliationsParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOptionsParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubPublishParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubOptionsParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubItemsParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubRetractParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h> + +using namespace Swift; + +PubSubParser::PubSubParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubParser::~PubSubParser() { +} + +void PubSubParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 1) { + if (element == "items" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubItemsParser>(parsers); + } + if (element == "create" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubCreateParser>(parsers); + } + if (element == "publish" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubPublishParser>(parsers); + } + if (element == "affiliations" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubAffiliationsParser>(parsers); + } + if (element == "retract" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubRetractParser>(parsers); + } + if (element == "options" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubOptionsParser>(parsers); + } + if (element == "configure" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubConfigureParser>(parsers); + } + if (element == "default" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubDefaultParser>(parsers); + } + if (element == "subscriptions" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubSubscriptionsParser>(parsers); + } + if (element == "subscribe" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubSubscribeParser>(parsers); + } + if (element == "unsubscribe" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubUnsubscribeParser>(parsers); + } + if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubSubscriptionParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (currentPayloadParser) { + if (element == "options" && ns == "http://jabber.org/protocol/pubsub") { + optionsPayload = boost::dynamic_pointer_cast<PubSubOptions>(currentPayloadParser->getPayload()); + } + else if (element == "configure" && ns == "http://jabber.org/protocol/pubsub") { + configurePayload = boost::dynamic_pointer_cast<PubSubConfigure>(currentPayloadParser->getPayload()); + } + else { + getPayloadInternal()->setPayload(boost::dynamic_pointer_cast<PubSubPayload>(currentPayloadParser->getPayload())); + } + } + currentPayloadParser.reset(); + } + + if (level == 0) { + if (boost::shared_ptr<PubSubCreate> create = boost::dynamic_pointer_cast<PubSubCreate>(getPayloadInternal()->getPayload())) { + if (configurePayload) { + create->setConfigure(configurePayload); + } + } + if (boost::shared_ptr<PubSubSubscribe> subscribe = boost::dynamic_pointer_cast<PubSubSubscribe>(getPayloadInternal()->getPayload())) { + if (optionsPayload) { + subscribe->setOptions(optionsPayload); + } + } + } + } +} + +void PubSubParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubParser.h b/Swiften/Parser/PayloadParsers/PubSubParser.h new file mode 100644 index 0000000..0618361 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubParser.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSub.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + class PubSubOptions; + class PubSubConfigure; + + class SWIFTEN_API PubSubParser : public GenericPayloadParser<PubSub> { + public: + PubSubParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + boost::shared_ptr<PubSubConfigure> configurePayload; + boost::shared_ptr<PubSubOptions> optionsPayload; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubPublishParser.cpp b/Swiften/Parser/PayloadParsers/PubSubPublishParser.cpp new file mode 100644 index 0000000..4cddf57 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubPublishParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubPublishParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h> + +using namespace Swift; + +PubSubPublishParser::PubSubPublishParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubPublishParser::~PubSubPublishParser() { +} + +void PubSubPublishParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubItemParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubPublishParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub") { + getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubItem>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubPublishParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubPublishParser.h b/Swiften/Parser/PayloadParsers/PubSubPublishParser.h new file mode 100644 index 0000000..6e6c6c3 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubPublishParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubPublish.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubPublishParser : public GenericPayloadParser<PubSubPublish> { + public: + PubSubPublishParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubPublishParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubRetractParser.cpp b/Swiften/Parser/PayloadParsers/PubSubRetractParser.cpp new file mode 100644 index 0000000..69ed5f7 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubRetractParser.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubRetractParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h> + +using namespace Swift; + +PubSubRetractParser::PubSubRetractParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubRetractParser::~PubSubRetractParser() { +} + +void PubSubRetractParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("notify")) { + getPayloadInternal()->setNotify(*attributeValue == "true" ? true : false); + } + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubItemParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubRetractParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "item" && ns == "http://jabber.org/protocol/pubsub") { + getPayloadInternal()->addItem(boost::dynamic_pointer_cast<PubSubItem>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubRetractParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubRetractParser.h b/Swiften/Parser/PayloadParsers/PubSubRetractParser.h new file mode 100644 index 0000000..2d04a8f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubRetractParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubRetract.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubRetractParser : public GenericPayloadParser<PubSubRetract> { + public: + PubSubRetractParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubRetractParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.cpp new file mode 100644 index 0000000..cac65ec --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubSubscribeOptionsParser::PubSubSubscribeOptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubSubscribeOptionsParser::~PubSubSubscribeOptionsParser() { +} + +void PubSubSubscribeOptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubSubscribeOptionsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "required") { + getPayloadInternal()->setRequired(true); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubSubscribeOptionsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h new file mode 100644 index 0000000..d10b9d4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubSubscribeOptions.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubSubscribeOptionsParser : public GenericPayloadParser<PubSubSubscribeOptions> { + public: + PubSubSubscribeOptionsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubSubscribeOptionsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.cpp new file mode 100644 index 0000000..f989924 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubSubscribeParser::PubSubSubscribeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubSubscribeParser::~PubSubSubscribeParser() { +} + +void PubSubSubscribeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) { + if (boost::optional<JID> jid = JID::parse(*attributeValue)) { + getPayloadInternal()->setJID(*jid); + } + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubSubscribeParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubSubscribeParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h new file mode 100644 index 0000000..1c2028d --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscribeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubSubscribe.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubSubscribeParser : public GenericPayloadParser<PubSubSubscribe> { + public: + PubSubSubscribeParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubSubscribeParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.cpp new file mode 100644 index 0000000..c3cf89c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/EnumParser.h> +#include <Swiften/Parser/PayloadParsers/PubSubSubscribeOptionsParser.h> + +using namespace Swift; + +PubSubSubscriptionParser::PubSubSubscriptionParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubSubscriptionParser::~PubSubSubscriptionParser() { +} + +void PubSubSubscriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) { + getPayloadInternal()->setSubscriptionID(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) { + if (boost::optional<JID> jid = JID::parse(*attributeValue)) { + getPayloadInternal()->setJID(*jid); + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subscription")) { + if (boost::optional<PubSubSubscription::SubscriptionType> value = EnumParser<PubSubSubscription::SubscriptionType>()(PubSubSubscription::None, "none")(PubSubSubscription::Pending, "pending")(PubSubSubscription::Subscribed, "subscribed")(PubSubSubscription::Unconfigured, "unconfigured").parse(*attributeValue)) { + getPayloadInternal()->setSubscription(*value); + } + } + } + + if (level == 1) { + if (element == "subscribe-options" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubSubscribeOptionsParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubSubscriptionParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "subscribe-options" && ns == "http://jabber.org/protocol/pubsub") { + getPayloadInternal()->setOptions(boost::dynamic_pointer_cast<PubSubSubscribeOptions>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubSubscriptionParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h new file mode 100644 index 0000000..2ae32d4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubSubscription.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubSubscriptionParser : public GenericPayloadParser<PubSubSubscription> { + public: + PubSubSubscriptionParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubSubscriptionParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.cpp b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.cpp new file mode 100644 index 0000000..de3b15b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionParser.h> + +using namespace Swift; + +PubSubSubscriptionsParser::PubSubSubscriptionsParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubSubscriptionsParser::~PubSubSubscriptionsParser() { +} + +void PubSubSubscriptionsParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + } + + if (level == 1) { + if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub") { + currentPayloadParser = boost::make_shared<PubSubSubscriptionParser>(parsers); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubSubscriptionsParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + if (element == "subscription" && ns == "http://jabber.org/protocol/pubsub") { + getPayloadInternal()->addSubscription(boost::dynamic_pointer_cast<PubSubSubscription>(currentPayloadParser->getPayload())); + } + currentPayloadParser.reset(); + } + } +} + +void PubSubSubscriptionsParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h new file mode 100644 index 0000000..a1a1a68 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubSubscriptionsParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubSubscriptions.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubSubscriptionsParser : public GenericPayloadParser<PubSubSubscriptions> { + public: + PubSubSubscriptionsParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubSubscriptionsParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.cpp b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.cpp new file mode 100644 index 0000000..b47640c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h> + +#include <boost/optional.hpp> + + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + + +using namespace Swift; + +PubSubUnsubscribeParser::PubSubUnsubscribeParser(PayloadParserFactoryCollection* parsers) : parsers(parsers), level(0) { +} + +PubSubUnsubscribeParser::~PubSubUnsubscribeParser() { +} + +void PubSubUnsubscribeParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("node")) { + getPayloadInternal()->setNode(*attributeValue); + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("jid")) { + if (boost::optional<JID> jid = JID::parse(*attributeValue)) { + getPayloadInternal()->setJID(*jid); + } + } + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("subid")) { + getPayloadInternal()->setSubscriptionID(*attributeValue); + } + } + + + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void PubSubUnsubscribeParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + + currentPayloadParser.reset(); + } + } +} + +void PubSubUnsubscribeParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} diff --git a/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h new file mode 100644 index 0000000..8d88e66 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/PubSubUnsubscribeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/PubSubUnsubscribe.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class PayloadParser; + + class SWIFTEN_API PubSubUnsubscribeParser : public GenericPayloadParser<PubSubUnsubscribe> { + public: + PubSubUnsubscribeParser(PayloadParserFactoryCollection* parsers); + virtual ~PubSubUnsubscribeParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + PayloadParserFactoryCollection* parsers; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h b/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h index 4a027a1..2e16d00 100644 --- a/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h +++ b/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Elements/RawXMLPayload.h> #include <Swiften/Parser/GenericPayloadParser.h> @@ -14,5 +15,5 @@ namespace Swift { class SerializingParser; - class RawXMLPayloadParser : public GenericPayloadParser<RawXMLPayload> { + class SWIFTEN_API RawXMLPayloadParser : public GenericPayloadParser<RawXMLPayload> { public: RawXMLPayloadParser(); diff --git a/Swiften/Parser/PayloadParsers/ReplaceParser.cpp b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp index fb85fbd..728ed63 100644 --- a/Swiften/Parser/PayloadParsers/ReplaceParser.cpp +++ b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp @@ -5,4 +5,12 @@ */ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + + #include <Swiften/Parser/PayloadParsers/ReplaceParser.h> diff --git a/Swiften/Parser/PayloadParsers/ResultSetParser.cpp b/Swiften/Parser/PayloadParsers/ResultSetParser.cpp new file mode 100644 index 0000000..4c8283b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ResultSetParser.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/ResultSetParser.h> +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> + +using namespace Swift; + +ResultSetParser::ResultSetParser() : level_(TopLevel) { +} + +void ResultSetParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + currentText_ = ""; + if (level_ == PayloadLevel) { + if (element == "first" && ns == "http://jabber.org/protocol/rsm") { + if (boost::optional<std::string> attributeValue = attributes.getAttributeValue("index")) { + try { + getPayloadInternal()->setFirstIDIndex(boost::lexical_cast<int>(*attributeValue)); + } catch(boost::bad_lexical_cast&) { + } + } + } + } + ++level_; +} + +void ResultSetParser::handleEndElement(const std::string& element, const std::string&) { + --level_; + if (level_ == PayloadLevel) { + if (element == "max") { + try { + getPayloadInternal()->setMaxItems(boost::lexical_cast<int>(currentText_)); + } catch(boost::bad_lexical_cast&) { + } + } else if (element == "count") { + try { + getPayloadInternal()->setCount(boost::lexical_cast<int>(currentText_)); + } catch(boost::bad_lexical_cast&) { + } + } else if (element == "first") { + getPayloadInternal()->setFirstID(currentText_); + } else if (element == "last") { + getPayloadInternal()->setLastID(currentText_); + } else if (element == "before") { + getPayloadInternal()->setBefore(currentText_); + } else if (element == "after") { + getPayloadInternal()->setAfter(currentText_); + } + } +} + +void ResultSetParser::handleCharacterData(const std::string& data) { + currentText_ += data; +} diff --git a/Swiften/Parser/PayloadParsers/ResultSetParser.h b/Swiften/Parser/PayloadParsers/ResultSetParser.h new file mode 100644 index 0000000..55399ef --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ResultSetParser.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ResultSet.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + + class SWIFTEN_API ResultSetParser : public GenericPayloadParser<ResultSet> { + public: + ResultSetParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + enum Level { + TopLevel = 0, + PayloadLevel = 1 + }; + + private: + std::string currentText_; + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/RosterParser.h b/Swiften/Parser/PayloadParsers/RosterParser.h index c29064f..3b62f0b 100644 --- a/Swiften/Parser/PayloadParsers/RosterParser.h +++ b/Swiften/Parser/PayloadParsers/RosterParser.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Elements/RosterPayload.h> #include <Swiften/Parser/GenericPayloadParser.h> @@ -13,5 +14,5 @@ namespace Swift { class SerializingParser; - class RosterParser : public GenericPayloadParser<RosterPayload> { + class SWIFTEN_API RosterParser : public GenericPayloadParser<RosterPayload> { public: RosterParser(); diff --git a/Swiften/Parser/PayloadParsers/SearchPayloadParser.h b/Swiften/Parser/PayloadParsers/SearchPayloadParser.h index 006e0d9..d456eb8 100644 --- a/Swiften/Parser/PayloadParsers/SearchPayloadParser.h +++ b/Swiften/Parser/PayloadParsers/SearchPayloadParser.h @@ -29,5 +29,5 @@ namespace Swift { TopLevel = 0, PayloadLevel = 1, - ItemLevel = 2, + ItemLevel = 2 }; int level; diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp index 0a13844..cc69348 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp +++ b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp @@ -36,5 +36,5 @@ void StreamInitiationFileInfoParser::handleStartElement(const std::string& eleme parseDescription = false; if (element == "range") { - int offset = 0; + boost::uintmax_t offset = 0; try { offset = boost::lexical_cast<boost::uintmax_t>(attributes.getAttributeValue("offset").get_value_or("0")); diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp index fd3d019..ff0a061 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -41,5 +41,5 @@ void StreamInitiationParser::handleStartElement(const std::string& element, cons currentFile.setName(attributes.getAttribute("name")); try { - currentFile.setSize(boost::lexical_cast<int>(attributes.getAttribute("size"))); + currentFile.setSize(boost::lexical_cast<unsigned long long>(attributes.getAttribute("size"))); } catch (boost::bad_lexical_cast&) { @@ -97,6 +97,6 @@ void StreamInitiationParser::handleEndElement(const std::string& element, const } else if (form->getType() == Form::SubmitType) { - if (field->getRawValues().size() > 0) { - getPayloadInternal()->setRequestedMethod(field->getRawValues()[0]); + if (!field->getValues().empty()) { + getPayloadInternal()->setRequestedMethod(field->getValues()[0]); } } diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.h b/Swiften/Parser/PayloadParsers/StreamInitiationParser.h index c2ffd07..f7350cd 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationParser.h +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.h @@ -30,5 +30,5 @@ namespace Swift { PayloadLevel = 1, FileOrFeatureLevel = 2, - FormOrDescriptionLevel = 3, + FormOrDescriptionLevel = 3 }; int level; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/BlockParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/BlockParserTest.cpp new file mode 100644 index 0000000..ddd3a88 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/BlockParserTest.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/PayloadParsers/BlockParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +#include <Swiften/Elements/BlockPayload.h> +#include <Swiften/Elements/UnblockPayload.h> +#include <Swiften/Elements/BlockListPayload.h> + +using namespace Swift; + +class BlockParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(BlockParserTest); + CPPUNIT_TEST(testExample4); + CPPUNIT_TEST(testExample6); + CPPUNIT_TEST(testExample10); + CPPUNIT_TEST_SUITE_END(); + + public: + BlockParserTest() {} + + void testExample4() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse("<blocklist xmlns='urn:xmpp:blocking'>" + "<item jid='romeo@montague.net'/>" + "<item jid='iago@shakespeare.lit'/>" + "</blocklist>")); + + BlockListPayload* payload = dynamic_cast<BlockListPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload); + CPPUNIT_ASSERT(2 == payload->getItems().size()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), payload->getItems()[0]); + CPPUNIT_ASSERT_EQUAL(JID("iago@shakespeare.lit"), payload->getItems()[1]); + } + + void testExample6() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse("<block xmlns='urn:xmpp:blocking'>" + "<item jid='romeo@montague.net'/>" + "</block>")); + + BlockPayload* payload = dynamic_cast<BlockPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload); + CPPUNIT_ASSERT(1 == payload->getItems().size()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), payload->getItems()[0]); + } + + void testExample10() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse("<unblock xmlns='urn:xmpp:blocking'>" + "<item jid='romeo@montague.net'/>" + "</unblock>")); + + UnblockPayload* payload = dynamic_cast<UnblockPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload); + CPPUNIT_ASSERT(1 == payload->getItems().size()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), payload->getItems()[0]); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BlockParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp index bfbc312..d01abd1 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp @@ -16,4 +16,5 @@ class DiscoInfoParserTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(DiscoInfoParserTest); CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParse_Node); CPPUNIT_TEST(testParse_Form); CPPUNIT_TEST_SUITE_END(); @@ -46,4 +47,34 @@ class DiscoInfoParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("bar-feature"), payload->getFeatures()[1]); CPPUNIT_ASSERT_EQUAL(std::string("baz-feature"), payload->getFeatures()[2]); + CPPUNIT_ASSERT(payload->getNode().empty()); + } + + void testParse_Node() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse( + "<query xmlns=\"http://jabber.org/protocol/disco#info\" node=\"blahblah\">" + "<identity name=\"Swift\" category=\"client\" type=\"pc\" xml:lang=\"en\"/>" + "<identity name=\"Vlug\" category=\"client\" type=\"pc\" xml:lang=\"nl\"/>" + "<feature var=\"foo-feature\"/>" + "<feature var=\"bar-feature\"/>" + "<feature var=\"baz-feature\"/>" + "</query>")); + + DiscoInfo::ref payload = boost::dynamic_pointer_cast<DiscoInfo>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getIdentities().size())); + CPPUNIT_ASSERT_EQUAL(std::string("Swift"), payload->getIdentities()[0].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("pc"), payload->getIdentities()[0].getType()); + CPPUNIT_ASSERT_EQUAL(std::string("client"), payload->getIdentities()[0].getCategory()); + CPPUNIT_ASSERT_EQUAL(std::string("en"), payload->getIdentities()[0].getLanguage()); + CPPUNIT_ASSERT_EQUAL(std::string("Vlug"), payload->getIdentities()[1].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("pc"), payload->getIdentities()[1].getType()); + CPPUNIT_ASSERT_EQUAL(std::string("client"), payload->getIdentities()[1].getCategory()); + CPPUNIT_ASSERT_EQUAL(std::string("nl"), payload->getIdentities()[1].getLanguage()); + CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(payload->getFeatures().size())); + CPPUNIT_ASSERT_EQUAL(std::string("foo-feature"), payload->getFeatures()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("bar-feature"), payload->getFeatures()[1]); + CPPUNIT_ASSERT_EQUAL(std::string("baz-feature"), payload->getFeatures()[2]); + CPPUNIT_ASSERT_EQUAL(std::string("blahblah"), payload->getNode()); } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/DiscoItemsParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/DiscoItemsParserTest.cpp new file mode 100644 index 0000000..ee234ad --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/DiscoItemsParserTest.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/PayloadParsers/DiscoItemsParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class DiscoItemsParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(DiscoItemsParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse( + "<query xmlns='http://jabber.org/protocol/disco#items' node='http://jabber.org/protocol/commands'>" + "<item jid='responder@domain' node='list' name='List Service Configurations'/>" + "<item jid='responder@domain' node='config' name='Configure Service'/>" + "</query>")); + + boost::shared_ptr<DiscoItems> payload = boost::dynamic_pointer_cast<DiscoItems>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getItems().size())); + CPPUNIT_ASSERT_EQUAL(std::string("List Service Configurations"), payload->getItems()[0].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("list"), payload->getItems()[0].getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("responder@domain"), payload->getItems()[0].getJID().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("Configure Service"), payload->getItems()[1].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("config"), payload->getItems()[1].getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("responder@domain"), payload->getItems()[1].getJID().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("http://jabber.org/protocol/commands"), payload->getNode()); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(DiscoItemsParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp index c36fbeb..bc8f1bc 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -55,6 +55,4 @@ class FormParserTest : public CppUnit::TestFixture { "<field label=\"Password for special access\" type=\"text-private\" var=\"password\"/>" "<field label=\"What features will the bot support?\" type=\"list-multi\" var=\"features\">" - "<value>news</value>" - "<value>search</value>" "<option label=\"Contests\"><value>contests</value></option>" "<option label=\"News\"><value>news</value></option>" @@ -62,4 +60,6 @@ class FormParserTest : public CppUnit::TestFixture { "<option label=\"Reminders\"><value>reminders</value></option>" "<option label=\"Search\"><value>search</value></option>" + "<value>news</value>" + "<value>search</value>" "</field>" "<field label=\"Maximum number of subscribers\" type=\"list-single\" var=\"maxsubs\">" @@ -85,22 +85,20 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(10, static_cast<int>(payload->getFields().size())); - CPPUNIT_ASSERT_EQUAL(std::string("jabber:bot"), boost::dynamic_pointer_cast<HiddenFormField>(payload->getFields()[0])->getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:bot"), payload->getFields()[0]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("FORM_TYPE"), payload->getFields()[0]->getName()); CPPUNIT_ASSERT(!payload->getFields()[0]->getRequired()); - CPPUNIT_ASSERT_EQUAL(std::string("Section 1: Bot Info"), boost::dynamic_pointer_cast<FixedFormField>(payload->getFields()[1])->getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("Section 1: Bot Info"), payload->getFields()[1]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("The name of your bot"), payload->getFields()[2]->getLabel()); - CPPUNIT_ASSERT_EQUAL(std::string("This is a bot.\nA quite good one actually"), boost::dynamic_pointer_cast<TextMultiFormField>(payload->getFields()[3])->getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("This is a bot.\nA quite good one actually"), payload->getFields()[3]->getTextMultiValue()); - CPPUNIT_ASSERT_EQUAL(true, boost::dynamic_pointer_cast<BooleanFormField>(payload->getFields()[4])->getValue()); + CPPUNIT_ASSERT_EQUAL(true, payload->getFields()[4]->getBoolValue()); CPPUNIT_ASSERT(payload->getFields()[4]->getRequired()); - CPPUNIT_ASSERT_EQUAL(std::string("1"), boost::dynamic_pointer_cast<BooleanFormField>(payload->getFields()[4])->getRawValues()[0]); - - CPPUNIT_ASSERT_EQUAL(std::string("news"), boost::dynamic_pointer_cast<ListMultiFormField>(payload->getFields()[6])->getValue()[0]); - CPPUNIT_ASSERT_EQUAL(std::string("news"), payload->getFields()[6]->getRawValues()[0]); - CPPUNIT_ASSERT_EQUAL(std::string("search"), boost::dynamic_pointer_cast<ListMultiFormField>(payload->getFields()[6])->getValue()[1]); - CPPUNIT_ASSERT_EQUAL(std::string("search"), payload->getFields()[6]->getRawValues()[1]); + CPPUNIT_ASSERT_EQUAL(std::string("1"), payload->getFields()[4]->getValues()[0]); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getFields()[6]->getValues().size())); + CPPUNIT_ASSERT_EQUAL(std::string("news"), payload->getFields()[6]->getValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("search"), payload->getFields()[6]->getValues()[1]); CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(payload->getFields()[6]->getOptions().size())); CPPUNIT_ASSERT_EQUAL(std::string("Contests"), payload->getFields()[6]->getOptions()[0].label); @@ -109,11 +107,11 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("news"), payload->getFields()[6]->getOptions()[1].value); - CPPUNIT_ASSERT_EQUAL(std::string("20"), boost::dynamic_pointer_cast<ListSingleFormField>(payload->getFields()[7])->getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("20"), payload->getFields()[7]->getValues()[0]); - CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), boost::dynamic_pointer_cast<JIDMultiFormField>(payload->getFields()[8])->getValue()[0]); - CPPUNIT_ASSERT_EQUAL(JID("baz@fum.org"), boost::dynamic_pointer_cast<JIDMultiFormField>(payload->getFields()[8])->getValue()[1]); + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), payload->getFields()[8]->getJIDMultiValue(0)); + CPPUNIT_ASSERT_EQUAL(JID("baz@fum.org"), payload->getFields()[8]->getJIDMultiValue(1)); CPPUNIT_ASSERT_EQUAL(std::string("Tell all your friends about your new bot!"), payload->getFields()[8]->getDescription()); - CPPUNIT_ASSERT_EQUAL(std::string("foo"), boost::dynamic_pointer_cast<TextSingleFormField>(payload->getFields()[9])->getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), payload->getFields()[9]->getValues()[0]); } @@ -158,13 +156,12 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size()); - CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName()); - JIDSingleFormField::ref jidField = boost::dynamic_pointer_cast<JIDSingleFormField>(item[2]); - CPPUNIT_ASSERT(jidField); - CPPUNIT_ASSERT_EQUAL(JID("benvolio@montague.net"), jidField->getValue()); + boost::shared_ptr<FormField> jidField = item[2]; + CPPUNIT_ASSERT_EQUAL(JID("benvolio@montague.net"), jidField->getJIDSingleValue()); CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName()); @@ -172,13 +169,13 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size()); - CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName()); - jidField = boost::dynamic_pointer_cast<JIDSingleFormField>(item[2]); + jidField = item[2]; CPPUNIT_ASSERT(jidField); - CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), jidField->getValue()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), jidField->getJIDSingleValue()); CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName()); } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp new file mode 100644 index 0000000..a950fa4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/ForwardedParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> + +using namespace Swift; + +class ForwardedParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ForwardedParserTest); + CPPUNIT_TEST(testParseIQ); + CPPUNIT_TEST(testParseMessage); + CPPUNIT_TEST(testParseMessageNoDelay); + CPPUNIT_TEST(testParsePresence); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParseIQ() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay xmlns=\"urn:xmpp:delay\" stamp=\"2010-07-10T23:08:25Z\"/>" + "<iq xmlns=\"jabber:client\" type=\"get\" from=\"kindanormal@example.com/IM\" to=\"stupidnewbie@example.com\" id=\"id0\"/>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(payload->getDelay()->getStamp())); + + boost::shared_ptr<IQ> iq = boost::dynamic_pointer_cast<IQ>(payload->getStanza()); + CPPUNIT_ASSERT(!!iq); + CPPUNIT_ASSERT_EQUAL(JID("stupidnewbie@example.com"), iq->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("kindanormal@example.com/IM"), iq->getFrom()); + CPPUNIT_ASSERT_EQUAL(std::string("id0"), iq->getID()); + CPPUNIT_ASSERT_EQUAL(IQ::Get, iq->getType()); + } + + void testParseMessage() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay xmlns=\"urn:xmpp:delay\" stamp=\"2010-07-10T23:08:25Z\"/>" + "<message xmlns=\"jabber:client\" to=\"juliet@capulet.lit/balcony\" from=\"romeo@montague.lit/orchard\" type=\"chat\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(payload->getDelay()->getStamp())); + + boost::shared_ptr<Message> message = boost::dynamic_pointer_cast<Message>(payload->getStanza()); + CPPUNIT_ASSERT(!!message); + const std::string expectedBody = "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."; + CPPUNIT_ASSERT_EQUAL(expectedBody, message->getBody()); + CPPUNIT_ASSERT_EQUAL(Message::Chat, message->getType()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), message->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), message->getFrom()); + } + + void testParseMessageNoDelay() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<message xmlns=\"jabber:client\" to=\"juliet@capulet.lit/balcony\" from=\"romeo@montague.lit/orchard\" type=\"chat\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(!payload->getDelay()); + + boost::shared_ptr<Message> message = boost::dynamic_pointer_cast<Message>(payload->getStanza()); + CPPUNIT_ASSERT(!!message); + const std::string expectedBody = "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."; + CPPUNIT_ASSERT_EQUAL(expectedBody, message->getBody()); + CPPUNIT_ASSERT_EQUAL(Message::Chat, message->getType()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), message->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), message->getFrom()); + } + + void testParsePresence() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay xmlns=\"urn:xmpp:delay\" stamp=\"2010-07-10T23:08:25Z\"/>" + "<presence xmlns=\"jabber:client\" from=\"alice@wonderland.lit/rabbithole\" to=\"madhatter@wonderland.lit\" type=\"unavailable\"/>" + "</forwarded>")); + + boost::shared_ptr<Forwarded> payload = parser.getPayload<Forwarded>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(payload->getDelay()->getStamp())); + + boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(payload->getStanza()); + CPPUNIT_ASSERT(!!presence); + CPPUNIT_ASSERT_EQUAL(JID("madhatter@wonderland.lit"), presence->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit/rabbithole"), presence->getFrom()); + CPPUNIT_ASSERT_EQUAL(Presence::Unavailable, presence->getType()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ForwardedParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/IdleParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/IdleParserTest.cpp new file mode 100644 index 0000000..74da474 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/IdleParserTest.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/Idle.h> +#include <Swiften/Base/DateTime.h> + +using namespace Swift; + +class IdleParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(IdleParserTest); + CPPUNIT_TEST(testParse_XepWhatever_Example1); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse_XepWhatever_Example1() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<presence from='juliet@capulet.com/balcony'>\n" + "<show>away</show>\n" + "<idle xmlns='urn:xmpp:idle:1' since='1969-07-21T02:56:15Z'/>\n" + "</presence>\n" + )); + + Presence::ref presence = parser.getPayload<Presence>(); + CPPUNIT_ASSERT(presence); + Idle::ref idle = presence->getPayload<Idle>(); + CPPUNIT_ASSERT(idle); + CPPUNIT_ASSERT(stringToDateTime("1969-07-21T02:56:15Z") == idle->getSince()); + } +}; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp index f1f25cd..8c8601a 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp @@ -122,5 +122,5 @@ class JingleParserTest : public CppUnit::TestFixture { JingleIBBTransportPayload::ref transportPaylod = payload->getTransport<JingleIBBTransportPayload>(); CPPUNIT_ASSERT(transportPaylod); - CPPUNIT_ASSERT_EQUAL(4096, transportPaylod->getBlockSize()); + CPPUNIT_ASSERT_EQUAL(4096U, *transportPaylod->getBlockSize()); CPPUNIT_ASSERT_EQUAL(std::string("ch3d9s71"), transportPaylod->getSessionID()); } @@ -159,5 +159,5 @@ class JingleParserTest : public CppUnit::TestFixture { JingleIBBTransportPayload::ref transportPaylod = payload->getTransport<JingleIBBTransportPayload>(); CPPUNIT_ASSERT(transportPaylod); - CPPUNIT_ASSERT_EQUAL(2048, transportPaylod->getBlockSize()); + CPPUNIT_ASSERT_EQUAL(2048U, *transportPaylod->getBlockSize()); CPPUNIT_ASSERT_EQUAL(std::string("ch3d9s71"), transportPaylod->getSessionID()); } @@ -192,5 +192,5 @@ class JingleParserTest : public CppUnit::TestFixture { JingleIBBTransportPayload::ref transportPaylod = payload->getTransport<JingleIBBTransportPayload>(); CPPUNIT_ASSERT(transportPaylod); - CPPUNIT_ASSERT_EQUAL(2048, transportPaylod->getBlockSize()); + CPPUNIT_ASSERT_EQUAL(2048U, *transportPaylod->getBlockSize()); CPPUNIT_ASSERT_EQUAL(std::string("bt8a71h6"), transportPaylod->getSessionID()); } @@ -469,5 +469,5 @@ class JingleParserTest : public CppUnit::TestFixture { StreamInitiationFileInfo file = content->getDescription<JingleFileTransferDescription>()->getRequests()[0]; CPPUNIT_ASSERT_EQUAL(std::string("552da749930852c69ae5d2141d3766b1"), file.getHash()); - CPPUNIT_ASSERT_EQUAL(270336, file.getRangeOffset()); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned long long>(270336), file.getRangeOffset()); CPPUNIT_ASSERT_EQUAL(true, file.getSupportsRangeRequests()); } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp new file mode 100644 index 0000000..3e65cc6 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/MAMArchivedParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class MAMArchivedParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MAMArchivedParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<archived by=\"juliet@capulet.lit\" id=\"28482-98726-73623\" xmlns=\"urn:xmpp:mam:0\"/>")); + + boost::shared_ptr<MAMArchived> payload = parser.getPayload<MAMArchived>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit"), payload->getBy()); + CPPUNIT_ASSERT_EQUAL(std::string("28482-98726-73623"), payload->getID()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMArchivedParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp new file mode 100644 index 0000000..ddcd7c4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/MAMQueryParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class MAMQueryParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MAMQueryParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParseEmpty); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<query queryid=\"id0\" xmlns=\"urn:xmpp:mam:0\">" + "<x type=\"form\" xmlns=\"jabber:x:data\">" + "<field type=\"text-single\" var=\"FORM_TYPE\">" + "<value>urn:xmpp:mam:0</value>" + "</field>" + "<field type=\"text-single\" var=\"start\">" + "<value>2010-08-07T00:00:00Z</value>" + "</field>" + "</x>" + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>10</max>" + "</set>" + "</query>")); + + + boost::shared_ptr<MAMQuery> payload = parser.getPayload<MAMQuery>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getQueryID()); + CPPUNIT_ASSERT_EQUAL(std::string("id0"), *payload->getQueryID()); + + CPPUNIT_ASSERT(payload->getForm()); + boost::shared_ptr<FormField> fieldType = payload->getForm()->getField("FORM_TYPE"); + CPPUNIT_ASSERT(fieldType); + CPPUNIT_ASSERT_EQUAL(std::string("urn:xmpp:mam:0"), fieldType->getTextSingleValue()); + boost::shared_ptr<FormField> fieldStart = payload->getForm()->getField("start"); + CPPUNIT_ASSERT(fieldStart); + CPPUNIT_ASSERT_EQUAL(std::string("2010-08-07T00:00:00Z"), fieldStart->getTextSingleValue()); + + CPPUNIT_ASSERT(payload->getResultSet()); + boost::shared_ptr<ResultSet> resultSet = payload->getResultSet(); + CPPUNIT_ASSERT(resultSet->getMaxItems()); + CPPUNIT_ASSERT_EQUAL(*resultSet->getMaxItems(), 10); + } + + void testParseEmpty() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<query queryid=\"id0\" xmlns=\"urn:xmpp:mam:0\">" + "</query>")); + + boost::shared_ptr<MAMQuery> payload = parser.getPayload<MAMQuery>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getQueryID()); + CPPUNIT_ASSERT_EQUAL(std::string("id0"), *payload->getQueryID()); + CPPUNIT_ASSERT(!payload->getForm()); + CPPUNIT_ASSERT(!payload->getResultSet()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMQueryParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp new file mode 100644 index 0000000..e62db9b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/Base/DateTime.h> +#include <Swiften/Parser/PayloadParsers/MAMResultParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Elements/Message.h> + +using namespace Swift; + +class MAMResultParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MAMResultParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<result id=\"28482-98726-73623\" queryid=\"f27\" xmlns=\"urn:xmpp:mam:0\">" + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<message xmlns=\"jabber:client\" from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>" + "</result>")); + + boost::shared_ptr<MAMResult> payload = parser.getPayload<MAMResult>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT_EQUAL(std::string("28482-98726-73623"), payload->getID()); + CPPUNIT_ASSERT(payload->getQueryID()); + CPPUNIT_ASSERT_EQUAL(std::string("f27"), *payload->getQueryID()); + + boost::shared_ptr<Forwarded> forwarded = payload->getPayload(); + CPPUNIT_ASSERT(forwarded->getDelay()); + CPPUNIT_ASSERT_EQUAL(std::string("2010-07-10T23:08:25Z"), dateTimeToString(forwarded->getDelay()->getStamp())); + + boost::shared_ptr<Message> message = boost::dynamic_pointer_cast<Message>(forwarded->getStanza()); + CPPUNIT_ASSERT(!!message); + const std::string expectedBody = "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."; + CPPUNIT_ASSERT_EQUAL(expectedBody, message->getBody()); + CPPUNIT_ASSERT_EQUAL(Message::Chat, message->getType()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), message->getTo()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), message->getFrom()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMResultParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h index 213cd06..b328670 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h +++ b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,6 +7,4 @@ #pragma once -#include <cppunit/extensions/HelperMacros.h> - #include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> #include <Swiften/Parser/XMLParser.h> @@ -33,7 +31,7 @@ namespace Swift { virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { if (level == 0) { - CPPUNIT_ASSERT(!payloadParser.get()); + assert(!payloadParser.get()); PayloadParserFactory* payloadParserFactory = factories.getPayloadParserFactory(element, ns, attributes); - CPPUNIT_ASSERT(payloadParserFactory); + assert(payloadParserFactory); payloadParser.reset(payloadParserFactory->createPayloadParser()); } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp new file mode 100644 index 0000000..e345323 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014 Kevin Smith and 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/ResultSetParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class ResultSetParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ResultSetParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParseFirstNoIndex); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>100</max>" + "<count>800</count>" + "<first index=\"123\">stpeter@jabber.org</first>" + "<last>peterpan@neverland.lit</last>" + "<before>decaf-badba-dbad1</before>" + "<after>09af3-cc343-b409f</after>" + "</set>")); + + boost::shared_ptr<ResultSet> payload = parser.getPayload<ResultSet>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getMaxItems()); + CPPUNIT_ASSERT_EQUAL(100, *payload->getMaxItems()); + CPPUNIT_ASSERT(payload->getCount()); + CPPUNIT_ASSERT_EQUAL(800, *payload->getCount()); + CPPUNIT_ASSERT(payload->getFirstID()); + CPPUNIT_ASSERT_EQUAL(std::string("stpeter@jabber.org"), *payload->getFirstID()); + CPPUNIT_ASSERT(payload->getFirstIDIndex()); + CPPUNIT_ASSERT_EQUAL(123, *payload->getFirstIDIndex()); + CPPUNIT_ASSERT(payload->getLastID()); + CPPUNIT_ASSERT_EQUAL(std::string("peterpan@neverland.lit"), *payload->getLastID()); + CPPUNIT_ASSERT(payload->getBefore()); + CPPUNIT_ASSERT_EQUAL(std::string("decaf-badba-dbad1"), *payload->getBefore()); + CPPUNIT_ASSERT(payload->getAfter()); + CPPUNIT_ASSERT_EQUAL(std::string("09af3-cc343-b409f"), *payload->getAfter()); + } + + void testParseFirstNoIndex() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<first>stpeter@jabber.org</first>" + "</set>")); + + boost::shared_ptr<ResultSet> payload = parser.getPayload<ResultSet>(); + CPPUNIT_ASSERT(!!payload); + CPPUNIT_ASSERT(payload->getFirstID()); + CPPUNIT_ASSERT_EQUAL(std::string("stpeter@jabber.org"), *payload->getFirstID()); + CPPUNIT_ASSERT(!payload->getFirstIDIndex()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ResultSetParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp index ef48ced..59ea3ff 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -156,11 +156,11 @@ class SearchPayloadParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size()); - CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("benvolio@montague.net"), item[2]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("benvolio@montague.net"), item[2]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName()); @@ -168,11 +168,11 @@ class SearchPayloadParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size()); - CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("romeo@montague.net"), item[2]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("romeo@montague.net"), item[2]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName()); - CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]); CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName()); } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp index a378d0b..5ceec27 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2012 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -55,5 +55,5 @@ class StorageParserTest : public CppUnit::TestFixture { "jid='council@conference.underhill.org' />" "<conference " - "name='Tea party' " + "name='Tea & jam party' " "jid='teaparty@wonderland.lit' />" "</storage>")); @@ -64,5 +64,5 @@ class StorageParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Council of Oberon"), rooms[0].name); CPPUNIT_ASSERT_EQUAL(JID("council@conference.underhill.org"), rooms[0].jid); - CPPUNIT_ASSERT_EQUAL(std::string("Tea party"), rooms[1].name); + CPPUNIT_ASSERT_EQUAL(std::string("Tea & jam party"), rooms[1].name); CPPUNIT_ASSERT_EQUAL(JID("teaparty@wonderland.lit"), rooms[1].jid); } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp index f1e6635..6436e90 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp @@ -8,4 +8,6 @@ #include <QA/Checker/IO.h> +#include <boost/date_time/posix_time/posix_time.hpp> + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -20,4 +22,5 @@ class VCardParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse); CPPUNIT_TEST(testParse_Photo); + CPPUNIT_TEST(testParse_NewlinedPhoto); CPPUNIT_TEST(testParse_Nickname); CPPUNIT_TEST_SUITE_END(); @@ -49,6 +52,34 @@ class VCardParserTest : public CppUnit::TestFixture { "<X400/>" "</EMAIL>" + "<TEL>" + "<NUMBER>555-6273</NUMBER>" + "<HOME/>" + "<VOICE/>" + "</TEL>" + "<ADR>" + "<LOCALITY>Any Town</LOCALITY>" + "<STREET>Fake Street 123</STREET>" + "<PCODE>12345</PCODE>" + "<CTRY>USA</CTRY>" + "<HOME/>" + "</ADR>" + "<LABEL>" + "<LINE>Fake Street 123</LINE>" + "<LINE>12345 Any Town</LINE>" + "<LINE>USA</LINE>" + "<HOME/>" + "</LABEL>" "<NICKNAME>DreamGirl</NICKNAME>" - "<BDAY>1234</BDAY>" + "<BDAY>1865-05-04</BDAY>" + "<JID>alice@teaparty.lit</JID>" + "<JID>alice@wonderland.lit</JID>" + "<DESC>I once fell down a rabbit hole.</DESC>" + "<ORG>" + "<ORGNAME>Alice In Wonderland Inc.</ORGNAME>" + "</ORG>" + "<TITLE>Some Title</TITLE>" + "<ROLE>Main Character</ROLE>" + "<URL>http://wonderland.lit/~alice</URL>" + "<URL>http://teaparty.lit/~alice2</URL>" "<MAILER>mutt</MAILER>" "</vCard>")); @@ -63,5 +94,5 @@ class VCardParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("PhD"), payload->getSuffix()); CPPUNIT_ASSERT_EQUAL(std::string("DreamGirl"), payload->getNickname()); - CPPUNIT_ASSERT_EQUAL(std::string("<BDAY xmlns=\"vcard-temp\">1234</BDAY><MAILER xmlns=\"vcard-temp\">mutt</MAILER>"), payload->getUnknownContent()); + CPPUNIT_ASSERT_EQUAL(boost::posix_time::ptime(boost::gregorian::date(1865, 5, 4)), payload->getBirthday()); CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getEMailAddresses().size())); CPPUNIT_ASSERT_EQUAL(std::string("alice@wonderland.lit"), payload->getEMailAddresses()[0].address); @@ -77,4 +108,43 @@ class VCardParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(payload->getEMailAddresses()[1].isWork); CPPUNIT_ASSERT(payload->getEMailAddresses()[1].isX400); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getTelephones().size())); + CPPUNIT_ASSERT_EQUAL(std::string("555-6273"), payload->getTelephones()[0].number); + CPPUNIT_ASSERT(payload->getTelephones()[0].isHome); + CPPUNIT_ASSERT(payload->getTelephones()[0].isVoice); + CPPUNIT_ASSERT(!payload->getTelephones()[0].isPreferred); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getAddresses().size())); + CPPUNIT_ASSERT_EQUAL(std::string("Any Town"), payload->getAddresses()[0].locality); + CPPUNIT_ASSERT_EQUAL(std::string("Fake Street 123"), payload->getAddresses()[0].street); + CPPUNIT_ASSERT_EQUAL(std::string("12345"), payload->getAddresses()[0].postalCode); + CPPUNIT_ASSERT_EQUAL(std::string("USA"), payload->getAddresses()[0].country); + CPPUNIT_ASSERT(payload->getAddresses()[0].isHome); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getAddressLabels().size())); + CPPUNIT_ASSERT_EQUAL(std::string("Fake Street 123"), payload->getAddressLabels()[0].lines[0]); + CPPUNIT_ASSERT_EQUAL(std::string("12345 Any Town"), payload->getAddressLabels()[0].lines[1]); + CPPUNIT_ASSERT_EQUAL(std::string("USA"), payload->getAddressLabels()[0].lines[2]); + CPPUNIT_ASSERT(payload->getAddressLabels()[0].isHome); + + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getJIDs().size())); + CPPUNIT_ASSERT_EQUAL(JID("alice@teaparty.lit"), payload->getJIDs()[0]); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit"), payload->getJIDs()[1]); + + CPPUNIT_ASSERT_EQUAL(std::string("I once fell down a rabbit hole."), payload->getDescription()); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getOrganizations().size())); + CPPUNIT_ASSERT_EQUAL(std::string("Alice In Wonderland Inc."), payload->getOrganizations()[0].name); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(payload->getOrganizations()[0].units.size())); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getTitles().size())); + CPPUNIT_ASSERT_EQUAL(std::string("Some Title"), payload->getTitles()[0]); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(payload->getRoles().size())); + CPPUNIT_ASSERT_EQUAL(std::string("Main Character"), payload->getRoles()[0]); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getURLs().size())); + CPPUNIT_ASSERT_EQUAL(std::string("http://wonderland.lit/~alice"), payload->getURLs()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("http://teaparty.lit/~alice2"), payload->getURLs()[1]); + + CPPUNIT_ASSERT_EQUAL(std::string("<MAILER xmlns=\"vcard-temp\">mutt</MAILER>"), payload->getUnknownContent()); } @@ -98,4 +168,28 @@ class VCardParserTest : public CppUnit::TestFixture { } + void testParse_NewlinedPhoto() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse( + "<vCard xmlns='vcard-temp'>" + "<PHOTO>" + "<TYPE>image/jpeg</TYPE>" + "<BINVAL>" + "dTsETKSAskgu2/BqVO+ogcu3DJy4QATGJqpsa6znWwNGiLnVElVVB6PtS+mTiHUXsrOlKvRjtvzV\n" + "VDknNaRF58Elmu5EC6VoCllBEEB/lFf0emYn2gkp0X1khNi75dl+rOj95Ar6XuwLh+ZoSStqwOWj\n" + "pIpxmZmVw7E69qr0FY0oI3zcaxXwzHw7Lx9Qf4sH7ufQvIN88ga+hwp8MiXevh3Ac8pN00kgINlq\n" + "9AY/bYJL418Y/6wWsJbgmrJ/N78wSMpC7VVszLBZVv8uFnupubyi8Ophd/1wIWWzPPwAbBhepWVb\n" + "1oPiFEBT5MNKCMTPEi0npXtedVz0HQbbPNIVwmo=" + "</BINVAL>" + "</PHOTO>" + "</vCard>")); + + VCard* payload = dynamic_cast<VCard*>(parser.getPayload().get()); + CPPUNIT_ASSERT_EQUAL(std::string("image/jpeg"), payload->getPhotoType()); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x75\x3B\x04\x4C\xA4\x80\xB2\x48\x2E\xDB\xF0\x6A\x54\xEF\xA8\x81\xCB\xB7\x0C\x9C\xB8\x40\x04\xC6\x26\xAA\x6C\x6B\xAC\xE7\x5B\x03\x46\x88\xB9\xD5\x12\x55\x55\x07\xA3\xED\x4B\xE9\x93\x88\x75\x17\xB2\xB3\xA5\x2A\xF4\x63\xB6\xFC\xD5\x54\x39\x27\x35\xA4\x45\xE7\xC1\x25\x9A\xEE\x44\x0B\xA5\x68\x0A\x59\x41\x10\x40\x7F\x94\x57\xF4\x7A\x66\x27\xDA\x09\x29\xD1\x7D\x64\x84\xD8\xBB\xE5\xD9\x7E\xAC\xE8\xFD\xE4\x0A\xFA\x5E\xEC\x0B\x87\xE6\x68\x49\x2B\x6A\xC0\xE5\xA3\xA4\x8A\x71\x99\x99\x95\xC3\xB1\x3A\xF6\xAA\xF4\x15\x8D\x28\x23\x7C\xDC\x6B\x15\xF0\xCC\x7C\x3B\x2F\x1F\x50\x7F\x8B\x07\xEE\xE7\xD0\xBC\x83\x7C\xF2\x06\xBE\x87\x0A\x7C\x32\x25\xDE\xBE\x1D\xC0\x73\xCA\x4D\xD3\x49\x20\x20\xD9\x6A\xF4\x06\x3F\x6D\x82\x4B\xE3\x5F\x18\xFF\xAC\x16\xB0\x96\xE0\x9A\xB2\x7F\x37\xBF\x30\x48\xCA\x42\xED\x55\x6C\xCC\xB0\x59\x56\xFF\x2E\x16\x7B\xA9\xB9\xBC\xA2\xF0\xEA\x61\x77\xFD\x70\x21\x65\xB3\x3C\xFC\x00\x6C\x18\x5E\xA5\x65\x5B\xD6\x83\xE2\x14\x40\x53\xE4\xC3\x4A\x08\xC4\xCF\x12\x2D\x27\xA5\x7B\x5E\x75\x5C\xF4\x1D\x06\xDB\x3C\xD2\x15\xC2\x6A", 257), payload->getPhoto()); + } + + + void testParse_Nickname() { PayloadsParserTester parser; diff --git a/Swiften/Parser/PayloadParsers/UserLocationParser.cpp b/Swiften/Parser/PayloadParsers/UserLocationParser.cpp new file mode 100644 index 0000000..d3aac69 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UserLocationParser.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/UserLocationParser.h> + +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/DateTime.h> + +using namespace Swift; + +UserLocationParser::UserLocationParser() : level(0) { +} + +UserLocationParser::~UserLocationParser() { +} + +void UserLocationParser::handleStartElement(const std::string&, const std::string&, const AttributeMap&) { + if (level == 1) { + currentText = ""; + } + ++level; +} + +void UserLocationParser::handleEndElement(const std::string& element, const std::string&) { + --level; + if (level == 1) { + try { + if (element == "accuracy") { + getPayloadInternal()->setAccuracy(boost::lexical_cast<float>(currentText)); + } + else if (element == "alt") { + getPayloadInternal()->setAltitude(boost::lexical_cast<float>(currentText)); + } + else if (element == "area") { + getPayloadInternal()->setArea(currentText); + } + else if (element == "bearing") { + getPayloadInternal()->setBearing(boost::lexical_cast<float>(currentText)); + } + else if (element == "building") { + getPayloadInternal()->setBuilding(currentText); + } + else if (element == "country") { + getPayloadInternal()->setCountry(currentText); + } + else if (element == "countrycode") { + getPayloadInternal()->setCountryCode(currentText); + } + else if (element == "datum") { + getPayloadInternal()->setDatum(currentText); + } + else if (element == "description") { + getPayloadInternal()->setDescription(currentText); + } + else if (element == "error") { + getPayloadInternal()->setError(boost::lexical_cast<float>(currentText)); + } + else if (element == "floor") { + getPayloadInternal()->setFloor(currentText); + } + else if (element == "lat") { + getPayloadInternal()->setLatitude(boost::lexical_cast<float>(currentText)); + } + else if (element == "locality") { + getPayloadInternal()->setLocality(currentText); + } + else if (element == "lon") { + getPayloadInternal()->setLongitude(boost::lexical_cast<float>(currentText)); + } + else if (element == "postalcode") { + getPayloadInternal()->setPostalCode(currentText); + } + else if (element == "region") { + getPayloadInternal()->setRegion(currentText); + } + else if (element == "room") { + getPayloadInternal()->setRoom(currentText); + } + else if (element == "speed") { + getPayloadInternal()->setSpeed(boost::lexical_cast<float>(currentText)); + } + else if (element == "street") { + getPayloadInternal()->setStreet(currentText); + } + else if (element == "text") { + getPayloadInternal()->setText(currentText); + } + else if (element == "timestamp") { + getPayloadInternal()->setTimestamp(stringToDateTime(currentText)); + } + else if (element == "uri") { + getPayloadInternal()->setURI(currentText); + } + } + catch (const boost::bad_lexical_cast&) { + } + } +} + +void UserLocationParser::handleCharacterData(const std::string& data) { + currentText += data; +} diff --git a/Swiften/Parser/PayloadParsers/UserLocationParser.h b/Swiften/Parser/PayloadParsers/UserLocationParser.h new file mode 100644 index 0000000..eb6e668 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UserLocationParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Elements/UserLocation.h> + +namespace Swift { + class SWIFTEN_API UserLocationParser : public GenericPayloadParser<UserLocation> { + public: + UserLocationParser(); + virtual ~UserLocationParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + int level; + std::string currentText; + }; +} diff --git a/Swiften/Parser/PayloadParsers/UserTuneParser.cpp b/Swiften/Parser/PayloadParsers/UserTuneParser.cpp new file mode 100644 index 0000000..bb299e4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UserTuneParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/UserTuneParser.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +UserTuneParser::UserTuneParser() : level(0) { +} + +UserTuneParser::~UserTuneParser() { +} + +void UserTuneParser::handleStartElement(const std::string&, const std::string&, const AttributeMap&) { + if (level == 1) { + currentText = ""; + } + ++level; +} + +void UserTuneParser::handleEndElement(const std::string& element, const std::string&) { + --level; + if (level == 1) { + try { + if (element == "artist") { + getPayloadInternal()->setArtist(currentText); + } + else if (element == "length") { + getPayloadInternal()->setLength(boost::lexical_cast<unsigned int>(currentText)); + } + else if (element == "rating") { + getPayloadInternal()->setRating(boost::lexical_cast<unsigned int>(currentText)); + } + else if (element == "source") { + getPayloadInternal()->setSource(currentText); + } + else if (element == "title") { + getPayloadInternal()->setTitle(currentText); + } + else if (element == "track") { + getPayloadInternal()->setTrack(currentText); + } + else if (element == "URI") { + getPayloadInternal()->setURI(currentText); + } + } + catch (const boost::bad_lexical_cast&) { + } + } +} + +void UserTuneParser::handleCharacterData(const std::string& data) { + currentText += data; +} diff --git a/Swiften/Parser/PayloadParsers/UserTuneParser.h b/Swiften/Parser/PayloadParsers/UserTuneParser.h new file mode 100644 index 0000000..1cfadea --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UserTuneParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Elements/UserTune.h> + +namespace Swift { + class SWIFTEN_API UserTuneParser : public GenericPayloadParser<UserTune> { + public: + UserTuneParser(); + virtual ~UserTuneParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + int level; + std::string currentText; + }; +} diff --git a/Swiften/Parser/PayloadParsers/VCardParser.cpp b/Swiften/Parser/PayloadParsers/VCardParser.cpp index 553d26a..0028411 100644 --- a/Swiften/Parser/PayloadParsers/VCardParser.cpp +++ b/Swiften/Parser/PayloadParsers/VCardParser.cpp @@ -7,4 +7,5 @@ #include <Swiften/Parser/PayloadParsers/VCardParser.h> #include <Swiften/Base/foreach.h> +#include <Swiften/Base/DateTime.h> #include <Swiften/StringCodecs/Base64.h> #include <Swiften/Parser/SerializingParser.h> @@ -21,4 +22,16 @@ void VCardParser::handleStartElement(const std::string& element, const std::stri currentEMailAddress_ = VCard::EMailAddress(); } + if (elementHierarchy == "/vCard/TEL") { + currentTelephone_ = VCard::Telephone(); + } + if (elementHierarchy == "/vCard/ADR") { + currentAddress_ = VCard::Address(); + } + if (elementHierarchy == "/vCard/LABEL") { + currentAddressLabel_ = VCard::AddressLabel(); + } + if (elementHierarchy == "/vCard/ORG") { + currentOrganization_ = VCard::Organization(); + } if (elementStack_.size() == 2) { assert(!unknownContentParser_); @@ -69,4 +82,6 @@ void VCardParser::handleEndElement(const std::string& element, const std::string } else if (elementHierarchy == "/vCard/PHOTO/BINVAL") { + currentText_.erase(std::remove(currentText_.begin(), currentText_.end(), '\n'), currentText_.end()); + currentText_.erase(std::remove(currentText_.begin(), currentText_.end(), '\r'), currentText_.end()); getPayloadInternal()->setPhoto(Base64::decode(currentText_)); } @@ -91,7 +106,158 @@ void VCardParser::handleEndElement(const std::string& element, const std::string currentEMailAddress_.isPreferred = true; } - else if (elementHierarchy == "/vCard/EMAIL") { + else if (elementHierarchy == "/vCard/EMAIL" && !currentEMailAddress_.address.empty()) { getPayloadInternal()->addEMailAddress(currentEMailAddress_); } + else if (elementHierarchy == "/vCard/BDAY" && !currentText_.empty()) { + getPayloadInternal()->setBirthday(stringToDateTime(currentText_)); + } + else if (elementHierarchy == "/vCard/TEL/NUMBER") { + currentTelephone_.number = currentText_; + } + else if (elementHierarchy == "/vCard/TEL/HOME") { + currentTelephone_.isHome = true; + } + else if (elementHierarchy == "/vCard/TEL/WORK") { + currentTelephone_.isWork = true; + } + else if (elementHierarchy == "/vCard/TEL/VOICE") { + currentTelephone_.isVoice = true; + } + else if (elementHierarchy == "/vCard/TEL/FAX") { + currentTelephone_.isFax = true; + } + else if (elementHierarchy == "/vCard/TEL/PAGER") { + currentTelephone_.isPager = true; + } + else if (elementHierarchy == "/vCard/TEL/MSG") { + currentTelephone_.isMSG = true; + } + else if (elementHierarchy == "/vCard/TEL/CELL") { + currentTelephone_.isCell = true; + } + else if (elementHierarchy == "/vCard/TEL/VIDEO") { + currentTelephone_.isVideo = true; + } + else if (elementHierarchy == "/vCard/TEL/BBS") { + currentTelephone_.isBBS = true; + } + else if (elementHierarchy == "/vCard/TEL/MODEM") { + currentTelephone_.isModem = true; + } + else if (elementHierarchy == "/vCard/TEL/ISDN") { + currentTelephone_.isISDN = true; + } + else if (elementHierarchy == "/vCard/TEL/PCS") { + currentTelephone_.isPCS = true; + } + else if (elementHierarchy == "/vCard/TEL/PREF") { + currentTelephone_.isPreferred = true; + } + else if (elementHierarchy == "/vCard/TEL" && !currentTelephone_.number.empty()) { + getPayloadInternal()->addTelephone(currentTelephone_); + } + else if (elementHierarchy == "/vCard/ADR/HOME") { + currentAddress_.isHome = true; + } + else if (elementHierarchy == "/vCard/ADR/WORK") { + currentAddress_.isWork = true; + } + else if (elementHierarchy == "/vCard/ADR/POSTAL") { + currentAddress_.isPostal = true; + } + else if (elementHierarchy == "/vCard/ADR/PARCEL") { + currentAddress_.isParcel = true; + } + else if (elementHierarchy == "/vCard/ADR/DOM") { + currentAddress_.deliveryType = VCard::DomesticDelivery; + } + else if (elementHierarchy == "/vCard/ADR/INTL") { + currentAddress_.deliveryType = VCard::InternationalDelivery; + } + else if (elementHierarchy == "/vCard/ADR/PREF") { + currentAddress_.isPreferred = true; + } + else if (elementHierarchy == "/vCard/ADR/POBOX") { + currentAddress_.poBox = currentText_; + } + else if (elementHierarchy == "/vCard/ADR/EXTADD") { + currentAddress_.addressExtension = currentText_; + } + else if (elementHierarchy == "/vCard/ADR/STREET") { + currentAddress_.street = currentText_; + } + else if (elementHierarchy == "/vCard/ADR/LOCALITY") { + currentAddress_.locality = currentText_; + } + else if (elementHierarchy == "/vCard/ADR/REGION") { + currentAddress_.region = currentText_; + } + else if (elementHierarchy == "/vCard/ADR/PCODE") { + currentAddress_.postalCode = currentText_; + } + else if (elementHierarchy == "/vCard/ADR/CTRY") { + currentAddress_.country = currentText_; + } + else if (elementHierarchy == "/vCard/ADR") { + if (!currentAddress_.poBox.empty() || !currentAddress_.addressExtension.empty() || + !currentAddress_.street.empty() || !currentAddress_.locality.empty() || + !currentAddress_.region.empty() || !currentAddress_.region.empty() || + !currentAddress_.postalCode.empty() || !currentAddress_.country.empty()) { + getPayloadInternal()->addAddress(currentAddress_); + } + } + else if (elementHierarchy == "/vCard/LABEL/HOME") { + currentAddressLabel_.isHome = true; + } + else if (elementHierarchy == "/vCard/LABEL/WORK") { + currentAddressLabel_.isWork = true; + } + else if (elementHierarchy == "/vCard/LABEL/POSTAL") { + currentAddressLabel_.isPostal = true; + } + else if (elementHierarchy == "/vCard/LABEL/PARCEL") { + currentAddressLabel_.isParcel = true; + } + else if (elementHierarchy == "/vCard/LABEL/DOM") { + currentAddressLabel_.deliveryType = VCard::DomesticDelivery; + } + else if (elementHierarchy == "/vCard/LABEL/INTL") { + currentAddressLabel_.deliveryType = VCard::InternationalDelivery; + } + else if (elementHierarchy == "/vCard/LABEL/PREF") { + currentAddressLabel_.isPreferred = true; + } + else if (elementHierarchy == "/vCard/LABEL/LINE") { + currentAddressLabel_.lines.push_back(currentText_); + } + else if (elementHierarchy == "/vCard/LABEL") { + getPayloadInternal()->addAddressLabel(currentAddressLabel_); + } + else if (elementHierarchy == "/vCard/JID" && !currentText_.empty()) { + getPayloadInternal()->addJID(JID(currentText_)); + } + else if (elementHierarchy == "/vCard/DESC") { + getPayloadInternal()->setDescription(currentText_); + } + else if (elementHierarchy == "/vCard/ORG/ORGNAME") { + currentOrganization_.name = currentText_; + } + else if (elementHierarchy == "/vCard/ORG/ORGUNIT" && !currentText_.empty()) { + currentOrganization_.units.push_back(currentText_); + } + else if (elementHierarchy == "/vCard/ORG") { + if (!currentOrganization_.name.empty() || !currentOrganization_.units.empty()) { + getPayloadInternal()->addOrganization(currentOrganization_); + } + } + else if (elementHierarchy == "/vCard/TITLE" && !currentText_.empty()) { + getPayloadInternal()->addTitle(currentText_); + } + else if (elementHierarchy == "/vCard/ROLE" && !currentText_.empty()) { + getPayloadInternal()->addRole(currentText_); + } + else if (elementHierarchy == "/vCard/URL" && !currentText_.empty()) { + getPayloadInternal()->addURL(currentText_); + } else if (elementStack_.size() == 2 && unknownContentParser_) { getPayloadInternal()->addUnknownContent(unknownContentParser_->getResult()); diff --git a/Swiften/Parser/PayloadParsers/VCardParser.h b/Swiften/Parser/PayloadParsers/VCardParser.h index 1475277..f10d639 100644 --- a/Swiften/Parser/PayloadParsers/VCardParser.h +++ b/Swiften/Parser/PayloadParsers/VCardParser.h @@ -10,8 +10,10 @@ #include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Base/API.h> + namespace Swift { class SerializingParser; - class VCardParser : public GenericPayloadParser<VCard> { + class SWIFTEN_API VCardParser : public GenericPayloadParser<VCard> { public: VCardParser(); @@ -27,4 +29,8 @@ namespace Swift { std::vector<std::string> elementStack_; VCard::EMailAddress currentEMailAddress_; + VCard::Telephone currentTelephone_; + VCard::Address currentAddress_; + VCard::AddressLabel currentAddressLabel_; + VCard::Organization currentOrganization_; SerializingParser* unknownContentParser_; std::string currentText_; diff --git a/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp b/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp new file mode 100644 index 0000000..a480813 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/WhiteboardParser.h> +#include <Swiften/Elements/Whiteboard/WhiteboardLineElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardRectElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardTextElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardPolygonElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardEllipseElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardFreehandPathElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardColor.h> +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h> +#include <boost/optional.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/lexical_cast.hpp> + +namespace Swift { + WhiteboardParser::WhiteboardParser() : actualIsText(false), level_(0) { + } + + void WhiteboardParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (level_ == 0) { + getPayloadInternal()->setType(stringToType(attributes.getAttributeValue("type").get_value_or(""))); + } else if (level_ == 1) { + std::string type = attributes.getAttributeValue("type").get_value_or(""); + if (type == "insert") { + WhiteboardInsertOperation::ref insertOp = boost::make_shared<WhiteboardInsertOperation>(); + operation = insertOp; + } else if (type == "update") { + WhiteboardUpdateOperation::ref updateOp = boost::make_shared<WhiteboardUpdateOperation>(); + std::string move = attributes.getAttributeValue("newpos").get_value_or("0"); + updateOp->setNewPos(boost::lexical_cast<int>(attributes.getAttributeValue("newpos").get_value_or("0"))); + operation = updateOp; + } else if (type == "delete") { + WhiteboardDeleteOperation::ref deleteOp = boost::make_shared<WhiteboardDeleteOperation>(); + deleteOp->setElementID(attributes.getAttributeValue("elementid").get_value_or("")); + operation = deleteOp; + } + if (operation) { + try { + operation->setID(attributes.getAttributeValue("id").get_value_or("")); + operation->setParentID(attributes.getAttributeValue("parentid").get_value_or("")); + operation->setPos(boost::lexical_cast<int>(attributes.getAttributeValue("pos").get_value_or("0"))); + } catch (boost::bad_lexical_cast&) { + } + } + + } else if (level_ == 2) { + if (element == "line") { + int x1 = 0; + int y1 = 0; + int x2 = 0; + int y2 = 0; + try { + x1 = boost::lexical_cast<int>(attributes.getAttributeValue("x1").get_value_or("0")); + y1 = boost::lexical_cast<int>(attributes.getAttributeValue("y1").get_value_or("0")); + x2 = boost::lexical_cast<int>(attributes.getAttributeValue("x2").get_value_or("0")); + y2 = boost::lexical_cast<int>(attributes.getAttributeValue("y2").get_value_or("0")); + } catch (boost::bad_lexical_cast&) { + } + WhiteboardLineElement::ref whiteboardElement = boost::make_shared<WhiteboardLineElement>(x1, y1, x2, y2); + + WhiteboardColor color(attributes.getAttributeValue("stroke").get_value_or("#000000")); + color.setAlpha(opacityToAlpha(attributes.getAttributeValue("opacity").get_value_or("1"))); + whiteboardElement->setColor(color); + + int penWidth = 1; + try { + penWidth = boost::lexical_cast<int>(attributes.getAttributeValue("stroke-width").get_value_or("1")); + } catch (boost::bad_lexical_cast&) { + } + whiteboardElement->setPenWidth(penWidth); + whiteboardElement->setID(attributes.getAttributeValue("id").get_value_or("")); + getPayloadInternal()->setElement(whiteboardElement); + wbElement = whiteboardElement; + } else if (element == "path") { + WhiteboardFreehandPathElement::ref whiteboardElement = boost::make_shared<WhiteboardFreehandPathElement>(); + std::string pathData = attributes.getAttributeValue("d").get_value_or(""); + std::vector<std::pair<int, int> > points; + if (pathData[0] == 'M') { + size_t pos = 1; + size_t npos; + int x, y; + if (pathData[pos] == ' ') { + pos++; + } + try { + npos = pathData.find(' ', pos); + x = boost::lexical_cast<int>(pathData.substr(pos, npos-pos)); + pos = npos+1; + npos = pathData.find('L', pos); + y = boost::lexical_cast<int>(pathData.substr(pos, npos-pos)); + pos = npos+1; + if (pathData[pos] == ' ') { + pos++; + } + points.push_back(std::pair<int, int>(x, y)); + while (pos < pathData.size()) { + npos = pathData.find(' ', pos); + x = boost::lexical_cast<int>(pathData.substr(pos, npos-pos)); + pos = npos+1; + npos = pathData.find(' ', pos); + y = boost::lexical_cast<int>(pathData.substr(pos, npos-pos)); + pos = npos+1; + points.push_back(std::pair<int, int>(x, y)); + } + } catch (boost::bad_lexical_cast&) { + } + } + whiteboardElement->setPoints(points); + + int penWidth = 1; + try { + penWidth = boost::lexical_cast<int>(attributes.getAttributeValue("stroke-width").get_value_or("1")); + } catch (boost::bad_lexical_cast&) { + } + whiteboardElement->setPenWidth(penWidth); + + WhiteboardColor color(attributes.getAttributeValue("stroke").get_value_or("#000000")); + color.setAlpha(opacityToAlpha(attributes.getAttributeValue("opacity").get_value_or("1"))); + whiteboardElement->setColor(color); + whiteboardElement->setID(attributes.getAttributeValue("id").get_value_or("")); + getPayloadInternal()->setElement(whiteboardElement); + wbElement = whiteboardElement; + } else if (element == "rect") { + int x = 0; + int y = 0; + int width = 0; + int height = 0; + try { + x = boost::lexical_cast<int>(attributes.getAttributeValue("x").get_value_or("0")); + y = boost::lexical_cast<int>(attributes.getAttributeValue("y").get_value_or("0")); + width = boost::lexical_cast<int>(attributes.getAttributeValue("width").get_value_or("0")); + height = boost::lexical_cast<int>(attributes.getAttributeValue("height").get_value_or("0")); + } catch (boost::bad_lexical_cast&) { + } + + WhiteboardRectElement::ref whiteboardElement = boost::make_shared<WhiteboardRectElement>(x, y, width, height); + + int penWidth = 1; + try { + penWidth = boost::lexical_cast<int>(attributes.getAttributeValue("stroke-width").get_value_or("1")); + } catch (boost::bad_lexical_cast&) { + } + whiteboardElement->setPenWidth(penWidth); + + WhiteboardColor penColor(attributes.getAttributeValue("stroke").get_value_or("#000000")); + WhiteboardColor brushColor(attributes.getAttributeValue("fill").get_value_or("#000000")); + penColor.setAlpha(opacityToAlpha(attributes.getAttributeValue("opacity").get_value_or("1"))); + brushColor.setAlpha(opacityToAlpha(attributes.getAttributeValue("fill-opacity").get_value_or("1"))); + whiteboardElement->setPenColor(penColor); + whiteboardElement->setBrushColor(brushColor); + whiteboardElement->setID(attributes.getAttributeValue("id").get_value_or("")); + getPayloadInternal()->setElement(whiteboardElement); + wbElement = whiteboardElement; + } else if (element == "polygon") { + WhiteboardPolygonElement::ref whiteboardElement = boost::make_shared<WhiteboardPolygonElement>(); + + std::string pointsData = attributes.getAttributeValue("points").get_value_or(""); + std::vector<std::pair<int, int> > points; + size_t pos = 0; + size_t npos; + int x, y; + try { + while (pos < pointsData.size()) { + npos = pointsData.find(',', pos); + x = boost::lexical_cast<int>(pointsData.substr(pos, npos-pos)); + pos = npos+1; + npos = pointsData.find(' ', pos); + y = boost::lexical_cast<int>(pointsData.substr(pos, npos-pos)); + pos = npos+1; + points.push_back(std::pair<int, int>(x, y)); + } + } catch (boost::bad_lexical_cast&) { + } + + whiteboardElement->setPoints(points); + + int penWidth = 1; + try { + penWidth = boost::lexical_cast<int>(attributes.getAttributeValue("stroke-width").get_value_or("1")); + } catch (boost::bad_lexical_cast&) { + } + whiteboardElement->setPenWidth(penWidth); + + WhiteboardColor penColor(attributes.getAttributeValue("stroke").get_value_or("#000000")); + WhiteboardColor brushColor(attributes.getAttributeValue("fill").get_value_or("#000000")); + penColor.setAlpha(opacityToAlpha(attributes.getAttributeValue("opacity").get_value_or("1"))); + brushColor.setAlpha(opacityToAlpha(attributes.getAttributeValue("fill-opacity").get_value_or("1"))); + whiteboardElement->setPenColor(penColor); + whiteboardElement->setBrushColor(brushColor); + whiteboardElement->setID(attributes.getAttributeValue("id").get_value_or("")); + getPayloadInternal()->setElement(whiteboardElement); + wbElement = whiteboardElement; + } else if (element == "text") { + int x = 0; + int y = 0; + try { + x = boost::lexical_cast<int>(attributes.getAttributeValue("x").get_value_or("0")); + y = boost::lexical_cast<int>(attributes.getAttributeValue("y").get_value_or("0")); + } catch (boost::bad_lexical_cast&) { + } + + WhiteboardTextElement::ref whiteboardElement = boost::make_shared<WhiteboardTextElement>(x, y); + + actualIsText = true; + WhiteboardColor color(attributes.getAttributeValue("fill").get_value_or("#000000")); + color.setAlpha(opacityToAlpha(attributes.getAttributeValue("opacity").get_value_or("1"))); + whiteboardElement->setColor(color); + + int fontSize = 1; + try { + fontSize = boost::lexical_cast<int>(attributes.getAttributeValue("font-size").get_value_or("12")); + } catch (boost::bad_lexical_cast&) { + } + whiteboardElement->setSize(fontSize); + whiteboardElement->setID(attributes.getAttributeValue("id").get_value_or("")); + getPayloadInternal()->setElement(whiteboardElement); + wbElement = whiteboardElement; + } else if (element == "ellipse") { + int cx = 0; + int cy = 0; + int rx = 0; + int ry = 0; + try { + cx = boost::lexical_cast<int>(attributes.getAttributeValue("cx").get_value_or("0")); + cy = boost::lexical_cast<int>(attributes.getAttributeValue("cy").get_value_or("0")); + rx = boost::lexical_cast<int>(attributes.getAttributeValue("rx").get_value_or("0")); + ry = boost::lexical_cast<int>(attributes.getAttributeValue("ry").get_value_or("0")); + } catch (boost::bad_lexical_cast&) { + } + + WhiteboardEllipseElement::ref whiteboardElement = boost::make_shared<WhiteboardEllipseElement>(cx, cy, rx, ry); + + int penWidth = 1; + try { + penWidth = boost::lexical_cast<int>(attributes.getAttributeValue("stroke-width").get_value_or("1")); + } catch (boost::bad_lexical_cast&) { + } + whiteboardElement->setPenWidth(penWidth); + + WhiteboardColor penColor(attributes.getAttributeValue("stroke").get_value_or("#000000")); + WhiteboardColor brushColor(attributes.getAttributeValue("fill").get_value_or("#000000")); + penColor.setAlpha(opacityToAlpha(attributes.getAttributeValue("opacity").get_value_or("1"))); + brushColor.setAlpha(opacityToAlpha(attributes.getAttributeValue("fill-opacity").get_value_or("1"))); + whiteboardElement->setPenColor(penColor); + whiteboardElement->setBrushColor(brushColor); + whiteboardElement->setID(attributes.getAttributeValue("id").get_value_or("")); + getPayloadInternal()->setElement(whiteboardElement); + wbElement = whiteboardElement; + } + } + ++level_; + } + + void WhiteboardParser::handleEndElement(const std::string& element, const std::string&) { + --level_; + if (level_ == 0) { + getPayloadInternal()->setData(data_); + } else if (level_ == 1) { + WhiteboardInsertOperation::ref insertOp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation); + if (insertOp) { + insertOp->setElement(wbElement); + } + + WhiteboardUpdateOperation::ref updateOp = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(operation); + if (updateOp) { + updateOp->setElement(wbElement); + } + getPayloadInternal()->setOperation(operation); + } else if (level_ == 2) { + if (element == "text") { + actualIsText = false; + } + } + } + + void WhiteboardParser::handleCharacterData(const std::string& data) { + if (level_ == 3 && actualIsText) { + WhiteboardTextElement::ref element = boost::dynamic_pointer_cast<WhiteboardTextElement>(getPayloadInternal()->getElement()); + element->setText(data); + } + } + + WhiteboardPayload::Type WhiteboardParser::stringToType(const std::string& type) const { + if (type == "data") { + return WhiteboardPayload::Data; + } else if (type == "session-request") { + return WhiteboardPayload::SessionRequest; + } else if (type == "session-accept") { + return WhiteboardPayload::SessionAccept; + } else if (type == "session-terminate") { + return WhiteboardPayload::SessionTerminate; + } else { + return WhiteboardPayload::UnknownType; + } + } + + int WhiteboardParser::opacityToAlpha(std::string opacity) const { + int value = 255; + if (opacity.find('.') != std::string::npos) { + opacity = opacity.substr(opacity.find('.')+1, 2); + try { + value = boost::lexical_cast<int>(opacity)*255/100; + } catch (boost::bad_lexical_cast&) { + } + } + return value; + } +} diff --git a/Swiften/Parser/PayloadParsers/WhiteboardParser.h b/Swiften/Parser/PayloadParsers/WhiteboardParser.h new file mode 100644 index 0000000..0368c7c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/WhiteboardParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/WhiteboardPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardOperation.h> + +namespace Swift { + class WhiteboardParser : public Swift::GenericPayloadParser<WhiteboardPayload> { + public: + WhiteboardParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + WhiteboardPayload::Type stringToType(const std::string& type) const; + int opacityToAlpha(std::string opacity) const; + + private: + bool actualIsText; + int level_; + std::string data_; + WhiteboardElement::ref wbElement; + WhiteboardOperation::ref operation; + }; +} diff --git a/Swiften/Parser/PlatformXMLParserFactory.h b/Swiften/Parser/PlatformXMLParserFactory.h index 16756ee..70355d0 100644 --- a/Swiften/Parser/PlatformXMLParserFactory.h +++ b/Swiften/Parser/PlatformXMLParserFactory.h @@ -8,7 +8,8 @@ #include <Swiften/Parser/XMLParserFactory.h> +#include <Swiften/Base/API.h> namespace Swift { - class PlatformXMLParserFactory : public XMLParserFactory { + class SWIFTEN_API PlatformXMLParserFactory : public XMLParserFactory { public: PlatformXMLParserFactory(); diff --git a/Swiften/Parser/PresenceParser.h b/Swiften/Parser/PresenceParser.h index 19f90b3..eb07af8 100644 --- a/Swiften/Parser/PresenceParser.h +++ b/Swiften/Parser/PresenceParser.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Parser/GenericStanzaParser.h> #include <Swiften/Elements/Presence.h> namespace Swift { - class PresenceParser : public GenericStanzaParser<Presence> { + class SWIFTEN_API PresenceParser : public GenericStanzaParser<Presence> { public: PresenceParser(PayloadParserFactoryCollection* factories); diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index e4c2778..e748320 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -70,7 +70,18 @@ sources = [ "PayloadParsers/ReplaceParser.cpp", "PayloadParsers/LastParser.cpp", + "PayloadParsers/IdleParser.cpp", "PayloadParsers/S5BProxyRequestParser.cpp", "PayloadParsers/DeliveryReceiptParser.cpp", "PayloadParsers/DeliveryReceiptRequestParser.cpp", + "PayloadParsers/UserLocationParser.cpp", + "PayloadParsers/UserTuneParser.cpp", + "PayloadParsers/WhiteboardParser.cpp", + "PayloadParsers/PubSubErrorParserFactory.cpp", + "PayloadParsers/ResultSetParser.cpp", + "PayloadParsers/ForwardedParser.cpp", + "PayloadParsers/MAMResultParser.cpp", + "PayloadParsers/MAMQueryParser.cpp", + "PayloadParsers/MAMArchivedParser.cpp", + "PayloadParsers/IsodeIQDelegationParser.cpp", "PlatformXMLParserFactory.cpp", "PresenceParser.cpp", diff --git a/Swiften/Parser/SerializingParser.h b/Swiften/Parser/SerializingParser.h index 5f2c0cd..7706961 100644 --- a/Swiften/Parser/SerializingParser.h +++ b/Swiften/Parser/SerializingParser.h @@ -8,9 +8,10 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Parser/AttributeMap.h> #include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { - class SerializingParser { + class SWIFTEN_API SerializingParser { public: SerializingParser(); diff --git a/Swiften/Parser/StanzaAckParser.h b/Swiften/Parser/StanzaAckParser.h index c188878..c453039 100644 --- a/Swiften/Parser/StanzaAckParser.h +++ b/Swiften/Parser/StanzaAckParser.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Parser/GenericElementParser.h> #include <Swiften/Elements/StanzaAck.h> namespace Swift { - class StanzaAckParser : public GenericElementParser<StanzaAck> { + class SWIFTEN_API StanzaAckParser : public GenericElementParser<StanzaAck> { public: StanzaAckParser(); diff --git a/Swiften/Parser/StanzaParser.h b/Swiften/Parser/StanzaParser.h index 6887981..fc60b47 100644 --- a/Swiften/Parser/StanzaParser.h +++ b/Swiften/Parser/StanzaParser.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <string> #include <Swiften/Elements/Stanza.h> @@ -19,5 +20,5 @@ namespace Swift { class PayloadParserFactoryCollection; - class StanzaParser : public ElementParser, public boost::noncopyable { + class SWIFTEN_API StanzaParser : public ElementParser, public boost::noncopyable { public: StanzaParser(PayloadParserFactoryCollection* factories); @@ -28,5 +29,5 @@ namespace Swift { void handleCharacterData(const std::string& data); - virtual boost::shared_ptr<Element> getElement() const = 0; + virtual boost::shared_ptr<ToplevelElement> getElement() const = 0; virtual void handleStanzaAttributes(const AttributeMap&) {} diff --git a/Swiften/Parser/StreamFeaturesParser.h b/Swiften/Parser/StreamFeaturesParser.h index d55abe9..4bbb31c 100644 --- a/Swiften/Parser/StreamFeaturesParser.h +++ b/Swiften/Parser/StreamFeaturesParser.h @@ -8,9 +8,10 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Parser/GenericElementParser.h> #include <Swiften/Elements/StreamFeatures.h> namespace Swift { - class StreamFeaturesParser : public GenericElementParser<StreamFeatures> { + class SWIFTEN_API StreamFeaturesParser : public GenericElementParser<StreamFeatures> { public: StreamFeaturesParser(); diff --git a/Swiften/Parser/StreamManagementEnabledParser.h b/Swiften/Parser/StreamManagementEnabledParser.h index db616af..dfe232c 100644 --- a/Swiften/Parser/StreamManagementEnabledParser.h +++ b/Swiften/Parser/StreamManagementEnabledParser.h @@ -9,7 +9,8 @@ #include <Swiften/Parser/GenericElementParser.h> #include <Swiften/Elements/StreamManagementEnabled.h> +#include <Swiften/Base/API.h> namespace Swift { - class StreamManagementEnabledParser : public GenericElementParser<StreamManagementEnabled> { + class SWIFTEN_API StreamManagementEnabledParser : public GenericElementParser<StreamManagementEnabled> { public: StreamManagementEnabledParser(); diff --git a/Swiften/Parser/Tree/ParserElement.cpp b/Swiften/Parser/Tree/ParserElement.cpp index 9d9b9b6..e5f8bc8 100644 --- a/Swiften/Parser/Tree/ParserElement.cpp +++ b/Swiften/Parser/Tree/ParserElement.cpp @@ -10,4 +10,8 @@ #include <iostream> +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> + +namespace lambda = boost::lambda; namespace Swift { @@ -29,17 +33,8 @@ void ParserElement::appendCharacterData(const std::string& data) { } -struct DoesntMatch { - public: - DoesntMatch(const std::string& tagName, const std::string& ns) : tagName(tagName), ns(ns) {} - bool operator()(ParserElement::ref element) { return element->getName() != tagName || element->getNamespace() != ns; } - private: - std::string tagName; - std::string ns; -}; - - std::vector<ParserElement::ref> ParserElement::getChildren(const std::string& name, const std::string& xmlns) const { std::vector<ParserElement::ref> result; - std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), DoesntMatch(name, xmlns)); + std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), + lambda::bind(&ParserElement::getName, *lambda::_1) != name || lambda::bind(&ParserElement::getNamespace, *lambda::_1) != xmlns); return result; } diff --git a/Swiften/Parser/Tree/ParserElement.h b/Swiften/Parser/Tree/ParserElement.h index b268c76..6be0631 100644 --- a/Swiften/Parser/Tree/ParserElement.h +++ b/Swiften/Parser/Tree/ParserElement.h @@ -10,4 +10,5 @@ #include <string> #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Parser/AttributeMap.h> @@ -16,5 +17,5 @@ namespace Swift { - class ParserElement { + class SWIFTEN_API ParserElement { public: typedef boost::shared_ptr<ParserElement> ref; diff --git a/Swiften/Parser/UnitTest/EnumParserTest.cpp b/Swiften/Parser/UnitTest/EnumParserTest.cpp new file mode 100644 index 0000000..44a30c0 --- /dev/null +++ b/Swiften/Parser/UnitTest/EnumParserTest.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 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/EnumParser.h> + +using namespace Swift; + +class EnumParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(EnumParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParse_NoValue); + CPPUNIT_TEST_SUITE_END(); + + public: + enum MyEnum { + MyValue1, + MyValue2, + MyValue3 + }; + + void testParse() { + CPPUNIT_ASSERT(MyValue2 == EnumParser<MyEnum>()(MyValue1, "my-value-1")(MyValue2, "my-value-2")(MyValue3, "my-value-3").parse("my-value-2")); + } + + void testParse_NoValue() { + CPPUNIT_ASSERT(!EnumParser<MyEnum>()(MyValue1, "my-value-1")(MyValue2, "my-value-2")(MyValue3, "my-value-3").parse("my-value-4")); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(EnumParserTest); diff --git a/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp b/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp index d095afc..93d4e7f 100644 --- a/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp +++ b/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp @@ -8,4 +8,5 @@ #include <cppunit/extensions/TestFactoryRegistry.h> +#include <Swiften/Base/Platform.h> #include <Swiften/Parser/GenericPayloadTreeParser.h> #include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h> @@ -14,4 +15,11 @@ using namespace Swift; + +#if !SWIFTEN_STATIC && defined(SWIFTEN_PLATFORM_WINDOWS) +// This base class of a class used in this file is already exported, so need to +// explicitly import it. +template class __declspec(dllimport) Swift::GenericPayloadParser<RawXMLPayload>; +#endif + class GenericPayloadTreeParserTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(GenericPayloadTreeParserTest); diff --git a/Swiften/Parser/UnitTest/StanzaParserTest.cpp b/Swiften/Parser/UnitTest/StanzaParserTest.cpp index 88e6dec..020f0ca 100644 --- a/Swiften/Parser/UnitTest/StanzaParserTest.cpp +++ b/Swiften/Parser/UnitTest/StanzaParserTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -197,5 +197,5 @@ class StanzaParserTest : public CppUnit::TestFixture { } - virtual boost::shared_ptr<Element> getElement() const { + virtual boost::shared_ptr<ToplevelElement> getElement() const { return stanza_; } diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index 3c84220..4bdeb54 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -36,4 +36,5 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_AttributeWithNamespace); CPPUNIT_TEST(testParse_BillionLaughs); + CPPUNIT_TEST(testParse_InternalEntity); //CPPUNIT_TEST(testParse_UndefinedPrefix); //CPPUNIT_TEST(testParse_UndefinedAttributePrefix); @@ -275,4 +276,10 @@ class XMLParserTest : public CppUnit::TestFixture { } + void testParse_InternalEntity() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<!DOCTYPE foo [<!ENTITY bar \"Bar\">]><foo>&bar;</foo>")); + } + void testParse_UndefinedPrefix() { ParserType testling(&client_); diff --git a/Swiften/Parser/UnitTest/XMPPParserTest.cpp b/Swiften/Parser/UnitTest/XMPPParserTest.cpp index f8d60f2..7d2d3fa 100644 --- a/Swiften/Parser/UnitTest/XMPPParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMPPParserTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -163,5 +163,5 @@ class XMPPParserTest : public CppUnit::TestFixture { enum Type { StreamStart, ElementEvent, StreamEnd }; struct Event { - Event(Type type, boost::shared_ptr<Element> element) + Event(Type type, boost::shared_ptr<ToplevelElement> element) : type(type), element(element) {} Event(Type type, const ProtocolHeader& header) : type(type), header(header) {} @@ -171,5 +171,5 @@ class XMPPParserTest : public CppUnit::TestFixture { Type type; boost::optional<ProtocolHeader> header; - boost::shared_ptr<Element> element; + boost::shared_ptr<ToplevelElement> element; }; @@ -180,5 +180,5 @@ class XMPPParserTest : public CppUnit::TestFixture { } - void handleElement(boost::shared_ptr<Element> element) { + void handleElement(boost::shared_ptr<ToplevelElement> element) { events.push_back(Event(ElementEvent, element)); } diff --git a/Swiften/Parser/XMLParser.h b/Swiften/Parser/XMLParser.h index 1b866e3..6ecc626 100644 --- a/Swiften/Parser/XMLParser.h +++ b/Swiften/Parser/XMLParser.h @@ -9,9 +9,10 @@ #include <string> -namespace Swift { +#include <Swiften/Base/API.h> +namespace Swift { class XMLParserClient; - class XMLParser { + class SWIFTEN_API XMLParser { public: XMLParser(XMLParserClient* client); diff --git a/Swiften/Parser/XMLParserClient.h b/Swiften/Parser/XMLParserClient.h index ff706a0..956eacf 100644 --- a/Swiften/Parser/XMLParserClient.h +++ b/Swiften/Parser/XMLParserClient.h @@ -5,13 +5,11 @@ */ -#ifndef XMLPARSERCLIENT_H -#define XMLPARSERCLIENT_H +#pragma once +#include <Swiften/Base/API.h> #include <Swiften/Parser/AttributeMap.h> namespace Swift { - - - class XMLParserClient { + class SWIFTEN_API XMLParserClient { public: virtual ~XMLParserClient(); @@ -22,4 +20,2 @@ namespace Swift { }; } - -#endif diff --git a/Swiften/Parser/XMLParserFactory.h b/Swiften/Parser/XMLParserFactory.h index 32665cb..6979ea4 100644 --- a/Swiften/Parser/XMLParserFactory.h +++ b/Swiften/Parser/XMLParserFactory.h @@ -7,9 +7,11 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { class XMLParser; class XMLParserClient; - class XMLParserFactory { + class SWIFTEN_API XMLParserFactory { public: virtual ~XMLParserFactory(); diff --git a/Swiften/Parser/XMPPParser.h b/Swiften/Parser/XMPPParser.h index 6cce2bd..757ee22 100644 --- a/Swiften/Parser/XMPPParser.h +++ b/Swiften/Parser/XMPPParser.h @@ -10,4 +10,5 @@ #include <boost/noncopyable.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Parser/XMLParserClient.h> #include <Swiften/Parser/AttributeMap.h> @@ -20,5 +21,5 @@ namespace Swift { class PayloadParserFactoryCollection; - class XMPPParser : public XMLParserClient, boost::noncopyable { + class SWIFTEN_API XMPPParser : public XMLParserClient, boost::noncopyable { public: XMPPParser( diff --git a/Swiften/Parser/XMPPParserClient.h b/Swiften/Parser/XMPPParserClient.h index e613f8e..7d35968 100644 --- a/Swiften/Parser/XMPPParserClient.h +++ b/Swiften/Parser/XMPPParserClient.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,5 +9,6 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ToplevelElement.h> namespace Swift { @@ -15,10 +16,10 @@ namespace Swift { class ProtocolHeader; - class XMPPParserClient { + class SWIFTEN_API XMPPParserClient { public: virtual ~XMPPParserClient(); virtual void handleStreamStart(const ProtocolHeader&) = 0; - virtual void handleElement(boost::shared_ptr<Element>) = 0; + virtual void handleElement(boost::shared_ptr<ToplevelElement>) = 0; virtual void handleStreamEnd() = 0; }; diff --git a/Swiften/Presence/DirectedPresenceSender.h b/Swiften/Presence/DirectedPresenceSender.h index 7dbdd37..0eb16a4 100644 --- a/Swiften/Presence/DirectedPresenceSender.h +++ b/Swiften/Presence/DirectedPresenceSender.h @@ -11,7 +11,8 @@ #include <Swiften/Elements/Presence.h> #include <Swiften/Presence/PresenceSender.h> +#include <Swiften/Base/API.h> namespace Swift { - class DirectedPresenceSender : public PresenceSender { + class SWIFTEN_API DirectedPresenceSender : public PresenceSender { public: enum SendPresence {AndSendPresence, DontSendPresence}; diff --git a/Swiften/Presence/PayloadAddingPresenceSender.h b/Swiften/Presence/PayloadAddingPresenceSender.h index 333842a..4845865 100644 --- a/Swiften/Presence/PayloadAddingPresenceSender.h +++ b/Swiften/Presence/PayloadAddingPresenceSender.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Presence/PresenceSender.h> #include <Swiften/Elements/Payload.h> @@ -18,5 +19,5 @@ namespace Swift { * This class isn't meant to be used with directed presence. */ - class PayloadAddingPresenceSender : public PresenceSender { + class SWIFTEN_API PayloadAddingPresenceSender : public PresenceSender { public: PayloadAddingPresenceSender(PresenceSender*); diff --git a/Swiften/Presence/PresenceOracle.h b/Swiften/Presence/PresenceOracle.h index 09126ea..fcf974f 100644 --- a/Swiften/Presence/PresenceOracle.h +++ b/Swiften/Presence/PresenceOracle.h @@ -12,9 +12,11 @@ #include <Swiften/Elements/Presence.h> +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> namespace Swift { class StanzaChannel; - class PresenceOracle { + + class SWIFTEN_API PresenceOracle { public: PresenceOracle(StanzaChannel* stanzaChannel); diff --git a/Swiften/Presence/StanzaChannelPresenceSender.h b/Swiften/Presence/StanzaChannelPresenceSender.h index d60d29d..8649acb 100644 --- a/Swiften/Presence/StanzaChannelPresenceSender.h +++ b/Swiften/Presence/StanzaChannelPresenceSender.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Presence/PresenceSender.h> @@ -12,5 +13,5 @@ namespace Swift { class StanzaChannel; - class StanzaChannelPresenceSender : public PresenceSender { + class SWIFTEN_API StanzaChannelPresenceSender : public PresenceSender { public: StanzaChannelPresenceSender(StanzaChannel*); diff --git a/Swiften/Presence/SubscriptionManager.h b/Swiften/Presence/SubscriptionManager.h index efa3e1c..5fabb04 100644 --- a/Swiften/Presence/SubscriptionManager.h +++ b/Swiften/Presence/SubscriptionManager.h @@ -13,9 +13,10 @@ #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Elements/Presence.h> +#include <Swiften/Base/API.h> namespace Swift { class StanzaChannel; - class SubscriptionManager { + class SWIFTEN_API SubscriptionManager { public: SubscriptionManager(StanzaChannel* stanzaChannel); diff --git a/Swiften/PubSub/PubSubManager.cpp b/Swiften/PubSub/PubSubManager.cpp new file mode 100644 index 0000000..8899b1e --- /dev/null +++ b/Swiften/PubSub/PubSubManager.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/PubSub/PubSubManager.h> + +using namespace Swift; + +PubSubManager::~PubSubManager() { +} diff --git a/Swiften/PubSub/PubSubManager.h b/Swiften/PubSub/PubSubManager.h new file mode 100644 index 0000000..2f3c84d --- /dev/null +++ b/Swiften/PubSub/PubSubManager.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Queries/PubSubRequest.h> +#include <Swiften/PubSub/PubSubUtil.h> +#include <Swiften/Elements/PubSub.h> +#include <Swiften/Elements/PubSubOwnerPubSub.h> +#include <Swiften/Elements/PubSubCreate.h> +#include <Swiften/Elements/PubSubSubscribe.h> +#include <Swiften/Elements/PubSubAffiliations.h> +#include <Swiften/Elements/PubSubDefault.h> +#include <Swiften/Elements/PubSubItems.h> +#include <Swiften/Elements/PubSubPublish.h> +#include <Swiften/Elements/PubSubRetract.h> +#include <Swiften/Elements/PubSubSubscription.h> +#include <Swiften/Elements/PubSubSubscriptions.h> +#include <Swiften/Elements/PubSubUnsubscribe.h> +#include <Swiften/Elements/PubSubOwnerAffiliations.h> +#include <Swiften/Elements/PubSubOwnerConfigure.h> +#include <Swiften/Elements/PubSubOwnerDefault.h> +#include <Swiften/Elements/PubSubOwnerDelete.h> +#include <Swiften/Elements/PubSubOwnerPurge.h> +#include <Swiften/Elements/PubSubOwnerSubscriptions.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/PubSubEventPayload.h> + +#define SWIFTEN_PUBSUBMANAGER_DECLARE_CREATE_REQUEST(payload, container, response) \ + virtual boost::shared_ptr< PubSubRequest<payload> > \ + createRequest(IQ::Type, const JID&, boost::shared_ptr<payload>) = 0; + +namespace Swift { + class JID; + + class SWIFTEN_API PubSubManager { + public: + virtual ~PubSubManager(); + + SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE( + SWIFTEN_PUBSUBMANAGER_DECLARE_CREATE_REQUEST) + + boost::signal<void (const JID&, const boost::shared_ptr<PubSubEventPayload>)> onEvent; + }; +} diff --git a/Swiften/PubSub/PubSubManagerImpl.cpp b/Swiften/PubSub/PubSubManagerImpl.cpp new file mode 100644 index 0000000..38b02aa --- /dev/null +++ b/Swiften/PubSub/PubSubManagerImpl.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/PubSub/PubSubManagerImpl.h> + +#include <boost/bind.hpp> + +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/PubSubEvent.h> + +using namespace Swift; + +PubSubManagerImpl::PubSubManagerImpl(StanzaChannel* stanzaChannel, IQRouter* router) : + stanzaChannel(stanzaChannel), + router(router) { + stanzaChannel->onMessageReceived.connect(boost::bind(&PubSubManagerImpl::handleMessageRecevied, this, _1)); +} + +PubSubManagerImpl::~PubSubManagerImpl() { + stanzaChannel->onMessageReceived.disconnect(boost::bind(&PubSubManagerImpl::handleMessageRecevied, this, _1)); +} + +void PubSubManagerImpl::handleMessageRecevied(boost::shared_ptr<Message> message) { + if (boost::shared_ptr<PubSubEvent> event = message->getPayload<PubSubEvent>()) { + onEvent(message->getFrom(), event->getPayload()); + } +} diff --git a/Swiften/PubSub/PubSubManagerImpl.h b/Swiften/PubSub/PubSubManagerImpl.h new file mode 100644 index 0000000..ba363ef --- /dev/null +++ b/Swiften/PubSub/PubSubManagerImpl.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/PubSub/PubSubManager.h> + +#define SWIFTEN_PUBSUBMANAGERIMPL_DECLARE_CREATE_REQUEST(payload, container, response) \ + virtual boost::shared_ptr< PubSubRequest<payload> > \ + createRequest(IQ::Type type, const JID& receiver, boost::shared_ptr<payload> p) SWIFTEN_OVERRIDE { \ + return boost::make_shared< PubSubRequest<payload> >(type, receiver, p, router); \ + } + +namespace Swift { + class JID; + class StanzaChannel; + class Message; + + class SWIFTEN_API PubSubManagerImpl : public PubSubManager { + public: + PubSubManagerImpl(StanzaChannel* stanzaChannel, IQRouter* router); + virtual ~PubSubManagerImpl(); + + SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE( + SWIFTEN_PUBSUBMANAGERIMPL_DECLARE_CREATE_REQUEST) + + private: + void handleMessageRecevied(boost::shared_ptr<Message>); + + private: + StanzaChannel* stanzaChannel; + IQRouter* router; + }; +} diff --git a/Swiften/PubSub/PubSubUtil.h b/Swiften/PubSub/PubSubUtil.h new file mode 100644 index 0000000..3342659 --- /dev/null +++ b/Swiften/PubSub/PubSubUtil.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#define SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE(action) \ + action(PubSubCreate, PubSub, PubSubCreate) \ + action(PubSubAffiliations, PubSub, PubSubAffiliations) \ + action(PubSubDefault, PubSub, PubSubDefault) \ + action(PubSubItems, PubSub, PubSubItems) \ + action(PubSubOptions, PubSub, PubSubOptions) \ + action(PubSubPublish, PubSub, PubSubPublish) \ + action(PubSubRetract, PubSub, PubSubRetract) \ + action(PubSubSubscription, PubSub, PubSubSubscription) \ + action(PubSubSubscriptions, PubSub, PubSubSubscriptions) \ + action(PubSubSubscribe, PubSub, PubSubSubscription) \ + action(PubSubUnsubscribe, PubSub, PubSubUnsubscribe) \ + action(PubSubOwnerAffiliations, PubSubOwnerPubSub, PubSubOwnerAffiliations) \ + action(PubSubOwnerConfigure, PubSubOwnerPubSub, PubSubOwnerConfigure) \ + action(PubSubOwnerDefault, PubSubOwnerPubSub, PubSubOwnerDefault) \ + action(PubSubOwnerDelete, PubSubOwnerPubSub, PubSubOwnerDelete) \ + action(PubSubOwnerPurge, PubSubOwnerPubSub, PubSubOwnerPurge) \ + action(PubSubOwnerSubscriptions, PubSubOwnerPubSub, PubSubOwnerSubscriptions) + diff --git a/Swiften/QA/ClientTest/ClientTest.cpp b/Swiften/QA/ClientTest/ClientTest.cpp index 3b8734e..38f70db 100644 --- a/Swiften/QA/ClientTest/ClientTest.cpp +++ b/Swiften/QA/ClientTest/ClientTest.cpp @@ -19,18 +19,18 @@ using namespace Swift; -SimpleEventLoop eventLoop; -BoostNetworkFactories networkFactories(&eventLoop); +static SimpleEventLoop eventLoop; +static BoostNetworkFactories networkFactories(&eventLoop); -Client* client = 0; -bool rosterReceived = false; +static Client* client = 0; +static bool rosterReceived = false; enum TestStage { FirstConnect, Reconnect }; -TestStage stage; -ClientOptions options; +static TestStage stage; +static ClientOptions options; -void handleDisconnected(boost::optional<ClientError> e) { - std::cout << "Disconnected: " << e << std::endl; +static void handleDisconnected(boost::optional<ClientError> e) { + std::cout << "Disconnected: " << (e ? e.get().getType() : ClientError::UnknownError) << std::endl; if (stage == FirstConnect) { stage = Reconnect; @@ -42,5 +42,5 @@ void handleDisconnected(boost::optional<ClientError> e) { } -void handleRosterReceived(boost::shared_ptr<Payload>) { +static void handleRosterReceived(boost::shared_ptr<Payload>) { rosterReceived = true; std::cout << "Disconnecting" << std::endl; @@ -48,5 +48,5 @@ void handleRosterReceived(boost::shared_ptr<Payload>) { } -void handleConnected() { +static void handleConnected() { std::cout << "Connected" << std::endl; rosterReceived = false; @@ -78,5 +78,5 @@ int main(int, char**) { client = new Swift::Client(JID(jid), std::string(pass), &networkFactories); - ClientXMLTracer* tracer = new ClientXMLTracer(client, !options.boshURL.empty()); + ClientXMLTracer* tracer = new ClientXMLTracer(client, !options.boshURL.isEmpty()); client->onConnected.connect(&handleConnected); client->onDisconnected.connect(boost::bind(&handleDisconnected, _1)); diff --git a/Swiften/QA/NetworkTest/BoostConnectionTest.cpp b/Swiften/QA/NetworkTest/BoostConnectionTest.cpp index 335f2d2..53faff7 100644 --- a/Swiften/QA/NetworkTest/BoostConnectionTest.cpp +++ b/Swiften/QA/NetworkTest/BoostConnectionTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ #include <Swiften/EventLoop/DummyEventLoop.h> -const unsigned char* address = reinterpret_cast<const unsigned char*>("\x41\x63\xde\x89"); +static const unsigned char* address = reinterpret_cast<const unsigned char*>("\x4A\x32\x3e\x31"); using namespace Swift; @@ -71,5 +71,5 @@ class BoostConnectionTest : public CppUnit::TestFixture { testling->onDataRead.connect(boost::bind(&BoostConnectionTest::handleDataRead, this, _1)); testling->onDisconnected.connect(boost::bind(&BoostConnectionTest::handleDisconnected, this)); - testling->connect(HostAddressPort(HostAddress("65.99.222.137"), 5222)); + testling->connect(HostAddressPort(HostAddress("74.50.62.49"), 5222)); while (receivedData.empty()) { Swift::sleep(10); @@ -98,5 +98,5 @@ class BoostConnectionTest : public CppUnit::TestFixture { testling->onDataRead.connect(boost::bind(&BoostConnectionTest::handleDataRead, this, _1)); testling->onDisconnected.connect(boost::bind(&BoostConnectionTest::handleDisconnected, this)); - testling->connect(HostAddressPort(HostAddress("65.99.222.137"), 5222)); + testling->connect(HostAddressPort(HostAddress("74.50.62.49"), 5222)); while (!connectFinished) { boostIOService->run_one(); diff --git a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp index 7cb9ed3..dcd2be8 100644 --- a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp +++ b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp @@ -10,12 +10,20 @@ #include <algorithm> - #include <Swiften/Base/sleep.h> #include <string> #include <Swiften/Base/ByteArray.h> +#ifdef USE_UNBOUND +#include <Swiften/Network/UnboundDomainNameResolver.h> +#else #include <Swiften/Network/PlatformDomainNameResolver.h> +#endif +#include <Swiften/Network/BoostTimerFactory.h> +#include <Swiften/Network/NetworkFactories.h> +#include <Swiften/Network/BoostIOServiceThread.h> #include <Swiften/Network/DomainNameAddressQuery.h> #include <Swiften/Network/DomainNameServiceQuery.h> #include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/IDN/PlatformIDNConverter.h> using namespace Swift; @@ -31,10 +39,14 @@ class DomainNameResolverTest : public CppUnit::TestFixture { CPPUNIT_TEST(testResolveAddress); CPPUNIT_TEST(testResolveAddress_Error); +#ifndef USE_UNBOUND CPPUNIT_TEST(testResolveAddress_IPv6); CPPUNIT_TEST(testResolveAddress_IPv4and6); CPPUNIT_TEST(testResolveAddress_International); +#endif CPPUNIT_TEST(testResolveAddress_Localhost); CPPUNIT_TEST(testResolveAddress_Parallel); +#ifndef USE_UNBOUND CPPUNIT_TEST(testResolveService); +#endif CPPUNIT_TEST(testResolveService_Error); CPPUNIT_TEST_SUITE_END(); @@ -42,10 +54,17 @@ class DomainNameResolverTest : public CppUnit::TestFixture { public: void setUp() { + ioServiceThread = new BoostIOServiceThread(); eventLoop = new DummyEventLoop(); - resolver = new PlatformDomainNameResolver(eventLoop); + idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); +#ifdef USE_UNBOUND + resolver = new UnboundDomainNameResolver(idnConverter.get(), ioServiceThread->getIOService(), eventLoop); +#else + resolver = new PlatformDomainNameResolver(idnConverter.get(), eventLoop); +#endif resultsAvailable = false; } void tearDown() { + delete ioServiceThread; delete resolver; delete eventLoop; @@ -142,5 +161,5 @@ class DomainNameResolverTest : public CppUnit::TestFixture { void testResolveService() { - boost::shared_ptr<DomainNameServiceQuery> query(createServiceQuery("_xmpp-client._tcp.xmpp-srv.test.swift.im")); + boost::shared_ptr<DomainNameServiceQuery> query(createServiceQuery("_xmpp-client._tcp.", "xmpp-srv.test.swift.im")); query->run(); @@ -184,6 +203,6 @@ class DomainNameResolverTest : public CppUnit::TestFixture { } - boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& domain) { - boost::shared_ptr<DomainNameServiceQuery> result = resolver->createServiceQuery(domain); + boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& serviceLookupPrefix, const std::string& domain) { + boost::shared_ptr<DomainNameServiceQuery> result = resolver->createServiceQuery(serviceLookupPrefix, domain); result->onResult.connect(boost::bind(&DomainNameResolverTest::handleServiceQueryResult, this, _1)); return result; @@ -209,5 +228,8 @@ class DomainNameResolverTest : public CppUnit::TestFixture { private: + BoostIOServiceThread* ioServiceThread; DummyEventLoop* eventLoop; + boost::shared_ptr<IDNConverter> idnConverter; + boost::shared_ptr<TimerFactory> timerFactory; bool resultsAvailable; std::vector<HostAddress> addressQueryResult; @@ -215,5 +237,5 @@ class DomainNameResolverTest : public CppUnit::TestFixture { boost::optional<DomainNameResolveError> addressQueryError; std::vector<DomainNameServiceQuery::Result> serviceQueryResult; - PlatformDomainNameResolver* resolver; + DomainNameResolver* resolver; }; diff --git a/Swiften/QA/NetworkTest/SConscript b/Swiften/QA/NetworkTest/SConscript index f9308f6..b090165 100644 --- a/Swiften/QA/NetworkTest/SConscript +++ b/Swiften/QA/NetworkTest/SConscript @@ -9,8 +9,9 @@ if env["TEST"] : myenv.MergeFlags(myenv["CHECKER_FLAGS"]) myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) + myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) myenv.MergeFlags(myenv["CPPUNIT_FLAGS"]) - myenv.MergeFlags(myenv["BOOST_FLAGS"]) - myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) - myenv.MergeFlags(env["PLATFORM_FLAGS"]) + + if env.get("unbound", False) : + myenv.Append(CPPDEFINES = ["USE_UNBOUND"]) tester = myenv.Program("NetworkTest", [ diff --git a/Swiften/QA/ScriptedTests/MultipleClients.lua b/Swiften/QA/ScriptedTests/MultipleClients.lua index ce51481..ddc7c44 100644 --- a/Swiften/QA/ScriptedTests/MultipleClients.lua +++ b/Swiften/QA/ScriptedTests/MultipleClients.lua @@ -1,4 +1,4 @@ -- --- Copyright (c) 2010 Remko Tronçon +-- Copyright (c) 2010-2013 Remko Tronçon -- Licensed under the GNU General Public License v3. -- See Documentation/Licenses/GPLv3.txt for more information. @@ -17,9 +17,9 @@ for i = 1, num_clients do client:set_options({compress = false}) client:async_connect() - table.insert(clients, client) + clients[#clients+1] = client end print("Waiting for clients to be connected") -for i, client in ipairs(clients) do +for _, client in ipairs(clients) do client:wait_connected() client:send_presence("Hello") @@ -27,5 +27,5 @@ end print("Disconnecting clients") -for i, client in ipairs(clients) do +for _, client in ipairs(clients) do client:disconnect() end diff --git a/Swiften/QA/ScriptedTests/PubSub.lua b/Swiften/QA/ScriptedTests/PubSub.lua new file mode 100644 index 0000000..43cce14 --- /dev/null +++ b/Swiften/QA/ScriptedTests/PubSub.lua @@ -0,0 +1,340 @@ + --[[ + Copyright (c) 2013 Remko Tronçon + Licensed under the GNU General Public License. + See the COPYING file for more information. +--]] + +require 'sluift' + +sluift.debug = os.getenv("SLUIFT_DEBUG") + +local publisher +local publisher_jid = os.getenv("SLUIFT_JID") +local pubsub_jid = os.getenv("SLUIFT_PUBSUB_SERVICE") or sluift.jid.to_bare(publisher_jid) +local pubsub +local node_id = os.getenv("SLUIFT_PUBSUB_NODE") or "http://swift.im/Swiften/QA/PubSub" +local node + +local subscriber +local subscriber_jid = os.getenv("SLUIFT_JID2") +local subscriber_pubsub +local subscriber_node + +local publish_item = {id = 'item_id', data = {{ _type = 'software_version', name = 'MyTest', os = 'Lua' }} } +local publish_item2 = {id = 'item_id2', data = {{ _type = 'software_version', name = 'MyTest2', os = 'Lua' }} } +local publish_item3 = {id = 'item_id3', data = {{ _type = 'software_version', name = 'MyTest3', os = 'Lua' }} } + +-------------------------------------------------------------------------------- +-- Helper methods +-------------------------------------------------------------------------------- + +function purge_pubsub_events(client) + client:for_each_pubsub_event({timeout = 2000}, function() end) +end + +-------------------------------------------------------------------------------- +-- 5. Entity use cases +-------------------------------------------------------------------------------- +function test_entity_use_cases() + node:delete() + + -- 5.2 List nodes + assert(node:create()) + local nodes = assert(pubsub:list_nodes()).items + local found_item = false + for _, node in ipairs(nodes) do + if node.node == node_id then found_item = true end + end + assert(found_item) + assert(node:delete()) + + + -- 5.5 Discover items of node + assert(node:create()) + assert(node:publish {items = {publish_item}}) + local items = assert(node:list_items()).items + assert(#items == 1) + assert(items[1].name == 'item_id') + assert(node:delete()) + + -- 5.6 Subscriptions + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + local service_subscriptions = assert(subscriber_pubsub:get_subscriptions()) + assert(#service_subscriptions == 1) + assert(service_subscriptions[1].node == node_id) + assert(service_subscriptions[1].jid == subscriber_jid) + assert(service_subscriptions[1].subscription == 'subscribed') + local node_subscriptions = assert(subscriber_node:get_subscriptions()) + assert(#node_subscriptions == 1) + assert(node_subscriptions[1].jid == subscriber_jid) + assert(node_subscriptions[1].subscription == 'subscribed') + assert(node:delete()) + + -- 5.7 Retrieve affiliations + --print(pubsub:get_affiliations()) -- Freezes Isode + --print(node:get_affiliations()) -- Freezes isode +end + +-------------------------------------------------------------------------------- +-- 6. Subscriber use cases +-------------------------------------------------------------------------------- + +function test_subscriber_use_cases() + node:delete() + + -- 6.1 Subscribe to a node + assert(node:create()) + local subscription = assert(subscriber_node:subscribe({ jid = subscriber_jid })) + -- TODO: Test subscription id etc. Doesn't work with M-link atm + -- TODO: Test pending subscription + -- TODO: Test configuration required + assert(node:delete()) + + -- 6.2 Unsubscribe from a node + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + assert(subscriber_node:unsubscribe({ jid = subscriber_jid })) + assert(node:delete()) + + -- 6.3 Configure subscription options + -- TODO: Not supported by M-Link? Finish it later + --assert(node:create()) + --assert(subscriber_node:subscribe({ jid = subscriber_jid })) + --local options = assert(subscriber_node:get_subscription_options({ jid = subscriber_jid })) + --print(options) + --assert(node:delete()) + + -- 6.4 Request default subscription configuration options + -- TODO: Not supported by M-Link? Finish it later + --local options = assert(subscriber_pubsub:get_default_subscription_options()) + --print(options) + --local options = assert(subscriber_node:get_default_subscription_options()) + --print(options) + + -- 6.5 Retrieve items of a node + assert(node:create()) + assert(node:set_configuration{configuration = {['pubsub#max_items'] = '10'}}) + assert(node:publish{item = publish_item}) + assert(node:publish{item = publish_item2}) + local items = assert(subscriber_node:get_items()) + assert(#items == 2) + assert(items[1].id == 'item_id') + assert(items[1].data[1].name == 'MyTest') + assert(items[2].id == 'item_id2') + assert(items[2].data[1].name == 'MyTest2') + assert(node:delete()) + + -- 6.5.7 Requesting most recent items + assert(node:create()) + assert(node:set_configuration{configuration = {['pubsub#max_items'] = '10'}}) + assert(node:publish{item = publish_item}) + assert(node:publish{item = publish_item2}) + assert(node:publish{item = publish_item3}) + local items = assert(subscriber_node:get_items{maximum_items = 2}) + assert(#items == 2) + assert(items[1].id == 'item_id2') + assert(items[1].data[1].name == 'MyTest2') + assert(items[2].id == 'item_id3') + assert(items[2].data[1].name == 'MyTest3') + assert(node:delete()) + + -- 6.5.8 requesting specific item + assert(node:create()) + assert(node:set_configuration{configuration = {['pubsub#max_items'] = '10'}}) + assert(node:publish{item = publish_item}) + assert(node:publish{item = publish_item2}) + local items = assert(subscriber_node:get_item{id = 'item_id2'}) + assert(#items == 1) + assert(items[1].id == 'item_id2') + assert(items[1].data[1].name == 'MyTest2') + assert(node:delete()) +end + +-------------------------------------------------------------------------------- +-- 7. Publisher use cases +-------------------------------------------------------------------------------- + +function test_publisher_use_cases() + node:delete() + + -- 7.1 Publish item to a node + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + purge_pubsub_events(subscriber) + assert(node:publish {items = {publish_item}}) + local event = assert(subscriber:get_next_event { type = 'pubsub' }) + assert(event.from == publisher_jid) + assert(event._type == 'pubsub_event_items') + assert(event.items[1].id == publish_item.id) + assert(event.items[1].data[1].os == publish_item.data[1].os) + assert(event.item.os == publish_item.data[1].os) + assert(node:delete()) + + -- 7.2 Delete item from a node + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + assert(node:publish {items = {publish_item}}) + assert(node:retract { id = 'item_id', notify = true }) + assert(node:delete()) + + -- 7.2.2.1 Delete and notify + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + assert(node:publish {items = {publish_item}}) + purge_pubsub_events(subscriber) + assert(node:retract { id = 'item_id', notify = true }) + local event = assert(subscriber:get_next_event { type = 'pubsub' }) + assert(event._type == 'pubsub_event_items') + assert(event.retracts[1].id == 'item_id') + assert(node:delete()) + + -- Publish an unknown element type + atom = [[ + <entry xmlns='http://www.w3.org/2005/Atom'> + <title>Down the Rabbit Hole</title> + <summary> + Alice was beginning to get very tired of sitting by her sister on the + bank and of having nothing to do: once or twice she had peeped into the + book her sister was reading, but it had no pictures or conversations in + it, "and what is the use of a book," thought Alice, "without pictures + or conversations?' + </summary> + <link rel='alternate' type='text/html' + href='http://www.gutenberg.org/files/11/11-h/11-h.htm#link2HCH0001'/> + <id>tag:gutenberg.org,2008:entry-1234</id> + <published>2008-06-25T18:30:02Z</published> + <updated>2008-06-25T18:30:02Z</updated> + </entry> + ]] + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + purge_pubsub_events(subscriber) + assert(node:publish { item = atom }) + local event_item = assert(subscriber:get_next_event { type = 'pubsub' }).item + assert(event_item._type == 'dom') + assert(event_item.ns == 'http://www.w3.org/2005/Atom') + assert(event_item.tag == 'entry') + assert(node:delete()) +end + +-------------------------------------------------------------------------------- +-- 8 Owner Use Cases +-------------------------------------------------------------------------------- + +function test_owner_use_cases() + node:delete() + + -- 8.1 Create a node + -- Create node with default config + assert(node:create()) + configuration = assert(node:get_configuration())['data'] + assert(node:delete()) + + -- Create node with custom config + print("Creating with configuration") + assert(node:create { configuration = { ['pubsub#access_model'] = 'whitelist' } }) + configuration = assert(node:get_configuration())['data'] + assert(configuration['pubsub#access_model']['value'] == 'whitelist') + assert(node:delete()) + + -- 8.2 Configure node + -- Set configuration + assert(node:create()) + assert(node:set_configuration {configuration = {['pubsub#access_model'] = 'whitelist'}}) + configuration = assert(node:get_configuration())['data'] + assert(configuration['pubsub#access_model']['value'] == 'whitelist') + assert(node:delete()) + + -- Untested: 8.2.5.3 Success With Notifications + + -- 8.3 Request Default Node Configuration Options + configuration = assert(pubsub:get_default_configuration())['data'] + assert(configuration['pubsub#access_model'] ~= nil) + + -- 8.4 Delete node + -- Without redirection (see above) + -- With redirection + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + purge_pubsub_events(subscriber) + assert(node:delete {redirect = 'foo@bar.com'}) + -- FIXME: M-Link doesn't send out an event. Test this later. + --local event = assert(subscriber:get_next_event { type = 'pubsub' }) + --print(event) + --assert(event._type == 'pubsub_event_items') + --assert(event.retracts[1].id == 'item_id') + + -- 8.5 Purge node items + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + -- Publishing multiple items doesn't seem to work in M-Link + --assert(node:publish {items = { publish_item, publish_item2 }}) + assert(node:publish {items = {publish_item} }) + assert(node:publish {items = {publish_item2} }) + purge_pubsub_events(subscriber) + if node:purge() then + -- Hasn't worked yet. Add more to this test later (including notifications) + else + print("Warning: Purge not supported. Skipping test") + end + assert(node:delete()) + + -- 8.6 Manage subscription requests + -- TODO + + -- 8.7 Process pending subscription requests + -- TODO + + -- 8.8 Manage Subscriptions + assert(node:create()) + assert(subscriber_node:subscribe({ jid = subscriber_jid })) + local items = assert(node:get_owner_subscriptions()) + assert(#items == 1) + assert(items[1].jid == subscriber_jid) + assert(items[1].subscription == "subscribed") + assert(node:delete()) + + -- 8.9 Manage Affiliations + assert(node:create()) + assert(node:set_owner_affiliations{affiliations = {{jid = subscriber_jid, type = 'publisher'}}}) + local items = assert(node:get_owner_affiliations()) + assert(#items == 2) + assert(items[1].jid == publisher_jid) + assert(items[1].type == "owner") + assert(items[2].jid == subscriber_jid) + assert(items[2].type == "publisher") + assert(node:delete()) +end + +function run_tests() + connect_options = {} + + -- Set up publisher & subscriber + publisher = sluift.new_client(publisher_jid, os.getenv("SLUIFT_PASS")) + assert(publisher:connect(connect_options)) + subscriber = sluift.new_client(subscriber_jid, os.getenv("SLUIFT_PASS2")) + assert(subscriber:connect(connect_options)) + + pubsub = publisher:pubsub(pubsub_jid) + node = pubsub:node(node_id) + + subscriber_pubsub = subscriber:pubsub(pubsub_jid) + subscriber_node = subscriber_pubsub:node(node_id) + + -- The tests + test_entity_use_cases() + test_subscriber_use_cases() + test_publisher_use_cases() + test_owner_use_cases() +end + +success, err = pcall(run_tests) + +if subscriber then subscriber:disconnect() end +if publisher then publisher:disconnect() end + +if not success then + print(err) + os.exit(-1) +end diff --git a/Swiften/QA/ScriptedTests/SendMessage.lua b/Swiften/QA/ScriptedTests/SendMessage.lua index 8c54d00..9623ef4 100644 --- a/Swiften/QA/ScriptedTests/SendMessage.lua +++ b/Swiften/QA/ScriptedTests/SendMessage.lua @@ -1,4 +1,4 @@ -- --- Copyright (c) 2010 Remko Tronçon +-- Copyright (c) 2010-2013 Remko Tronçon -- Licensed under the GNU General Public License v3. -- See Documentation/Licenses/GPLv3.txt for more information. @@ -24,5 +24,5 @@ client2:send_presence("I'm here") print "Checking version of client 2 from client 1" client2:set_version({name = "Sluift Test", version = "1.0"}) -client2_version = client1:get_version(client2_jid) +client2_version = client1:get_software_version {to=client2_jid} assert(client2_version["name"] == "Sluift Test") assert(client2_version["version"] == "1.0") @@ -30,14 +30,14 @@ assert(client2_version["version"] == "1.0") print "Sending message from client 1 to client 2" client1:send_message(client2_jid, "Hello") -received_message = client2:for_event(function(event) - if event["type"] == "message" and event["from"] == client1_jid then - return event["body"] +received_message = client2:for_each_message({timeout = 1000}, function(message) + if message["from"] == client1_jid then + return message["body"] end - end, 10000) +end) assert(received_message == "Hello") print "Retrieving the roster" roster = client1:get_roster() -tprint(roster) +sluift.tprint(roster) client1:disconnect() diff --git a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp index 7667176..4145696 100644 --- a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp +++ b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp @@ -50,5 +50,5 @@ class VCardFileStorageTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(boost::filesystem::exists(vcardFile)); ByteArray data; - data.readFromFile(vcardFile.string()); + data.readFromFile(vcardFile); CPPUNIT_ASSERT(boost::starts_with(data.toString(), "<vCard xmlns=\"vcard-temp\">")); } diff --git a/Swiften/QA/TLSTest/CertificateTest.cpp b/Swiften/QA/TLSTest/CertificateTest.cpp index 6932881..2089732 100644 --- a/Swiften/QA/TLSTest/CertificateTest.cpp +++ b/Swiften/QA/TLSTest/CertificateTest.cpp @@ -33,5 +33,5 @@ class CertificateTest : public CppUnit::TestFixture { void setUp() { pathProvider = new PlatformApplicationPathProvider("FileReadBytestreamTest"); - readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt").string()); + readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt")); certificateFactory = new CERTIFICATE_FACTORY(); } @@ -43,5 +43,5 @@ class CertificateTest : public CppUnit::TestFixture { void testConstructFromDER() { - Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData); + Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData)); CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getCommonNames()[0]); @@ -49,5 +49,5 @@ class CertificateTest : public CppUnit::TestFixture { void testToDER() { - Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData); + Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData)); CPPUNIT_ASSERT_EQUAL(certificateData, testling->toDER()); @@ -56,5 +56,5 @@ class CertificateTest : public CppUnit::TestFixture { /* void testGetSubjectName() { - Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData); + Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData); CPPUNIT_ASSERT_EQUAL(std::string("/description=114072-VMk8pdi1aj5kTXxO/C=US/ST=Colorado/L=Denver/O=Peter Saint-Andre/OU=StartCom Trusted Certificate Member/CN=*.jabber.org/emailAddress=hostmaster@jabber.org"), testling->getSubjectName()); @@ -63,5 +63,5 @@ class CertificateTest : public CppUnit::TestFixture { void testGetCommonNames() { - Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData); + Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData)); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getCommonNames().size())); @@ -70,5 +70,5 @@ class CertificateTest : public CppUnit::TestFixture { void testGetSRVNames() { - Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData); + Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData)); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getSRVNames().size())); @@ -77,5 +77,5 @@ class CertificateTest : public CppUnit::TestFixture { void testGetDNSNames() { - Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData); + Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData)); CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(testling->getDNSNames().size())); @@ -85,5 +85,5 @@ class CertificateTest : public CppUnit::TestFixture { void testGetXMPPAddresses() { - Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData); + Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData)); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getXMPPAddresses().size())); diff --git a/Swiften/QA/TLSTest/SConscript b/Swiften/QA/TLSTest/SConscript index 14e2de0..18f6998 100644 --- a/Swiften/QA/TLSTest/SConscript +++ b/Swiften/QA/TLSTest/SConscript @@ -8,11 +8,6 @@ if env["TEST"] : myenv.MergeFlags(myenv["SWIFTOOLS_FLAGS"]) myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) + myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) myenv.MergeFlags(myenv["CPPUNIT_FLAGS"]) - myenv.MergeFlags(myenv["BOOST_FLAGS"]) - myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) - if myenv.get("HAVE_OPENSSL") : - myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) - myenv.Append(CPPDEFINES = ["HAVE_OPENSSL"]) - myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) tester = myenv.Program("TLSTest", [ diff --git a/Swiften/Queries/GenericRequest.h b/Swiften/Queries/GenericRequest.h index b9cc6fc..b1b7f8a 100644 --- a/Swiften/Queries/GenericRequest.h +++ b/Swiften/Queries/GenericRequest.h @@ -8,5 +8,4 @@ #include <Swiften/Base/boost_bsignals.h> - #include <Swiften/Queries/Request.h> @@ -24,4 +23,7 @@ namespace Swift { class GenericRequest : public Request { public: + typedef boost::shared_ptr<GenericRequest<PAYLOAD_TYPE> > ref; + + public: /** * Create a request suitable for client use. @@ -63,5 +65,5 @@ namespace Swift { } - protected: + public: boost::shared_ptr<PAYLOAD_TYPE> getPayloadGeneric() const { return boost::dynamic_pointer_cast<PAYLOAD_TYPE>(getPayload()); diff --git a/Swiften/Queries/GetResponder.h b/Swiften/Queries/GetResponder.h index bca507a..213a52f 100644 --- a/Swiften/Queries/GetResponder.h +++ b/Swiften/Queries/GetResponder.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Queries/Responder.h> namespace Swift { template<typename T> - class GetResponder : public Responder<T> { + class SWIFTEN_API GetResponder : public Responder<T> { public: GetResponder(IQRouter* router) : Responder<T>(router) {} diff --git a/Swiften/Queries/IQChannel.h b/Swiften/Queries/IQChannel.h index 71a6dd4..c9da593 100644 --- a/Swiften/Queries/IQChannel.h +++ b/Swiften/Queries/IQChannel.h @@ -11,8 +11,9 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Elements/IQ.h> namespace Swift { - class IQChannel { + class SWIFTEN_API IQChannel { public: virtual ~IQChannel(); diff --git a/Swiften/Queries/IQHandler.h b/Swiften/Queries/IQHandler.h index c9af5ea..19e16a7 100644 --- a/Swiften/Queries/IQHandler.h +++ b/Swiften/Queries/IQHandler.h @@ -9,4 +9,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/IQ.h> @@ -14,5 +15,5 @@ namespace Swift { class IQRouter; - class IQHandler { + class SWIFTEN_API IQHandler { public: virtual ~IQHandler(); diff --git a/Swiften/Queries/IQRouter.h b/Swiften/Queries/IQRouter.h index de2822b..0655035 100644 --- a/Swiften/Queries/IQRouter.h +++ b/Swiften/Queries/IQRouter.h @@ -9,6 +9,7 @@ #include <boost/shared_ptr.hpp> #include <vector> - #include <string> + +#include <Swiften/Base/API.h> #include <Swiften/Elements/IQ.h> @@ -17,5 +18,5 @@ namespace Swift { class IQHandler; - class IQRouter { + class SWIFTEN_API IQRouter { public: IQRouter(IQChannel* channel); diff --git a/Swiften/Queries/PubSubRequest.h b/Swiften/Queries/PubSubRequest.h new file mode 100644 index 0000000..55bf9e3 --- /dev/null +++ b/Swiften/Queries/PubSubRequest.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Queries/Request.h> +#include <Swiften/Elements/ContainerPayload.h> +#include <Swiften/PubSub/PubSubUtil.h> +#include <Swiften/Elements/PubSub.h> +#include <Swiften/Elements/PubSubOwnerPubSub.h> +#include <Swiften/Elements/PubSubCreate.h> +#include <Swiften/Elements/PubSubSubscribe.h> +#include <Swiften/Elements/PubSubAffiliations.h> +#include <Swiften/Elements/PubSubDefault.h> +#include <Swiften/Elements/PubSubItems.h> +#include <Swiften/Elements/PubSubPublish.h> +#include <Swiften/Elements/PubSubRetract.h> +#include <Swiften/Elements/PubSubSubscription.h> +#include <Swiften/Elements/PubSubSubscriptions.h> +#include <Swiften/Elements/PubSubUnsubscribe.h> +#include <Swiften/Elements/PubSubOwnerAffiliations.h> +#include <Swiften/Elements/PubSubOwnerConfigure.h> +#include <Swiften/Elements/PubSubOwnerDefault.h> +#include <Swiften/Elements/PubSubOwnerDelete.h> +#include <Swiften/Elements/PubSubOwnerPurge.h> +#include <Swiften/Elements/PubSubOwnerSubscriptions.h> + +namespace Swift { + namespace Detail { + template<typename T> + struct PubSubPayloadTraits; + +#define SWIFTEN_PUBSUB_DECLARE_PAYLOAD_TRAITS(PAYLOAD, CONTAINER, RESPONSE) \ + template<> struct PubSubPayloadTraits< PAYLOAD > { \ + typedef CONTAINER ContainerType; \ + typedef RESPONSE ResponseType; \ + }; + + SWIFTEN_PUBSUB_FOREACH_PUBSUB_PAYLOAD_TYPE( + SWIFTEN_PUBSUB_DECLARE_PAYLOAD_TRAITS) + } + + template<typename T> + class PubSubRequest : public Request { + typedef typename Detail::PubSubPayloadTraits<T>::ContainerType ContainerType; + typedef typename Detail::PubSubPayloadTraits<T>::ResponseType ResponseType; + + public: + PubSubRequest( + IQ::Type type, + const JID& receiver, + boost::shared_ptr<T> payload, + IQRouter* router) : + Request(type, receiver, router) { + boost::shared_ptr<ContainerType> wrapper = boost::make_shared<ContainerType>(); + wrapper->setPayload(payload); + setPayload(wrapper); + } + + PubSubRequest( + IQ::Type type, + const JID& sender, + const JID& receiver, + boost::shared_ptr<T> payload, + IQRouter* router) : + Request(type, sender, receiver, router) { + boost::shared_ptr<ContainerType> wrapper = boost::make_shared<ContainerType>(); + wrapper->setPayload(payload); + setPayload(wrapper); + } + + virtual void handleResponse( + boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { + boost::shared_ptr<ResponseType> result; + if (boost::shared_ptr<ContainerType> container = boost::dynamic_pointer_cast<ContainerType>(payload)) { + result = boost::dynamic_pointer_cast<ResponseType>(container->getPayload()); + } + onResponse(result, error); + } + + public: + boost::signal<void (boost::shared_ptr<ResponseType>, ErrorPayload::ref)> onResponse; + }; +} diff --git a/Swiften/Queries/RawRequest.h b/Swiften/Queries/RawRequest.h index e5b3a1d..efe0890 100644 --- a/Swiften/Queries/RawRequest.h +++ b/Swiften/Queries/RawRequest.h @@ -10,4 +10,5 @@ #include <typeinfo> +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Queries/Request.h> #include <Swiften/Elements/RawXMLPayload.h> @@ -34,5 +35,5 @@ namespace Swift { virtual void handleResponse(boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { if (error) { - onResponse(ErrorSerializer().serializePayload(error)); + onResponse(ErrorSerializer(&serializers).serializePayload(error)); } else { diff --git a/Swiften/Queries/Request.cpp b/Swiften/Queries/Request.cpp index 422f36c..40c8f60 100644 --- a/Swiften/Queries/Request.cpp +++ b/Swiften/Queries/Request.cpp @@ -24,5 +24,5 @@ Request::Request(IQ::Type type, const JID& sender, const JID& receiver, IQRouter } -void Request::send() { +std::string Request::send() { assert(payload_); assert(!sent_); @@ -44,4 +44,5 @@ void Request::send() { router_->sendIQ(iq); + return id_; } diff --git a/Swiften/Queries/Request.h b/Swiften/Queries/Request.h index 668ed04..f17cc11 100644 --- a/Swiften/Queries/Request.h +++ b/Swiften/Queries/Request.h @@ -10,6 +10,7 @@ #include <boost/optional.hpp> #include <boost/enable_shared_from_this.hpp> - #include <string> + +#include <Swiften/Base/API.h> #include <Swiften/Queries/IQHandler.h> #include <Swiften/Elements/IQ.h> @@ -22,7 +23,7 @@ namespace Swift { * An IQ get/set request query. */ - class Request : public IQHandler, public boost::enable_shared_from_this<Request> { + class SWIFTEN_API Request : public IQHandler, public boost::enable_shared_from_this<Request> { public: - void send(); + std::string send(); const JID& getReceiver() const { @@ -30,4 +31,13 @@ namespace Swift { } + /** + * Returns the ID of this request. + * This will only be set after send() is called. + */ + const std::string& getID() const { + return id_; + } + + protected: /** diff --git a/Swiften/Queries/Responder.h b/Swiften/Queries/Responder.h index 2ba9c24..edcaa52 100644 --- a/Swiften/Queries/Responder.h +++ b/Swiften/Queries/Responder.h @@ -84,6 +84,6 @@ namespace Swift { * Convenience function for responding with an error. */ - void sendError(const JID& to, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type) { - router_->sendIQ(IQ::createError(to, id, condition, type)); + void sendError(const JID& to, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type, Payload::ref payload = Payload::ref()) { + router_->sendIQ(IQ::createError(to, id, condition, type, payload)); } @@ -91,6 +91,6 @@ namespace Swift { * Convenience function for responding with an error from a specific from address. */ - void sendError(const JID& to, const JID& from, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type) { - router_->sendIQ(IQ::createError(to, from, id, condition, type)); + void sendError(const JID& to, const JID& from, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type, Payload::ref payload = Payload::ref()) { + router_->sendIQ(IQ::createError(to, from, id, condition, type, payload)); } diff --git a/Swiften/Queries/Responders/SoftwareVersionResponder.h b/Swiften/Queries/Responders/SoftwareVersionResponder.h index a2929df..4957c0f 100644 --- a/Swiften/Queries/Responders/SoftwareVersionResponder.h +++ b/Swiften/Queries/Responders/SoftwareVersionResponder.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Queries/GetResponder.h> #include <Swiften/Elements/SoftwareVersion.h> @@ -13,5 +14,5 @@ namespace Swift { class IQRouter; - class SoftwareVersionResponder : public GetResponder<SoftwareVersion> { + class SWIFTEN_API SoftwareVersionResponder : public GetResponder<SoftwareVersion> { public: SoftwareVersionResponder(IQRouter* router); diff --git a/Swiften/Roster/RosterMemoryStorage.h b/Swiften/Roster/RosterMemoryStorage.h index b659d77..c9312db 100644 --- a/Swiften/Roster/RosterMemoryStorage.h +++ b/Swiften/Roster/RosterMemoryStorage.h @@ -7,8 +7,9 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Roster/RosterStorage.h> namespace Swift { - class RosterMemoryStorage : public RosterStorage { + class SWIFTEN_API RosterMemoryStorage : public RosterStorage { public: RosterMemoryStorage(); diff --git a/Swiften/Roster/RosterStorage.h b/Swiften/Roster/RosterStorage.h index ba24cb3..7f0f20b 100644 --- a/Swiften/Roster/RosterStorage.h +++ b/Swiften/Roster/RosterStorage.h @@ -9,8 +9,9 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/RosterPayload.h> namespace Swift { - class RosterStorage { + class SWIFTEN_API RosterStorage { public: virtual ~RosterStorage(); diff --git a/Swiften/Roster/XMPPRosterController.h b/Swiften/Roster/XMPPRosterController.h index f105463..603f350 100644 --- a/Swiften/Roster/XMPPRosterController.h +++ b/Swiften/Roster/XMPPRosterController.h @@ -9,4 +9,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <string> @@ -21,5 +22,5 @@ namespace Swift { class RosterStorage; - class XMPPRosterController { + class SWIFTEN_API XMPPRosterController { public: XMPPRosterController(IQRouter *iqRouter, XMPPRosterImpl* xmppRoster, RosterStorage* storage); diff --git a/Swiften/Roster/XMPPRosterImpl.h b/Swiften/Roster/XMPPRosterImpl.h index cbb3166..96da1f3 100644 --- a/Swiften/Roster/XMPPRosterImpl.h +++ b/Swiften/Roster/XMPPRosterImpl.h @@ -10,12 +10,13 @@ #include <set> +#include <Swiften/Base/API.h> #include <Swiften/Roster/XMPPRoster.h> namespace Swift { - class XMPPRosterImpl : public XMPPRoster { + class SWIFTEN_API XMPPRosterImpl : public XMPPRoster { public: XMPPRosterImpl(); - void addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, const RosterItemPayload::Subscription subscription); + void addContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, RosterItemPayload::Subscription subscription); void removeContact(const JID& jid); void clear(); diff --git a/Swiften/SASL/ClientAuthenticator.h b/Swiften/SASL/ClientAuthenticator.h index 8710ac8..bc5b4f1 100644 --- a/Swiften/SASL/ClientAuthenticator.h +++ b/Swiften/SASL/ClientAuthenticator.h @@ -11,9 +11,10 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> #include <Swiften/Base/ByteArray.h> namespace Swift { - class ClientAuthenticator { + class SWIFTEN_API ClientAuthenticator { public: ClientAuthenticator(const std::string& name); diff --git a/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp b/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp index 249a538..74cdb85 100644 --- a/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp +++ b/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,16 +9,12 @@ #include <cassert> -#include <Swiften/StringCodecs/MD5.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/Base/Concat.h> #include <Swiften/Base/Algorithm.h> +#include <Swiften/Crypto/CryptoProvider.h> namespace Swift { -DIGESTMD5ClientAuthenticator::DIGESTMD5ClientAuthenticator(const std::string& host, const std::string& nonce) : ClientAuthenticator("DIGEST-MD5"), step(Initial), host(host), cnonce(nonce) { -} - -bool DIGESTMD5ClientAuthenticator::canBeUsed() { - return MD5::isAllowedForCrypto(); +DIGESTMD5ClientAuthenticator::DIGESTMD5ClientAuthenticator(const std::string& host, const std::string& nonce, CryptoProvider* crypto) : ClientAuthenticator("DIGEST-MD5"), step(Initial), host(host), cnonce(nonce), crypto(crypto) { } @@ -38,5 +34,5 @@ boost::optional<SafeByteArray> DIGESTMD5ClientAuthenticator::getResponse() const // Compute the response value ByteArray A1 = concat( - MD5::getHash( + crypto->getMD5Hash( concat(createSafeByteArray(getAuthenticationID().c_str()), createSafeByteArray(":"), createSafeByteArray(realm.c_str()), createSafeByteArray(":"), getPassword())), createByteArray(":"), createByteArray(*challenge.getValue("nonce")), createByteArray(":"), createByteArray(cnonce)); @@ -46,8 +42,8 @@ boost::optional<SafeByteArray> DIGESTMD5ClientAuthenticator::getResponse() const ByteArray A2 = createByteArray("AUTHENTICATE:" + digestURI); - std::string responseValue = Hexify::hexify(MD5::getHash(createByteArray( - Hexify::hexify(MD5::getHash(A1)) + ":" + std::string responseValue = Hexify::hexify(crypto->getMD5Hash(createByteArray( + Hexify::hexify(crypto->getMD5Hash(A1)) + ":" + *challenge.getValue("nonce") + ":" + nc + ":" + cnonce + ":" + qop + ":" - + Hexify::hexify(MD5::getHash(A2))))); + + Hexify::hexify(crypto->getMD5Hash(A2))))); diff --git a/Swiften/SASL/DIGESTMD5ClientAuthenticator.h b/Swiften/SASL/DIGESTMD5ClientAuthenticator.h index 7ced962..d141401 100644 --- a/Swiften/SASL/DIGESTMD5ClientAuthenticator.h +++ b/Swiften/SASL/DIGESTMD5ClientAuthenticator.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,4 +11,5 @@ #include <string> #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/SASL/ClientAuthenticator.h> #include <Swiften/SASL/DIGESTMD5Properties.h> @@ -16,11 +17,12 @@ namespace Swift { - class DIGESTMD5ClientAuthenticator : public ClientAuthenticator { + class CryptoProvider; + + class SWIFTEN_API DIGESTMD5ClientAuthenticator : public ClientAuthenticator { public: - DIGESTMD5ClientAuthenticator(const std::string& host, const std::string& nonce); + DIGESTMD5ClientAuthenticator(const std::string& host, const std::string& nonce, CryptoProvider*); virtual boost::optional<SafeByteArray> getResponse() const; virtual bool setChallenge(const boost::optional<std::vector<unsigned char> >&); - static bool canBeUsed(); private: @@ -28,8 +30,9 @@ namespace Swift { Initial, Response, - Final, + Final } step; std::string host; std::string cnonce; + CryptoProvider* crypto; DIGESTMD5Properties challenge; }; diff --git a/Swiften/SASL/DIGESTMD5Properties.cpp b/Swiften/SASL/DIGESTMD5Properties.cpp index 6d406e0..23a3476 100644 --- a/Swiften/SASL/DIGESTMD5Properties.cpp +++ b/Swiften/SASL/DIGESTMD5Properties.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -49,5 +49,5 @@ DIGESTMD5Properties DIGESTMD5Properties::parse(const ByteArray& data) { ByteArray currentValue; for (size_t i = 0; i < data.size(); ++i) { - char c = data[i]; + char c = static_cast<char>(data[i]); if (inKey) { if (c == '=') { @@ -55,5 +55,5 @@ DIGESTMD5Properties DIGESTMD5Properties::parse(const ByteArray& data) { } else { - currentKey.push_back(c); + currentKey.push_back(static_cast<unsigned char>(c)); } } @@ -72,5 +72,5 @@ DIGESTMD5Properties DIGESTMD5Properties::parse(const ByteArray& data) { } else { - currentValue.push_back(c); + currentValue.push_back(static_cast<unsigned char>(c)); } } diff --git a/Swiften/SASL/DIGESTMD5Properties.h b/Swiften/SASL/DIGESTMD5Properties.h index ef87574..654208d 100644 --- a/Swiften/SASL/DIGESTMD5Properties.h +++ b/Swiften/SASL/DIGESTMD5Properties.h @@ -11,8 +11,9 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> namespace Swift { - class DIGESTMD5Properties { + class SWIFTEN_API DIGESTMD5Properties { public: DIGESTMD5Properties(); diff --git a/Swiften/SASL/EXTERNALClientAuthenticator.cpp b/Swiften/SASL/EXTERNALClientAuthenticator.cpp new file mode 100644 index 0000000..a3016d1 --- /dev/null +++ b/Swiften/SASL/EXTERNALClientAuthenticator.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/SASL/EXTERNALClientAuthenticator.h> + +namespace Swift { + +EXTERNALClientAuthenticator::EXTERNALClientAuthenticator() : ClientAuthenticator("EXTERNAL"), finished(false) { +} + +boost::optional<SafeByteArray> EXTERNALClientAuthenticator::getResponse() const { + return boost::optional<SafeByteArray>(); +} + +bool EXTERNALClientAuthenticator::setChallenge(const boost::optional<ByteArray>&) { + if (finished) { + return false; + } + finished = true; + return true; +} + +} diff --git a/Swiften/SASL/EXTERNALClientAuthenticator.h b/Swiften/SASL/EXTERNALClientAuthenticator.h new file mode 100644 index 0000000..b986295 --- /dev/null +++ b/Swiften/SASL/EXTERNALClientAuthenticator.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2012 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/SASL/ClientAuthenticator.h> +#include <Swiften/Base/ByteArray.h> + +namespace Swift { + class EXTERNALClientAuthenticator : public ClientAuthenticator { + public: + EXTERNALClientAuthenticator(); + + virtual boost::optional<SafeByteArray> getResponse() const; + virtual bool setChallenge(const boost::optional<ByteArray>&); + + private: + bool finished; + }; +} diff --git a/Swiften/SASL/PLAINClientAuthenticator.h b/Swiften/SASL/PLAINClientAuthenticator.h index 83e45c1..ad3a695 100644 --- a/Swiften/SASL/PLAINClientAuthenticator.h +++ b/Swiften/SASL/PLAINClientAuthenticator.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/SASL/ClientAuthenticator.h> #include <Swiften/Base/ByteArray.h> namespace Swift { - class PLAINClientAuthenticator : public ClientAuthenticator { + class SWIFTEN_API PLAINClientAuthenticator : public ClientAuthenticator { public: PLAINClientAuthenticator(); diff --git a/Swiften/SASL/PLAINMessage.cpp b/Swiften/SASL/PLAINMessage.cpp index 20ffea7..c43b446 100644 --- a/Swiften/SASL/PLAINMessage.cpp +++ b/Swiften/SASL/PLAINMessage.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,5 +16,5 @@ PLAINMessage::PLAINMessage(const SafeByteArray& value) { size_t i = 0; while (i < value.size() && value[i] != '\0') { - authzid += value[i]; + authzid += static_cast<char>(value[i]); ++i; } @@ -24,5 +24,5 @@ PLAINMessage::PLAINMessage(const SafeByteArray& value) { ++i; while (i < value.size() && value[i] != '\0') { - authcid += value[i]; + authcid += static_cast<char>(value[i]); ++i; } diff --git a/Swiften/SASL/PLAINMessage.h b/Swiften/SASL/PLAINMessage.h index 46ee8f7..3811b31 100644 --- a/Swiften/SASL/PLAINMessage.h +++ b/Swiften/SASL/PLAINMessage.h @@ -10,8 +10,10 @@ #include <string> + +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> namespace Swift { - class PLAINMessage { + class SWIFTEN_API PLAINMessage { public: PLAINMessage(const std::string& authcid, const SafeByteArray& password, const std::string& authzid = ""); diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp index 7842b4f..44fef76 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp @@ -11,9 +11,8 @@ #include <boost/lexical_cast.hpp> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/StringCodecs/Base64.h> -#include <Swiften/StringCodecs/HMAC_SHA1.h> #include <Swiften/StringCodecs/PBKDF2.h> -#include <Swiften/IDN/StringPrep.h> +#include <Swiften/IDN/IDNConverter.h> #include <Swiften/Base/Concat.h> @@ -37,5 +36,5 @@ static std::string escape(const std::string& s) { -SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding) : ClientAuthenticator(useChannelBinding ? "SCRAM-SHA-1-PLUS" : "SCRAM-SHA-1"), step(Initial), clientnonce(nonce), useChannelBinding(useChannelBinding) { +SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding, IDNConverter* idnConverter, CryptoProvider* crypto) : ClientAuthenticator(useChannelBinding ? "SCRAM-SHA-1-PLUS" : "SCRAM-SHA-1"), step(Initial), clientnonce(nonce), useChannelBinding(useChannelBinding), idnConverter(idnConverter), crypto(crypto) { } @@ -45,7 +44,7 @@ boost::optional<SafeByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const } else if (step == Proof) { - ByteArray clientKey = HMAC_SHA1()(saltedPassword, createByteArray("Client Key")); - ByteArray storedKey = SHA1::getHash(clientKey); - ByteArray clientSignature = HMAC_SHA1()(createSafeByteArray(storedKey), authMessage); + ByteArray clientKey = crypto->getHMACSHA1(saltedPassword, createByteArray("Client Key")); + ByteArray storedKey = crypto->getSHA1Hash(clientKey); + ByteArray clientSignature = crypto->getHMACSHA1(createSafeByteArray(storedKey), authMessage); ByteArray clientProof = clientKey; for (unsigned int i = 0; i < clientProof.size(); ++i) { @@ -95,18 +94,13 @@ bool SCRAMSHA1ClientAuthenticator::setChallenge(const boost::optional<ByteArray> } - ByteArray channelBindData; - if (useChannelBinding && tlsChannelBindingData) { - channelBindData = *tlsChannelBindingData; - } - // Compute all the values needed for the server signature try { - saltedPassword = PBKDF2::encode<HMAC_SHA1>(StringPrep::getPrepared(getPassword(), StringPrep::SASLPrep), salt, iterations); + saltedPassword = PBKDF2::encode(idnConverter->getStringPrepared(getPassword(), IDNConverter::SASLPrep), salt, iterations, crypto); } catch (const std::exception&) { } authMessage = concat(getInitialBareClientMessage(), createByteArray(","), initialServerMessage, createByteArray(","), getFinalMessageWithoutProof()); - ByteArray serverKey = HMAC_SHA1()(saltedPassword, createByteArray("Server Key")); - serverSignature = HMAC_SHA1()(serverKey, authMessage); + ByteArray serverKey = crypto->getHMACSHA1(saltedPassword, createByteArray("Server Key")); + serverSignature = crypto->getHMACSHA1(serverKey, authMessage); step = Proof; @@ -137,5 +131,5 @@ std::map<char, std::string> SCRAMSHA1ClientAuthenticator::parseMap(const std::st } else if (s[i] == ',') { - result[static_cast<size_t>(key)] = value; + result[key] = value; value = ""; expectKey = true; @@ -154,5 +148,5 @@ ByteArray SCRAMSHA1ClientAuthenticator::getInitialBareClientMessage() const { std::string authenticationID; try { - authenticationID = StringPrep::getPrepared(getAuthenticationID(), StringPrep::SASLPrep); + authenticationID = idnConverter->getStringPrepared(getAuthenticationID(), IDNConverter::SASLPrep); } catch (const std::exception&) { diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h index d140013..b713f9f 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,9 +13,13 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/SASL/ClientAuthenticator.h> +#include <Swiften/Base/API.h> namespace Swift { - class SCRAMSHA1ClientAuthenticator : public ClientAuthenticator { + class IDNConverter; + class CryptoProvider; + + class SWIFTEN_API SCRAMSHA1ClientAuthenticator : public ClientAuthenticator { public: - SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding = false); + SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding, IDNConverter*, CryptoProvider*); void setTLSChannelBindingData(const ByteArray& channelBindingData); @@ -44,4 +48,6 @@ namespace Swift { ByteArray serverSignature; bool useChannelBinding; + IDNConverter* idnConverter; + CryptoProvider* crypto; boost::optional<ByteArray> tlsChannelBindingData; }; diff --git a/Swiften/SASL/SConscript b/Swiften/SASL/SConscript index 085e49d..6509547 100644 --- a/Swiften/SASL/SConscript +++ b/Swiften/SASL/SConscript @@ -2,8 +2,8 @@ Import("swiften_env", "env") myenv = swiften_env.Clone() -myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) objects = myenv.SwiftenObject([ "ClientAuthenticator.cpp", + "EXTERNALClientAuthenticator.cpp", "PLAINClientAuthenticator.cpp", "PLAINMessage.cpp", diff --git a/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp index 38bab15..94bcd0a 100644 --- a/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp +++ b/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,4 +13,7 @@ #include <Swiften/Base/ByteArray.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> + using namespace Swift; @@ -24,6 +27,10 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture { public: + void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + } + void testGetInitialResponse() { - DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh"); + DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh", crypto.get()); CPPUNIT_ASSERT(!testling.getResponse()); @@ -31,5 +38,5 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetResponse() { - DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh"); + DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh", crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -45,5 +52,5 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetResponse_WithAuthorizationID() { - DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh"); + DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh", crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), "myauthzid"); @@ -57,4 +64,7 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(createSafeByteArray("authzid=\"myauthzid\",charset=utf-8,cnonce=\"abcdefgh\",digest-uri=\"xmpp/xmpp.example.com\",nc=00000001,nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\",qop=auth,realm=\"example.com\",response=4293834432b6e7889a2dee7e8fe7dd06,username=\"user\""), response); } + + private: + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp index f0ca01c..3341ad8 100644 --- a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp +++ b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,4 +12,8 @@ #include <Swiften/SASL/SCRAMSHA1ClientAuthenticator.h> #include <Swiften/Base/ByteArray.h> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/IDN/PlatformIDNConverter.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -40,8 +44,10 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { public: void setUp() { + idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); } void testGetInitialResponse() { - SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -52,5 +58,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetInitialResponse_UsernameHasSpecialChars() { - SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get(), crypto.get()); testling.setCredentials(",us=,er=", createSafeByteArray("pass"), ""); @@ -61,5 +67,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetInitialResponse_WithAuthorizationID() { - SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), "auth"); @@ -70,5 +76,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetInitialResponse_WithAuthorizationIDWithSpecialChars() { - SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), "a=u,th"); @@ -79,5 +85,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetInitialResponse_WithoutChannelBindingWithTLSChannelBindingData() { - SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false); + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false, idnConverter.get(), crypto.get()); testling.setTLSChannelBindingData(createByteArray("xyza")); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -89,5 +95,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetInitialResponse_WithChannelBindingWithTLSChannelBindingData() { - SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", true); + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", true, idnConverter.get(), crypto.get()); testling.setTLSChannelBindingData(createByteArray("xyza")); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -99,5 +105,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetFinalResponse() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); @@ -109,5 +115,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetFinalResponse_WithoutChannelBindingWithTLSChannelBindingData() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh", false); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); testling.setTLSChannelBindingData(createByteArray("xyza")); @@ -120,5 +126,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetFinalResponse_WithChannelBindingWithTLSChannelBindingData() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh", true); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", true, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); testling.setTLSChannelBindingData(createByteArray("xyza")); @@ -131,5 +137,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetFinalChallenge() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); @@ -141,5 +147,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetChallenge() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -150,5 +156,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetChallenge_InvalidClientNonce() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -159,5 +165,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetChallenge_OnlyClientNonce() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -168,5 +174,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetChallenge_InvalidIterations() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -177,5 +183,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetChallenge_MissingIterations() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -186,5 +192,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetChallenge_ZeroIterations() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -195,5 +201,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetChallenge_NegativeIterations() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); @@ -204,5 +210,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testSetFinalChallenge_InvalidChallenge() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); @@ -213,5 +219,5 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetResponseAfterFinalChallenge() { - SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + SCRAMSHA1ClientAuthenticator testling("abcdefgh", false, idnConverter.get(), crypto.get()); testling.setCredentials("user", createSafeByteArray("pass"), ""); testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); @@ -220,4 +226,7 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!testling.getResponse()); } + + boost::shared_ptr<IDNConverter> idnConverter; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/SConscript b/Swiften/SConscript index 2e0b73b..29298ca 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -1,3 +1,3 @@ -import os, re, Version, os.path +import os, re, Version, os.path, time Import("env") @@ -7,7 +7,9 @@ Import("env") ################################################################################ -swiften_dep_modules = ["BOOST", "GCONF", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP"] +swiften_dep_modules = ["BOOST", "GCONF", "ICU", "LIBIDN", "ZLIB", "LDNS", "UNBOUND", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP", "SQLITE"] +external_swiften_dep_modules = ["BOOST"] if env["SCONS_STAGE"] == "flags" : + env["SWIFTEN_DLL"] = env["swiften_dll"] env["SWIFTEN_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift") version_match = re.match("(\d+)\.(\d+).*", env["SWIFTEN_VERSION"]) @@ -23,7 +25,8 @@ if env["SCONS_STAGE"] == "flags" : env["SWIFTEN_LIBRARY_ALIASES"] = [] - if ARGUMENTS.get("swiften_dll", False) : + if env["SWIFTEN_DLL"] : if env["PLATFORM"] == "win32" : - pass + env["SWIFTEN_LIBRARY"] = env.subst("Swiften${SWIFTEN_VERSION_MAJOR}") + env["SWIFTEN_LIBRARY_FILE"] = env.subst("${SWIFTEN_LIBRARY}.dll") elif env["PLATFORM"] == "darwin" : env["SWIFTEN_LIBRARY_FILE"] = env.subst("Swiften.${SWIFTEN_VERSION_MAJOR}.${SWIFTEN_VERSION_MINOR}") @@ -33,13 +36,29 @@ if env["SCONS_STAGE"] == "flags" : env["SWIFTEN_LIBRARY_ALIASES"] = ["libSwiften.so", env.subst("libSwiften.so.${SWIFTEN_VERSION_MAJOR}")] + if env["SWIFTEN_DLL"] : + env.AddMethod(lambda e,s : e.SharedObject(s), "SwiftenObject") + else : + env.AddMethod(lambda e,s : e.StaticObject(s), "SwiftenObject") + swiften_env = env.Clone() swiften_env["LIBPATH"] = [Dir(".")] + swiften_env["LIBRUNPATH"] = [Dir(".")] swiften_env["LIBS"] = [swiften_env["SWIFTEN_LIBRARY"]] + if not env["SWIFTEN_DLL"] : + swiften_env.Append(CPPDEFINES = ["SWIFTEN_STATIC"]) dep_env = env.Clone() for module in swiften_dep_modules : + module_flags = env.get(module + "_FLAGS", {}) if env.get(module + "_BUNDLED", False) : - swiften_env.UseFlags(env.get(module + "_FLAGS", {})) + if module in external_swiften_dep_modules : + swiften_env.UseFlags(module_flags) + else : + if module in external_swiften_dep_modules : + dep_env.UseFlags(module_flags) else : - dep_env.UseFlags(env.get(module + "_FLAGS", {})) + # Expose only libraries + dep_env.Append(LIBPATH = module_flags.get("LIBPATH", [])) + dep_env.Append(LIBS = module_flags.get("LIBS", [])) + dep_env.Append(FRAMEWORKS = module_flags.get("FRAMEWORKS", [])) dep_env.UseFlags(dep_env["PLATFORM_FLAGS"]) @@ -47,5 +66,4 @@ if env["SCONS_STAGE"] == "flags" : dep_env.Append(LIBS = ["Winscard"]) - for var, e in [("SWIFTEN_FLAGS", swiften_env), ("SWIFTEN_DEP_FLAGS", dep_env)] : env[var] = { @@ -54,8 +72,12 @@ if env["SCONS_STAGE"] == "flags" : "CPPFLAGS": e.get("CPPFLAGS", []), "LIBPATH": e.get("LIBPATH", []), + "LIBRUNPATH": e.get("LIBRUNPATH", []), "LIBS": e.get("LIBS", []), "FRAMEWORKS": e.get("FRAMEWORKS", []), } + if env["PLATFORM"] == "win32" : + env.Append(CPPDEFINES = [("_WIN32_WINNT","_WIN32_WINNT_VISTA") , ("NTDDI_VERSION","NTDDI_VISTA")]) + ################################################################################ # Build @@ -64,13 +86,15 @@ if env["SCONS_STAGE"] == "flags" : if env["SCONS_STAGE"] == "build" : swiften_env = env.Clone() + swiften_env.Append(CPPDEFINES = ["SWIFTEN_BUILDING"]) for module in swiften_dep_modules : swiften_env.UseFlags(swiften_env.get(module + "_FLAGS", {})) + if env.get(module + "_BUNDLED", False) : + swiften_env.Append(SWIFTEN_OBJECTS = env.get(module + "_OBJECTS", [])) swiften_env.UseFlags(swiften_env["PLATFORM_FLAGS"]) - if ARGUMENTS.get("swiften_dll", False) : - swiften_env.AddMethod(lambda e,s : e.SharedObject(s), "SwiftenObject") + if swiften_env["SWIFTEN_DLL"] : swiften_env.AddMethod(lambda e,l,o : e.SharedLibrary(l,o), "SwiftenLibrary") else : - swiften_env.AddMethod(lambda e,s : e.StaticObject(s), "SwiftenObject") + swiften_env.Append(CPPDEFINES = ["SWIFTEN_STATIC"]) swiften_env.AddMethod(lambda e,l,o : e.StaticLibrary(l,o), "SwiftenLibrary") Export("swiften_env") @@ -100,23 +124,41 @@ if env["SCONS_STAGE"] == "build" : "Elements/Presence.cpp", "Elements/Form.cpp", + "Elements/FormField.cpp", "Elements/StreamFeatures.cpp", "Elements/Element.cpp", + "Elements/ToplevelElement.cpp", "Elements/IQ.cpp", "Elements/Payload.cpp", + "Elements/PubSubPayload.cpp", + "Elements/PubSubOwnerPayload.cpp", + "Elements/PubSubEventPayload.cpp", "Elements/RosterItemExchangePayload.cpp", "Elements/RosterPayload.cpp", + "Elements/SecurityLabel.cpp", "Elements/Stanza.cpp", + "Elements/StanzaAck.cpp", "Elements/StatusShow.cpp", "Elements/StreamManagementEnabled.cpp", "Elements/StreamResume.cpp", "Elements/StreamResumed.cpp", + "Elements/UserLocation.cpp", + "Elements/UserTune.cpp", "Elements/VCard.cpp", "Elements/MUCOccupant.cpp", + "Elements/ResultSet.cpp", + "Elements/Forwarded.cpp", + "Elements/MAMResult.cpp", + "Elements/MAMQuery.cpp", + "Elements/MAMArchived.cpp", + "Elements/IsodeIQDelegation.cpp", "Entity/Entity.cpp", "Entity/PayloadPersister.cpp", "MUC/MUC.cpp", + "MUC/MUCImpl.cpp", "MUC/MUCManager.cpp", "MUC/MUCRegistry.cpp", "MUC/MUCBookmarkManager.cpp", + "PubSub/PubSubManager.cpp", + "PubSub/PubSubManagerImpl.cpp", "Queries/IQChannel.cpp", "Queries/IQHandler.cpp", @@ -185,4 +227,13 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/DeliveryReceiptSerializer.cpp", "Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.cpp", + "Serializer/PayloadSerializers/UserLocationSerializer.cpp", + "Serializer/PayloadSerializers/UserTuneSerializer.cpp", + "Serializer/PayloadSerializers/WhiteboardSerializer.cpp", + "Serializer/PayloadSerializers/ResultSetSerializer.cpp", + "Serializer/PayloadSerializers/ForwardedSerializer.cpp", + "Serializer/PayloadSerializers/MAMResultSerializer.cpp", + "Serializer/PayloadSerializers/MAMQuerySerializer.cpp", + "Serializer/PayloadSerializers/MAMArchivedSerializer.cpp", + "Serializer/PayloadSerializers/IsodeIQDelegationSerializer.cpp", "Serializer/PresenceSerializer.cpp", "Serializer/StanzaSerializer.cpp", @@ -198,7 +249,36 @@ if env["SCONS_STAGE"] == "build" : "Session/BOSHSessionStream.cpp", "StringCodecs/Base64.cpp", - "StringCodecs/SHA256.cpp", - "StringCodecs/MD5.cpp", "StringCodecs/Hexify.cpp", + "Whiteboard/WhiteboardResponder.cpp", + "Whiteboard/WhiteboardSession.cpp", + "Whiteboard/IncomingWhiteboardSession.cpp", + "Whiteboard/OutgoingWhiteboardSession.cpp", + "Whiteboard/WhiteboardSessionManager.cpp", + "Whiteboard/WhiteboardServer.cpp", + "Whiteboard/WhiteboardClient.cpp", + "Elements/Whiteboard/WhiteboardColor.cpp", + "Whiteboard/WhiteboardTransformer.cpp", + ] + + elements = [ + "PubSub", "PubSubAffiliations", "PubSubAffiliation", "PubSubConfigure", "PubSubCreate", "PubSubDefault", + "PubSubItems", "PubSubItem", "PubSubOptions", "PubSubPublish", "PubSubRetract", "PubSubSubscribeOptions", + "PubSubSubscribe", "PubSubSubscriptions", "PubSubSubscription", "PubSubUnsubscribe", + + "PubSubEvent", "PubSubEventAssociate", "PubSubEventCollection", "PubSubEventConfiguration", "PubSubEventDelete", + "PubSubEventDisassociate", "PubSubEventItem", "PubSubEventItems", "PubSubEventPurge", "PubSubEventRedirect", + "PubSubEventRetract", "PubSubEventSubscription", + + "PubSubOwnerAffiliation", "PubSubOwnerAffiliations", "PubSubOwnerConfigure", "PubSubOwnerDefault", + "PubSubOwnerDelete", "PubSubOwnerPubSub", "PubSubOwnerPurge", "PubSubOwnerRedirect", + "PubSubOwnerSubscription", "PubSubOwnerSubscriptions", + + "PubSubError", + ] + for element in elements : + sources += [ + "Elements/" + element + ".cpp", + "Serializer/PayloadSerializers/" + element + "Serializer.cpp", + "Parser/PayloadParsers/" + element + "Parser.cpp", ] @@ -209,4 +289,5 @@ if env["SCONS_STAGE"] == "build" : "SASL", "TLS", + "Crypto", "EventLoop", "Parser", @@ -234,19 +315,29 @@ if env["SCONS_STAGE"] == "build" : ]) - myenv = swiften_env.Clone() - if myenv["PLATFORM"] == "win32": - sources.append("StringCodecs/SHA1_Windows.cpp") - else: - sources.append("StringCodecs/SHA1.cpp") - if myenv["PLATFORM"] != "darwin" and myenv["PLATFORM"] != "win32" and myenv.get("HAVE_GCONF", 0) : env.MergeFlags(env["GCONF_FLAGS"]) - if ARGUMENTS.get("swiften_dll", False) : + + if myenv["SWIFTEN_DLL"] : if myenv["PLATFORM"] == "posix" : myenv.Append(LINKFLAGS = ["-Wl,-soname,libSwiften.so.$SWIFTEN_VERSION_MAJOR"]) myenv["SHLIBSUFFIX"] = "" elif myenv["PLATFORM"] == "darwin" : - myenv.Append(LINKFLAGS = ["-Wl,-install_name,libSwiften.so.$SWIFTEN_VERSION_MAJOR", "-Wl,-compatibility_version,${SWIFTEN_VERSION_MAJOR}.${SWIFTEN_VERSION_MINOR}", "-Wl,-current_version,${SWIFTEN_VERSION_MAJOR}.${SWIFTEN_VERSION_MINOR}"]) + myenv.Append(LINKFLAGS = ["-Wl,-install_name,${SHLIBPREFIX}Swiften.${SWIFTEN_VERSION_MAJOR}${SHLIBSUFFIX}", "-Wl,-compatibility_version,${SWIFTEN_VERSION_MAJOR}.${SWIFTEN_VERSION_MINOR}", "-Wl,-current_version,${SWIFTEN_VERSION_MAJOR}.${SWIFTEN_VERSION_MINOR}"]) + elif myenv["PLATFORM"] == "win32" : + res_env = myenv.Clone() + res_env.Append(CPPDEFINES = [ + ("SWIFTEN_LIBRARY_FILE", "\"\\\"${SWIFTEN_LIBRARY_FILE}\\\"\""), + ("SWIFTEN_COPYRIGHT_YEAR", "\"\\\"2010-%s\\\"\"" % str(time.localtime()[0])), + ("SWIFTEN_VERSION_MAJOR", "${SWIFTEN_VERSION_MAJOR}"), + ("SWIFTEN_VERSION_MINOR", "${SWIFTEN_VERSION_MINOR}"), + ("SWIFTEN_VERSION_PATCH", "${SWIFTEN_VERSION_PATCH}"), + ]) + res = res_env.RES("Swiften.rc") + # For some reason, SCons isn't picking up the dependency correctly + # Adding it explicitly until i figure out why + res_env.Depends(res, "Version.h") + sources += res + swiften_lib = myenv.SwiftenLibrary(swiften_env["SWIFTEN_LIBRARY_FILE"], sources + swiften_env["SWIFTEN_OBJECTS"]) def symlink(env, target, source) : @@ -261,4 +352,5 @@ if env["SCONS_STAGE"] == "build" : File("Avatars/UnitTest/VCardAvatarManagerTest.cpp"), File("Avatars/UnitTest/CombinedAvatarProviderTest.cpp"), + File("Avatars/UnitTest/AvatarManagerImplTest.cpp"), File("Base/UnitTest/IDGeneratorTest.cpp"), File("Base/UnitTest/SimpleIDGeneratorTest.cpp"), @@ -266,8 +358,11 @@ if env["SCONS_STAGE"] == "build" : File("Base/UnitTest/DateTimeTest.cpp"), File("Base/UnitTest/ByteArrayTest.cpp"), + File("Base/UnitTest/URLTest.cpp"), + File("Base/UnitTest/PathTest.cpp"), File("Chat/UnitTest/ChatStateNotifierTest.cpp"), # File("Chat/UnitTest/ChatStateTrackerTest.cpp"), File("Client/UnitTest/ClientSessionTest.cpp"), File("Client/UnitTest/NickResolverTest.cpp"), + File("Client/UnitTest/ClientBlockListManagerTest.cpp"), File("Compress/UnitTest/ZLibCompressorTest.cpp"), File("Compress/UnitTest/ZLibDecompressorTest.cpp"), @@ -292,4 +387,5 @@ if env["SCONS_STAGE"] == "build" : File("LinkLocal/UnitTest/LinkLocalServiceTest.cpp"), File("MUC/UnitTest/MUCTest.cpp"), + File("MUC/UnitTest/MockMUC.cpp"), File("Network/UnitTest/HostAddressTest.cpp"), File("Network/UnitTest/ConnectorTest.cpp"), @@ -299,6 +395,8 @@ if env["SCONS_STAGE"] == "build" : File("Network/UnitTest/BOSHConnectionTest.cpp"), File("Network/UnitTest/BOSHConnectionPoolTest.cpp"), + File("Parser/PayloadParsers/UnitTest/BlockParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/DiscoItemsParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/FormParserTest.cpp"), @@ -326,6 +424,13 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/MUCUserPayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/DeliveryReceiptParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/IdleParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ResultSetParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ForwardedParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MAMResultParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MAMQueryParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MAMArchivedParserTest.cpp"), File("Parser/UnitTest/BOSHBodyExtractorTest.cpp"), File("Parser/UnitTest/AttributeMapTest.cpp"), + File("Parser/UnitTest/EnumParserTest.cpp"), File("Parser/UnitTest/IQParserTest.cpp"), File("Parser/UnitTest/GenericPayloadTreeParserTest.cpp"), @@ -351,4 +456,5 @@ if env["SCONS_STAGE"] == "build" : File("Roster/UnitTest/XMPPRosterSignalHandler.cpp"), File("Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp"), + File("Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp"), @@ -375,4 +481,12 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/DeliveryReceiptSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/IdleSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/PubSubItemSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/PubSubItemsSerializerTest.cpp"), File("Serializer/UnitTest/StreamFeaturesSerializerTest.cpp"), File("Serializer/UnitTest/AuthSuccessSerializerTest.cpp"), @@ -387,13 +501,11 @@ if env["SCONS_STAGE"] == "build" : File("StreamStack/UnitTest/XMPPLayerTest.cpp"), File("StringCodecs/UnitTest/Base64Test.cpp"), - File("StringCodecs/UnitTest/SHA1Test.cpp"), - File("StringCodecs/UnitTest/SHA256Test.cpp"), - File("StringCodecs/UnitTest/MD5Test.cpp"), File("StringCodecs/UnitTest/HexifyTest.cpp"), - File("StringCodecs/UnitTest/HMACTest.cpp"), File("StringCodecs/UnitTest/PBKDF2Test.cpp"), File("TLS/UnitTest/ServerIdentityVerifierTest.cpp"), File("TLS/UnitTest/CertificateTest.cpp"), File("VCards/UnitTest/VCardManagerTest.cpp"), + File("Whiteboard/UnitTest/WhiteboardServerTest.cpp"), + File("Whiteboard/UnitTest/WhiteboardClientTest.cpp"), ]) @@ -416,17 +528,17 @@ if env["SCONS_STAGE"] == "build" : swiften_includes.append(include) # Private modules - if root.endswith("Config") or root.endswith("Compress") : + if root.endswith("Config") : continue # Library-specfifc private modules - if root.endswith("OpenSSL") or root.endswith("Cocoa") or root.endswith("Qt") or root.endswith("IDN") or root.endswith("Avahi") or root.endswith("Bonjour") : + if root.endswith("OpenSSL") or root.endswith("Cocoa") or root.endswith("Qt") or root.endswith("Avahi") or root.endswith("Bonjour") : continue # Library-specific files - if file.startswith("Schannel") or file.startswith("CAPI") or file.startswith("LibXML") or file.startswith("Expat") or file.startswith("GConf") or file.startswith("MacOSX") or file.startswith("Windows") or file.endswith("_Windows.h") or file.startswith("SQLite") or file.startswith("NATPMP") or file.startswith("MiniUPnP") : + if file.endswith("_Private.h") or file.startswith("Schannel") or file.startswith("CAPI") or file.startswith("MacOSX") or file.startswith("Windows") or file.endswith("_Windows.h") or file.startswith("SQLite") or file == "ICUConverter.h" or file == "UnboundDomainNameResolver.h" : continue # Specific headers we don't want to globally include - if file == "Swiften.h" or file == "foreach.h" or file == "Log.h" or file == "format.h" or file == "CompressionLayer.h": + if file == "Swiften.h" or file == "foreach.h" or file == "Log.h" or file == "format.h" : continue swiften_header += "#include <" + include + ">\n" diff --git a/Swiften/Serializer/AuthChallengeSerializer.cpp b/Swiften/Serializer/AuthChallengeSerializer.cpp index 1ddc165..57a79e0 100644 --- a/Swiften/Serializer/AuthChallengeSerializer.cpp +++ b/Swiften/Serializer/AuthChallengeSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,5 +16,5 @@ AuthChallengeSerializer::AuthChallengeSerializer() { } -SafeByteArray AuthChallengeSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthChallengeSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { boost::shared_ptr<AuthChallenge> authChallenge(boost::dynamic_pointer_cast<AuthChallenge>(element)); std::string value; diff --git a/Swiften/Serializer/AuthChallengeSerializer.h b/Swiften/Serializer/AuthChallengeSerializer.h index d485473..af77a5e 100644 --- a/Swiften/Serializer/AuthChallengeSerializer.h +++ b/Swiften/Serializer/AuthChallengeSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,13 +9,14 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/AuthChallenge.h> #include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { - class AuthChallengeSerializer : public GenericElementSerializer<AuthChallenge> { + class SWIFTEN_API AuthChallengeSerializer : public GenericElementSerializer<AuthChallenge> { public: AuthChallengeSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; }; } diff --git a/Swiften/Serializer/AuthFailureSerializer.h b/Swiften/Serializer/AuthFailureSerializer.h index 090f0c4..f7e48f0 100644 --- a/Swiften/Serializer/AuthFailureSerializer.h +++ b/Swiften/Serializer/AuthFailureSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("failure", "urn:ietf:params:xml:ns:xmpp-sasl").serialize()); } diff --git a/Swiften/Serializer/AuthRequestSerializer.cpp b/Swiften/Serializer/AuthRequestSerializer.cpp index 7f25c93..5c78e48 100644 --- a/Swiften/Serializer/AuthRequestSerializer.cpp +++ b/Swiften/Serializer/AuthRequestSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ AuthRequestSerializer::AuthRequestSerializer() { } -SafeByteArray AuthRequestSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthRequestSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { boost::shared_ptr<AuthRequest> authRequest(boost::dynamic_pointer_cast<AuthRequest>(element)); SafeByteArray value; diff --git a/Swiften/Serializer/AuthRequestSerializer.h b/Swiften/Serializer/AuthRequestSerializer.h index add7983..45c2ff8 100644 --- a/Swiften/Serializer/AuthRequestSerializer.h +++ b/Swiften/Serializer/AuthRequestSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,13 +9,14 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/AuthRequest.h> #include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { - class AuthRequestSerializer : public GenericElementSerializer<AuthRequest> { + class SWIFTEN_API AuthRequestSerializer : public GenericElementSerializer<AuthRequest> { public: AuthRequestSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; }; } diff --git a/Swiften/Serializer/AuthResponseSerializer.cpp b/Swiften/Serializer/AuthResponseSerializer.cpp index 86b7fbe..c04fed0 100644 --- a/Swiften/Serializer/AuthResponseSerializer.cpp +++ b/Swiften/Serializer/AuthResponseSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ AuthResponseSerializer::AuthResponseSerializer() { } -SafeByteArray AuthResponseSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthResponseSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { boost::shared_ptr<AuthResponse> authResponse(boost::dynamic_pointer_cast<AuthResponse>(element)); SafeByteArray value; diff --git a/Swiften/Serializer/AuthResponseSerializer.h b/Swiften/Serializer/AuthResponseSerializer.h index 495f8cc..9c9ae74 100644 --- a/Swiften/Serializer/AuthResponseSerializer.h +++ b/Swiften/Serializer/AuthResponseSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,13 +9,14 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/AuthResponse.h> #include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { - class AuthResponseSerializer : public GenericElementSerializer<AuthResponse> { + class SWIFTEN_API AuthResponseSerializer : public GenericElementSerializer<AuthResponse> { public: AuthResponseSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; }; } diff --git a/Swiften/Serializer/AuthSuccessSerializer.cpp b/Swiften/Serializer/AuthSuccessSerializer.cpp index 26b58c3..0f4ef6e 100644 --- a/Swiften/Serializer/AuthSuccessSerializer.cpp +++ b/Swiften/Serializer/AuthSuccessSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,5 +16,5 @@ AuthSuccessSerializer::AuthSuccessSerializer() { } -SafeByteArray AuthSuccessSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthSuccessSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { boost::shared_ptr<AuthSuccess> authSuccess(boost::dynamic_pointer_cast<AuthSuccess>(element)); std::string value; diff --git a/Swiften/Serializer/AuthSuccessSerializer.h b/Swiften/Serializer/AuthSuccessSerializer.h index 8163d16..7aa934e 100644 --- a/Swiften/Serializer/AuthSuccessSerializer.h +++ b/Swiften/Serializer/AuthSuccessSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,13 +9,14 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/AuthSuccess.h> #include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { - class AuthSuccessSerializer : public GenericElementSerializer<AuthSuccess> { + class SWIFTEN_API AuthSuccessSerializer : public GenericElementSerializer<AuthSuccess> { public: AuthSuccessSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; }; } diff --git a/Swiften/Serializer/ComponentHandshakeSerializer.cpp b/Swiften/Serializer/ComponentHandshakeSerializer.cpp index e7837d3..123798c 100644 --- a/Swiften/Serializer/ComponentHandshakeSerializer.cpp +++ b/Swiften/Serializer/ComponentHandshakeSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,5 +14,5 @@ ComponentHandshakeSerializer::ComponentHandshakeSerializer() { } -SafeByteArray ComponentHandshakeSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray ComponentHandshakeSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { boost::shared_ptr<ComponentHandshake> handshake(boost::dynamic_pointer_cast<ComponentHandshake>(element)); return createSafeByteArray("<handshake>" + handshake->getData() + "</handshake>"); diff --git a/Swiften/Serializer/ComponentHandshakeSerializer.h b/Swiften/Serializer/ComponentHandshakeSerializer.h index 1145ed9..54cd7c8 100644 --- a/Swiften/Serializer/ComponentHandshakeSerializer.h +++ b/Swiften/Serializer/ComponentHandshakeSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ namespace Swift { ComponentHandshakeSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; }; } diff --git a/Swiften/Serializer/CompressFailureSerializer.h b/Swiften/Serializer/CompressFailureSerializer.h index 27a638f..2545608 100644 --- a/Swiften/Serializer/CompressFailureSerializer.h +++ b/Swiften/Serializer/CompressFailureSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("failure", "http://jabber.org/protocol/compress").serialize()); } diff --git a/Swiften/Serializer/CompressRequestSerializer.cpp b/Swiften/Serializer/CompressRequestSerializer.cpp index af7f7db..38f5b71 100644 --- a/Swiften/Serializer/CompressRequestSerializer.cpp +++ b/Swiften/Serializer/CompressRequestSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,10 +14,10 @@ CompressRequestSerializer::CompressRequestSerializer() { } -SafeByteArray CompressRequestSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray CompressRequestSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { boost::shared_ptr<CompressRequest> compressRequest(boost::dynamic_pointer_cast<CompressRequest>(element)); return createSafeByteArray("<compress xmlns='http://jabber.org/protocol/compress'><method>" + compressRequest->getMethod() + "</method></compress>"); } -bool CompressRequestSerializer::canSerialize(boost::shared_ptr<Element> element) const { +bool CompressRequestSerializer::canSerialize(boost::shared_ptr<ToplevelElement> element) const { return boost::dynamic_pointer_cast<CompressRequest>(element) != 0; } diff --git a/Swiften/Serializer/CompressRequestSerializer.h b/Swiften/Serializer/CompressRequestSerializer.h index 4d68c98..a8610d1 100644 --- a/Swiften/Serializer/CompressRequestSerializer.h +++ b/Swiften/Serializer/CompressRequestSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,6 +16,6 @@ namespace Swift { CompressRequestSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; - virtual bool canSerialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; + virtual bool canSerialize(boost::shared_ptr<ToplevelElement> element) const; }; } diff --git a/Swiften/Serializer/ElementSerializer.h b/Swiften/Serializer/ElementSerializer.h index ba59106..76c7d20 100644 --- a/Swiften/Serializer/ElementSerializer.h +++ b/Swiften/Serializer/ElementSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,5 +9,5 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Base/SafeByteArray.h> @@ -17,6 +17,6 @@ namespace Swift { virtual ~ElementSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const = 0; - virtual bool canSerialize(boost::shared_ptr<Element> element) const = 0; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const = 0; + virtual bool canSerialize(boost::shared_ptr<ToplevelElement> element) const = 0; }; } diff --git a/Swiften/Serializer/EnableStreamManagementSerializer.h b/Swiften/Serializer/EnableStreamManagementSerializer.h index 384753b..a41df81 100644 --- a/Swiften/Serializer/EnableStreamManagementSerializer.h +++ b/Swiften/Serializer/EnableStreamManagementSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("enable", "urn:xmpp:sm:2").serialize()); } diff --git a/Swiften/Serializer/GenericElementSerializer.h b/Swiften/Serializer/GenericElementSerializer.h index e56f156..620ae7b 100644 --- a/Swiften/Serializer/GenericElementSerializer.h +++ b/Swiften/Serializer/GenericElementSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -15,8 +15,8 @@ namespace Swift { class GenericElementSerializer : public ElementSerializer { public: - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const = 0; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const = 0; - virtual bool canSerialize(boost::shared_ptr<Element> element) const { - return boost::dynamic_pointer_cast<T>(element); + virtual bool canSerialize(boost::shared_ptr<ToplevelElement> element) const { + return !!boost::dynamic_pointer_cast<T>(element); } }; diff --git a/Swiften/Serializer/GenericPayloadSerializer.h b/Swiften/Serializer/GenericPayloadSerializer.h index b501613..7b01824 100644 --- a/Swiften/Serializer/GenericPayloadSerializer.h +++ b/Swiften/Serializer/GenericPayloadSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -20,5 +20,5 @@ namespace Swift { virtual bool canSerialize(boost::shared_ptr<Payload> element) const { - return boost::dynamic_pointer_cast<PAYLOAD_TYPE>(element); + return !!boost::dynamic_pointer_cast<PAYLOAD_TYPE>(element); } diff --git a/Swiften/Serializer/GenericStanzaSerializer.h b/Swiften/Serializer/GenericStanzaSerializer.h index 4129ca8..e8f3787 100644 --- a/Swiften/Serializer/GenericStanzaSerializer.h +++ b/Swiften/Serializer/GenericStanzaSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,12 +13,12 @@ namespace Swift { class GenericStanzaSerializer : public StanzaSerializer { public: - GenericStanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers) : StanzaSerializer(tag, payloadSerializers) {} + GenericStanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explicitNS = boost::optional<std::string>()) : StanzaSerializer(tag, payloadSerializers, explicitNS) {} - virtual bool canSerialize(boost::shared_ptr<Element> element) const { + virtual bool canSerialize(boost::shared_ptr<ToplevelElement> element) const { return dynamic_cast<STANZA_TYPE*>(element.get()) != 0; } virtual void setStanzaSpecificAttributes( - boost::shared_ptr<Element> stanza, + boost::shared_ptr<ToplevelElement> stanza, XMLElement& element) const { setStanzaSpecificAttributesGeneric( diff --git a/Swiften/Serializer/IQSerializer.h b/Swiften/Serializer/IQSerializer.h index 76a9cb7..7ebafa0 100644 --- a/Swiften/Serializer/IQSerializer.h +++ b/Swiften/Serializer/IQSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,9 +11,12 @@ #include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/optional.hpp> + namespace Swift { class IQSerializer : public GenericStanzaSerializer<IQ> { public: - IQSerializer(PayloadSerializerCollection* payloadSerializers) : - GenericStanzaSerializer<IQ>("iq", payloadSerializers) {} + IQSerializer(PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explicitNS = boost::optional<std::string>()) : + GenericStanzaSerializer<IQ>("iq", payloadSerializers, explicitNS) { + } private: diff --git a/Swiften/Serializer/MessageSerializer.cpp b/Swiften/Serializer/MessageSerializer.cpp index c221680..f944f9b 100644 --- a/Swiften/Serializer/MessageSerializer.cpp +++ b/Swiften/Serializer/MessageSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,6 +10,6 @@ namespace Swift { -MessageSerializer::MessageSerializer(PayloadSerializerCollection* payloadSerializers) : - GenericStanzaSerializer<Message>("message", payloadSerializers) { +MessageSerializer::MessageSerializer(PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explicitNS) : + GenericStanzaSerializer<Message>("message", payloadSerializers, explicitNS) { } diff --git a/Swiften/Serializer/MessageSerializer.h b/Swiften/Serializer/MessageSerializer.h index 8e9e941..dd8ca21 100644 --- a/Swiften/Serializer/MessageSerializer.h +++ b/Swiften/Serializer/MessageSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,4 +10,6 @@ #include <Swiften/Elements/Message.h> +#include <boost/optional.hpp> + namespace Swift { class XMLElement; @@ -15,5 +17,5 @@ namespace Swift { class MessageSerializer : public GenericStanzaSerializer<Message> { public: - MessageSerializer(PayloadSerializerCollection* payloadSerializers); + MessageSerializer(PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explitNS = boost::optional<std::string>()); private: diff --git a/Swiften/Serializer/PayloadSerializer.h b/Swiften/Serializer/PayloadSerializer.h index c4ad23b..46132fc 100644 --- a/Swiften/Serializer/PayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializer.h @@ -10,8 +10,10 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> + namespace Swift { class Payload; - class PayloadSerializer { + class SWIFTEN_API PayloadSerializer { public: virtual ~PayloadSerializer(); diff --git a/Swiften/Serializer/PayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializerCollection.cpp index ab2b4f4..0db89a9 100644 --- a/Swiften/Serializer/PayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializerCollection.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -21,5 +21,5 @@ void PayloadSerializerCollection::addSerializer(PayloadSerializer* serializer) { void PayloadSerializerCollection::removeSerializer(PayloadSerializer* serializer) { - serializers_.erase(remove(serializers_.begin(), serializers_.end(), serializer), serializers_.end()); + serializers_.erase(std::remove(serializers_.begin(), serializers_.end(), serializer), serializers_.end()); } diff --git a/Swiften/Serializer/PayloadSerializerCollection.h b/Swiften/Serializer/PayloadSerializerCollection.h index f922a45..78f8808 100644 --- a/Swiften/Serializer/PayloadSerializerCollection.h +++ b/Swiften/Serializer/PayloadSerializerCollection.h @@ -10,4 +10,5 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Payload.h> @@ -16,5 +17,5 @@ namespace Swift { - class PayloadSerializerCollection { + class SWIFTEN_API PayloadSerializerCollection { public: PayloadSerializerCollection(); diff --git a/Swiften/Serializer/PayloadSerializers/BlockSerializer.h b/Swiften/Serializer/PayloadSerializers/BlockSerializer.h index 345463c..fc628c2 100644 --- a/Swiften/Serializer/PayloadSerializers/BlockSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/BlockSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,7 +9,7 @@ #include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/JID/JID.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Serializer/XML/XMLElement.h> -#include <Swiften/Base/foreach.h> namespace Swift { @@ -22,7 +22,9 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<BLOCK_ELEMENT> payload) const { XMLElement element(tag, "urn:xmpp:blocking"); - foreach (const JID& jid, payload->getItems()) { + const std::vector<JID>& items = payload->getItems(); + for (std::vector<JID>::const_iterator i = items.begin(); i != items.end(); ++i) { boost::shared_ptr<XMLElement> item = boost::make_shared<XMLElement>("item"); - item->setAttribute("jid", jid); + item->setAttribute("jid", *i); + element.addNode(item); } return element.serialize(); diff --git a/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h b/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h index 2587ee0..b952a31 100644 --- a/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/CapsInfo.h> namespace Swift { - class CapsInfoSerializer : public GenericPayloadSerializer<CapsInfo> { + class SWIFTEN_API CapsInfoSerializer : public GenericPayloadSerializer<CapsInfo> { public: CapsInfoSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp index ee468bb..d23cad7 100644 --- a/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp @@ -20,5 +20,4 @@ std::string ChatStateSerializer::serializePayload(boost::shared_ptr<ChatState> c case ChatState::Inactive: result += "inactive"; break; case ChatState::Gone: result += "gone"; break; - default: result += "gone"; break; } result += " xmlns=\"http://jabber.org/protocol/chatstates\"/>"; diff --git a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp index 6148632..f809798 100644 --- a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp @@ -21,5 +21,5 @@ DelaySerializer::DelaySerializer() : GenericPayloadSerializer<Delay>() { std::string DelaySerializer::serializePayload(boost::shared_ptr<Delay> delay) const { XMLElement delayElement("delay", "urn:xmpp:delay"); - if (delay->getFrom()) { + if (delay->getFrom() && delay->getFrom()->isValid()) { delayElement.setAttribute("from", delay->getFrom()->toString()); } diff --git a/Swiften/Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.h b/Swiften/Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.h index aa3c315..784d9e1 100644 --- a/Swiften/Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.h @@ -9,7 +9,8 @@ #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/DeliveryReceiptRequest.h> +#include <Swiften/Base/API.h> namespace Swift { - class DeliveryReceiptRequestSerializer : public GenericPayloadSerializer<DeliveryReceiptRequest> { + class SWIFTEN_API DeliveryReceiptRequestSerializer : public GenericPayloadSerializer<DeliveryReceiptRequest> { public: DeliveryReceiptRequestSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/DeliveryReceiptSerializer.h b/Swiften/Serializer/PayloadSerializers/DeliveryReceiptSerializer.h index 5fda3ea..92a531a 100644 --- a/Swiften/Serializer/PayloadSerializers/DeliveryReceiptSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/DeliveryReceiptSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/DeliveryReceipt.h> namespace Swift { - class DeliveryReceiptSerializer : public GenericPayloadSerializer<DeliveryReceipt> { + class SWIFTEN_API DeliveryReceiptSerializer : public GenericPayloadSerializer<DeliveryReceipt> { public: DeliveryReceiptSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h b/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h index 3e028e1..233d752 100644 --- a/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/DiscoInfo.h> namespace Swift { - class DiscoInfoSerializer : public GenericPayloadSerializer<DiscoInfo> { + class SWIFTEN_API DiscoInfoSerializer : public GenericPayloadSerializer<DiscoInfo> { public: DiscoInfoSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp index e3bfd54..954b885 100644 --- a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp @@ -7,8 +7,9 @@ #include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> #include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> namespace Swift { -ErrorSerializer::ErrorSerializer() : GenericPayloadSerializer<ErrorPayload>() { +ErrorSerializer::ErrorSerializer(PayloadSerializerCollection* serializers) : GenericPayloadSerializer<ErrorPayload>(), serializers(serializers) { } @@ -20,5 +21,5 @@ std::string ErrorSerializer::serializePayload(boost::shared_ptr<ErrorPayload> er case ErrorPayload::Auth: result += "auth"; break; case ErrorPayload::Wait: result += "wait"; break; - default: result += "cancel"; break; + case ErrorPayload::Cancel: result += "cancel"; break; } result += "\">"; @@ -47,5 +48,5 @@ std::string ErrorSerializer::serializePayload(boost::shared_ptr<ErrorPayload> er case ErrorPayload::SubscriptionRequired: conditionElement = "subscription-required"; break; case ErrorPayload::UnexpectedRequest: conditionElement = "unexpected-request"; break; - default: conditionElement = "undefined-condition"; break; + case ErrorPayload::UndefinedCondition: conditionElement = "undefined-condition"; break; } result += "<" + conditionElement + " xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"; @@ -56,4 +57,11 @@ std::string ErrorSerializer::serializePayload(boost::shared_ptr<ErrorPayload> er } + if (error->getPayload()) { + PayloadSerializer* serializer = serializers->getPayloadSerializer(error->getPayload()); + if (serializer) { + result += serializer->serialize(error->getPayload()); + } + } + result += "</error>"; return result; diff --git a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h index d06efc8..f41d585 100644 --- a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h @@ -7,13 +7,19 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/ErrorPayload.h> namespace Swift { - class ErrorSerializer : public GenericPayloadSerializer<ErrorPayload> { + class PayloadSerializerCollection; + + class SWIFTEN_API ErrorSerializer : public GenericPayloadSerializer<ErrorPayload> { public: - ErrorSerializer(); + ErrorSerializer(PayloadSerializerCollection* serializers); virtual std::string serializePayload(boost::shared_ptr<ErrorPayload> error) const; + + private: + PayloadSerializerCollection* serializers; }; } diff --git a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp index ba658e3..cf0f4ea 100644 --- a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -38,4 +38,8 @@ FormSerializer::FormSerializer() : GenericPayloadSerializer<Form>() { std::string FormSerializer::serializePayload(boost::shared_ptr<Form> form) const { + if (!form) { + return ""; + } + boost::shared_ptr<XMLElement> formElement(new XMLElement("x", "jabber:x:data")); std::string type; @@ -93,64 +97,25 @@ boost::shared_ptr<XMLElement> FormSerializer::fieldToXML(boost::shared_ptr<FormF // Set the value and type std::string fieldType; - if (boost::dynamic_pointer_cast<BooleanFormField>(field)) { - fieldType = "boolean"; - boost::shared_ptr<XMLElement> valueElement(new XMLElement("value")); - valueElement->addNode(XMLTextNode::create(boost::dynamic_pointer_cast<BooleanFormField>(field)->getValue() ? "1" : "0")); - fieldElement->addNode(valueElement); - } - else if (boost::dynamic_pointer_cast<FixedFormField>(field)) { - fieldType = "fixed"; - serializeValueAsString<FixedFormField>(field, fieldElement); - } - else if (boost::dynamic_pointer_cast<HiddenFormField>(field)) { - fieldType = "hidden"; - serializeValueAsString<HiddenFormField>(field, fieldElement); - } - else if (boost::dynamic_pointer_cast<ListSingleFormField>(field)) { - fieldType = "list-single"; - serializeValueAsString<ListSingleFormField>(field, fieldElement); - } - else if (boost::dynamic_pointer_cast<TextPrivateFormField>(field)) { - fieldType = "text-private"; - serializeValueAsString<TextPrivateFormField>(field, fieldElement); - } - else if (boost::dynamic_pointer_cast<TextSingleFormField>(field)) { - fieldType = "text-single"; - serializeValueAsString<TextSingleFormField>(field, fieldElement); - } - else if (boost::dynamic_pointer_cast<JIDMultiFormField>(field)) { - fieldType = "jid-multi"; - std::vector<JID> jids = boost::dynamic_pointer_cast<JIDMultiFormField>(field)->getValue(); - foreach(const JID& jid, jids) { - boost::shared_ptr<XMLElement> valueElement(new XMLElement("value")); - valueElement->addNode(XMLTextNode::create(jid.toString())); - fieldElement->addNode(valueElement); - } - } - else if (boost::dynamic_pointer_cast<JIDSingleFormField>(field)) { - fieldType = "jid-single"; - boost::shared_ptr<XMLElement> valueElement(new XMLElement("value")); - valueElement->addNode(XMLTextNode::create(boost::dynamic_pointer_cast<JIDSingleFormField>(field)->getValue().toString())); - if ( boost::dynamic_pointer_cast<JIDSingleFormField>(field)->getValue().isValid()) fieldElement->addNode(valueElement); - } - else if (boost::dynamic_pointer_cast<ListMultiFormField>(field)) { - fieldType = "list-multi"; - std::vector<std::string> lines = boost::dynamic_pointer_cast<ListMultiFormField>(field)->getValue(); - foreach(const std::string& line, lines) { - boost::shared_ptr<XMLElement> valueElement(new XMLElement("value")); - valueElement->addNode(XMLTextNode::create(line)); - fieldElement->addNode(valueElement); - } - } - else if (boost::dynamic_pointer_cast<TextMultiFormField>(field)) { - fieldType = "text-multi"; - multiLineify(boost::dynamic_pointer_cast<TextMultiFormField>(field)->getValue(), "value", fieldElement); - } - else { - assert(false); + switch (field->getType()) { + case FormField::UnknownType: fieldType = ""; break; + case FormField::BooleanType: fieldType = "boolean"; break; + case FormField::FixedType: fieldType = "fixed"; break; + case FormField::HiddenType: fieldType = "hidden"; break; + case FormField::ListSingleType: fieldType = "list-single"; break; + case FormField::TextMultiType: fieldType = "text-multi"; break; + case FormField::TextPrivateType: fieldType = "text-private"; break; + case FormField::TextSingleType: fieldType = "text-single"; break; + case FormField::JIDSingleType: fieldType = "jid-single"; break; + case FormField::JIDMultiType: fieldType = "jid-multi"; break; + case FormField::ListMultiType: fieldType = "list-multi"; break; } if (!fieldType.empty() && withTypeAttribute) { fieldElement->setAttribute("type", fieldType); } + foreach (const std::string& value, field->getValues()) { + boost::shared_ptr<XMLElement> valueElement = boost::make_shared<XMLElement>("value"); + valueElement->addNode(boost::make_shared<XMLTextNode>(value)); + fieldElement->addNode(valueElement); + } foreach (const FormField::Option& option, field->getOptions()) { diff --git a/Swiften/Serializer/PayloadSerializers/FormSerializer.h b/Swiften/Serializer/PayloadSerializers/FormSerializer.h index d10f649..f0f365c 100644 --- a/Swiften/Serializer/PayloadSerializers/FormSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/FormSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/Form.h> @@ -13,5 +14,5 @@ namespace Swift { - class FormSerializer : public GenericPayloadSerializer<Form> { + class SWIFTEN_API FormSerializer : public GenericPayloadSerializer<Form> { public: FormSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.cpp new file mode 100644 index 0000000..767d9de --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/GenericStanzaSerializer.h> +#include <Swiften/Serializer/IQSerializer.h> +#include <Swiften/Serializer/MessageSerializer.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/DelaySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PresenceSerializer.h> + + +using namespace Swift; + +ForwardedSerializer::ForwardedSerializer(PayloadSerializerCollection* serializers) : serializers_(serializers) { +} + +ForwardedSerializer::~ForwardedSerializer() { +} + +std::string ForwardedSerializer::serializePayload(boost::shared_ptr<Forwarded> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("forwarded", "urn:xmpp:forward:0"); + + if (payload->getDelay()) { + element.addNode(boost::make_shared<XMLRawTextNode>(DelaySerializer().serialize(payload->getDelay()))); + } + + if (payload->getStanza()) { /* find out what type of stanza we are dealing with and branch into the correct serializer*/ + boost::shared_ptr<IQ> iq; + boost::shared_ptr<Message> message; + boost::shared_ptr<Presence> presence; + const std::string ns = "jabber:client"; + if ((iq = boost::dynamic_pointer_cast<IQ>(payload->getStanza()))) { + element.addNode(boost::make_shared<XMLRawTextNode>(safeByteArrayToString(IQSerializer(serializers_).serialize(iq, ns)))); + } else if ((message = boost::dynamic_pointer_cast<Message>(payload->getStanza()))) { + element.addNode(boost::make_shared<XMLRawTextNode>(safeByteArrayToString(MessageSerializer(serializers_).serialize(message, ns)))); + } else if ((presence = boost::dynamic_pointer_cast<Presence>(payload->getStanza()))) { + element.addNode(boost::make_shared<XMLRawTextNode>(safeByteArrayToString(PresenceSerializer(serializers_).serialize(presence, ns)))); + } + } + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h new file mode 100644 index 0000000..4b283e2 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API ForwardedSerializer : public GenericPayloadSerializer<Forwarded> { + public: + ForwardedSerializer(PayloadSerializerCollection* serializers); + virtual ~ForwardedSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<Forwarded>) const SWIFTEN_OVERRIDE; + + private: + PayloadSerializerCollection* serializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 499a185..dcfb4ed 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,46 +11,22 @@ #include <Swiften/Elements/BlockListPayload.h> #include <Swiften/Serializer/PayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/IBBSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/BodySerializer.h> #include <Swiften/Serializer/PayloadSerializers/BlockSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/SubjectSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/BodySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h> #include <Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/PrioritySerializer.h> -#include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/RosterSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/StatusSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/CommandSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/DelaySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/DeliveryReceiptSerializer.h> #include <Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h> #include <Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/VCardSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/StorageSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/DelaySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> #include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/CommandSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/IBBSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/IdleSerializer.h> #include <Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/NicknameSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/LastSerializer.h> - -#include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h> @@ -58,9 +34,46 @@ #include <Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/LastSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/NicknameSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PrioritySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/RosterSerializer.h> #include <Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/DeliveryReceiptSerializer.h> -#include <Swiften/Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StatusSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StorageSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SubjectSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/VCardSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h> namespace Swift { @@ -72,5 +85,5 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new ChatStateSerializer()); serializers_.push_back(new PrioritySerializer()); - serializers_.push_back(new ErrorSerializer()); + serializers_.push_back(new ErrorSerializer(this)); serializers_.push_back(new RosterSerializer()); serializers_.push_back(new RosterItemExchangeSerializer()); @@ -109,4 +122,8 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new ReplaceSerializer()); serializers_.push_back(new LastSerializer()); + serializers_.push_back(new WhiteboardSerializer()); + serializers_.push_back(new UserLocationSerializer(this)); + serializers_.push_back(new UserTuneSerializer(this)); + serializers_.push_back(new IdleSerializer()); serializers_.push_back(new StreamInitiationFileInfoSerializer()); @@ -122,4 +139,16 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new DeliveryReceiptRequestSerializer()); + serializers_.push_back(new PubSubSerializer(this)); + serializers_.push_back(new PubSubEventSerializer(this)); + serializers_.push_back(new PubSubOwnerPubSubSerializer(this)); + serializers_.push_back(new PubSubErrorSerializer()); + + serializers_.push_back(new ResultSetSerializer()); + serializers_.push_back(new ForwardedSerializer(this)); + serializers_.push_back(new MAMResultSerializer(this)); + serializers_.push_back(new MAMQuerySerializer()); + serializers_.push_back(new MAMArchivedSerializer()); + serializers_.push_back(new IsodeIQDelegationSerializer(this)); + foreach(PayloadSerializer* serializer, serializers_) { addSerializer(serializer); diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h index bfe7d76..eaae742 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h @@ -9,8 +9,9 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Serializer/PayloadSerializerCollection.h> namespace Swift { - class FullPayloadSerializerCollection : public PayloadSerializerCollection { + class SWIFTEN_API FullPayloadSerializerCollection : public PayloadSerializerCollection { public: FullPayloadSerializerCollection(); diff --git a/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp b/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp index e78cdb4..c83b293 100644 --- a/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp @@ -9,4 +9,5 @@ #include <boost/shared_ptr.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <cassert> #include <boost/lexical_cast.hpp> @@ -49,4 +50,5 @@ std::string IBBSerializer::serializePayload(boost::shared_ptr<IBB> ibb) const { } } + assert(false); return ""; } diff --git a/Swiften/Serializer/PayloadSerializers/IdleSerializer.h b/Swiften/Serializer/PayloadSerializers/IdleSerializer.h new file mode 100644 index 0000000..45f9da4 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/IdleSerializer.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Idle.h> +#include <Swiften/Base/DateTime.h> + +namespace Swift { + class IdleSerializer : public GenericPayloadSerializer<Idle> { + public: + IdleSerializer() : GenericPayloadSerializer<Idle>() {} + + virtual std::string serializePayload(boost::shared_ptr<Idle> idle) const { + return "<idle xmlns='urn:xmpp:idle:1' since='" + dateTimeToString(idle->getSince()) + "'/>"; + } + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h index 3b88590..e71671c 100644 --- a/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h @@ -8,9 +8,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/InBandRegistrationPayload.h> namespace Swift { - class InBandRegistrationPayloadSerializer : public GenericPayloadSerializer<InBandRegistrationPayload> { + class SWIFTEN_API InBandRegistrationPayloadSerializer : public GenericPayloadSerializer<InBandRegistrationPayload> { public: InBandRegistrationPayloadSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.cpp new file mode 100644 index 0000000..8e782b4 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 Remko Tronçon and Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +IsodeIQDelegationSerializer::IsodeIQDelegationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +IsodeIQDelegationSerializer::~IsodeIQDelegationSerializer() { +} + +std::string IsodeIQDelegationSerializer::serializePayload(boost::shared_ptr<IsodeIQDelegation> payload) const { + if (!payload) { + return ""; + } + XMLElement element("delegate", "http://isode.com/iq_delegation"); + element.addNode(boost::make_shared<XMLRawTextNode>(serializers->getPayloadSerializer(payload->getForward())->serialize(payload->getForward()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.h b/Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.h new file mode 100644 index 0000000..1bcd993 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/IsodeIQDelegationSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 Remko Tronçon and Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/IsodeIQDelegation.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API IsodeIQDelegationSerializer : public GenericPayloadSerializer<IsodeIQDelegation> { + public: + IsodeIQDelegationSerializer(PayloadSerializerCollection* serializers); + virtual ~IsodeIQDelegationSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<IsodeIQDelegation>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp index 90bd940..6ba264a 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp @@ -5,4 +5,10 @@ */ +/* +* Copyright (c) 2014 Kevin Smith +* Licensed under the GNU General Public License v3. +* See Documentation/Licenses/GPLv3.txt for more information. +*/ + #include <Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h> @@ -11,4 +17,5 @@ #include <boost/smart_ptr/intrusive_ptr.hpp> +#include <Swiften/Base/Log.h> #include <Swiften/Base/foreach.h> #include <Swiften/Serializer/XML/XMLNode.h> @@ -21,6 +28,4 @@ #include <Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h> -#include "Swiften/FileTransfer/JingleTransport.h" - namespace Swift { @@ -72,8 +77,9 @@ std::string JingleContentPayloadSerializer::creatorToString(JingleContentPayload return "responder"; case JingleContentPayload::UnknownCreator: - std::cerr << "Serializing unknown creator value." << std::endl; + SWIFT_LOG(error) << "Serializing unknown creator value."; return "ERROR ERROR ERROR"; } assert(false); + return ""; } } diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h index 5131435..da8fa55 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h @@ -8,14 +8,13 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/JingleFileTransferDescription.h> - - namespace Swift { class PayloadSerializerCollection; class XMLElement; - class JingleFileTransferDescriptionSerializer : public GenericPayloadSerializer<JingleFileTransferDescription> { + class SWIFTEN_API JingleFileTransferDescriptionSerializer : public GenericPayloadSerializer<JingleFileTransferDescription> { public: JingleFileTransferDescriptionSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp index 029a5b4..61e093f 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp @@ -23,5 +23,7 @@ JingleIBBTransportPayloadSerializer::JingleIBBTransportPayloadSerializer() { std::string JingleIBBTransportPayloadSerializer::serializePayload(boost::shared_ptr<JingleIBBTransportPayload> payload) const { XMLElement payloadXML("transport", "urn:xmpp:jingle:transports:ibb:1"); - payloadXML.setAttribute("block-size", boost::lexical_cast<std::string>(payload->getBlockSize())); + if (payload->getBlockSize()) { + payloadXML.setAttribute("block-size", boost::lexical_cast<std::string>(*payload->getBlockSize())); + } payloadXML.setAttribute("sid", payload->getSessionID()); diff --git a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp index a04687b..2e8ae4a 100644 --- a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp @@ -12,4 +12,5 @@ #include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> #include <Swiften/Serializer/XML/XMLNode.h> #include <Swiften/Serializer/XML/XMLElement.h> @@ -94,5 +95,5 @@ std::string JinglePayloadSerializer::actionToString(JinglePayload::Action action return "transport-replace"; case JinglePayload::UnknownAction: - std::cerr << "Serializing unknown action value." << std::endl; + SWIFT_LOG(warning) << "Serializing unknown action value." << std::endl; return ""; } @@ -104,5 +105,5 @@ std::string JinglePayloadSerializer::reasonTypeToString(JinglePayload::Reason::T switch(type) { case JinglePayload::Reason::UnknownType: - std::cerr << "Unknown jingle reason type!" << std::endl; + SWIFT_LOG(warning) << "Unknown jingle reason type!" << std::endl; return ""; case JinglePayload::Reason::AlternativeSession: diff --git a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h index ccdb6d0..5ac266f 100644 --- a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h @@ -8,4 +8,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/JinglePayload.h> @@ -15,5 +16,5 @@ namespace Swift { class XMLElement; - class JinglePayloadSerializer : public GenericPayloadSerializer<JinglePayload> { + class SWIFTEN_API JinglePayloadSerializer : public GenericPayloadSerializer<JinglePayload> { public: JinglePayloadSerializer(PayloadSerializerCollection*); diff --git a/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.cpp new file mode 100644 index 0000000..0a49a4b --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h> + +using namespace Swift; + +MAMArchivedSerializer::MAMArchivedSerializer() { +} + +MAMArchivedSerializer::~MAMArchivedSerializer() { +} + +std::string MAMArchivedSerializer::serializePayload(boost::shared_ptr<MAMArchived> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("archived", "urn:xmpp:mam:0"); + element.setAttribute("by", payload->getBy()); + element.setAttribute("id", payload->getID()); + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h new file mode 100644 index 0000000..67fffcb --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMArchived.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API MAMArchivedSerializer : public GenericPayloadSerializer<MAMArchived> { + public: + MAMArchivedSerializer(); + virtual ~MAMArchivedSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<MAMArchived>) const SWIFTEN_OVERRIDE; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.cpp b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.cpp new file mode 100644 index 0000000..6a12f8e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> + +using namespace Swift; + +MAMQuerySerializer::MAMQuerySerializer() { +} + +MAMQuerySerializer::~MAMQuerySerializer() { +} + +std::string MAMQuerySerializer::serializePayload(boost::shared_ptr<MAMQuery> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("query", "urn:xmpp:mam:0"); + + if (payload->getQueryID()) { + element.setAttribute("queryid", *payload->getQueryID()); + } + + if (payload->getForm()) { + element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getForm()))); + } + + if (payload->getResultSet()) { + element.addNode(boost::make_shared<XMLRawTextNode>(ResultSetSerializer().serialize(payload->getResultSet()))); + } + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h new file mode 100644 index 0000000..11526a8 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMQuery.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API MAMQuerySerializer : public GenericPayloadSerializer<MAMQuery> { + public: + MAMQuerySerializer(); + virtual ~MAMQuerySerializer(); + + virtual std::string serializePayload(boost::shared_ptr<MAMQuery>) const SWIFTEN_OVERRIDE; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.cpp new file mode 100644 index 0000000..c4fd4a5 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h> + +using namespace Swift; + +MAMResultSerializer::MAMResultSerializer(PayloadSerializerCollection* serializers) : serializers_(serializers) { +} + +MAMResultSerializer::~MAMResultSerializer() { +} + +std::string MAMResultSerializer::serializePayload(boost::shared_ptr<MAMResult> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("result", "urn:xmpp:mam:0"); + + element.setAttribute("id", payload->getID()); + + if (payload->getQueryID()) { + element.setAttribute("queryid", *payload->getQueryID()); + } + + element.addNode(boost::make_shared<XMLRawTextNode>(ForwardedSerializer(serializers_).serialize(payload->getPayload()))); + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h new file mode 100644 index 0000000..bb0c326 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API MAMResultSerializer : public GenericPayloadSerializer<MAMResult> { + public: + MAMResultSerializer(PayloadSerializerCollection* serializers); + virtual ~MAMResultSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<MAMResult>) const SWIFTEN_OVERRIDE; + + private: + PayloadSerializerCollection* serializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h index e288cd7..a033a9c 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/MUCAdminPayload.h> namespace Swift { - class MUCAdminPayloadSerializer : public GenericPayloadSerializer<MUCAdminPayload> { + class SWIFTEN_API MUCAdminPayloadSerializer : public GenericPayloadSerializer<MUCAdminPayload> { public: MUCAdminPayloadSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.cpp index 24e30e6..26df08c 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.cpp @@ -38,4 +38,7 @@ std::string MUCInvitationPayloadSerializer::serializePayload(boost::shared_ptr<M mucElement.setAttribute("thread", payload->getThread()); } + if (payload->getIsImpromptu()) { + mucElement.addNode(boost::make_shared<XMLElement>("impromptu", "http://swift.im/impromptu")); + } return mucElement.serialize(); } diff --git a/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h index 2b5ffcc..2f2623f 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h @@ -24,5 +24,4 @@ namespace Swift { case MUCOccupant::Outcast: result = "outcast"; break; case MUCOccupant::NoAffiliation: result = "none"; break; - default: assert(false); } return result; @@ -36,5 +35,4 @@ namespace Swift { case MUCOccupant::Participant: result = "participant"; break; case MUCOccupant::Visitor: result = "visitor"; break; - default: assert(false); } return result; diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.cpp new file mode 100644 index 0000000..798697e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubAffiliationSerializer::PubSubAffiliationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubAffiliationSerializer::~PubSubAffiliationSerializer() { +} + +std::string PubSubAffiliationSerializer::serializePayload(boost::shared_ptr<PubSubAffiliation> payload) const { + if (!payload) { + return ""; + } + XMLElement element("affiliation", "http://jabber.org/protocol/pubsub"); + element.setAttribute("node", payload->getNode()); + element.setAttribute("affiliation", serializeType(payload->getType())); + return element.serialize(); +} + +std::string PubSubAffiliationSerializer::serializeType(PubSubAffiliation::Type value) { + switch (value) { + case PubSubAffiliation::None: return "none"; + case PubSubAffiliation::Member: return "member"; + case PubSubAffiliation::Outcast: return "outcast"; + case PubSubAffiliation::Owner: return "owner"; + case PubSubAffiliation::Publisher: return "publisher"; + case PubSubAffiliation::PublishOnly: return "publish-only"; + } + assert(false); + return ""; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h new file mode 100644 index 0000000..72bbbd7 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubAffiliation.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubAffiliationSerializer : public GenericPayloadSerializer<PubSubAffiliation> { + public: + PubSubAffiliationSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubAffiliationSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubAffiliation>) const SWIFTEN_OVERRIDE; + + private: + static std::string serializeType(PubSubAffiliation::Type); + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.cpp new file mode 100644 index 0000000..3b8cffc --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubAffiliationsSerializer::PubSubAffiliationsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubAffiliationsSerializer::~PubSubAffiliationsSerializer() { +} + +std::string PubSubAffiliationsSerializer::serializePayload(boost::shared_ptr<PubSubAffiliations> payload) const { + if (!payload) { + return ""; + } + XMLElement element("affiliations", "http://jabber.org/protocol/pubsub"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + foreach(boost::shared_ptr<PubSubAffiliation> item, payload->getAffiliations()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubAffiliationSerializer(serializers).serialize(item))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h new file mode 100644 index 0000000..5f97d0c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubAffiliations.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubAffiliationsSerializer : public GenericPayloadSerializer<PubSubAffiliations> { + public: + PubSubAffiliationsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubAffiliationsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubAffiliations>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.cpp new file mode 100644 index 0000000..6109990 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubConfigureSerializer::PubSubConfigureSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubConfigureSerializer::~PubSubConfigureSerializer() { +} + +std::string PubSubConfigureSerializer::serializePayload(boost::shared_ptr<PubSubConfigure> payload) const { + if (!payload) { + return ""; + } + XMLElement element("configure", "http://jabber.org/protocol/pubsub"); + element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h new file mode 100644 index 0000000..baf17c0 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubConfigure.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubConfigureSerializer : public GenericPayloadSerializer<PubSubConfigure> { + public: + PubSubConfigureSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubConfigureSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubConfigure>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.cpp new file mode 100644 index 0000000..481209c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubCreateSerializer::PubSubCreateSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubCreateSerializer::~PubSubCreateSerializer() { +} + +std::string PubSubCreateSerializer::serializePayload(boost::shared_ptr<PubSubCreate> payload) const { + if (!payload) { + return ""; + } + XMLElement element("create", "http://jabber.org/protocol/pubsub"); + element.setAttribute("node", payload->getNode()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h new file mode 100644 index 0000000..f43e65a --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubCreate.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubCreateSerializer : public GenericPayloadSerializer<PubSubCreate> { + public: + PubSubCreateSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubCreateSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubCreate>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.cpp new file mode 100644 index 0000000..bcb4b69 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubDefaultSerializer::PubSubDefaultSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubDefaultSerializer::~PubSubDefaultSerializer() { +} + +std::string PubSubDefaultSerializer::serializePayload(boost::shared_ptr<PubSubDefault> payload) const { + if (!payload) { + return ""; + } + XMLElement element("default", "http://jabber.org/protocol/pubsub"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + element.setAttribute("type", serializeType(payload->getType())); + return element.serialize(); +} + +std::string PubSubDefaultSerializer::serializeType(PubSubDefault::Type value) { + switch (value) { + case PubSubDefault::None: return "none"; + case PubSubDefault::Collection: return "collection"; + case PubSubDefault::Leaf: return "leaf"; + } + assert(false); + return ""; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h new file mode 100644 index 0000000..18a7db1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubDefault.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubDefaultSerializer : public GenericPayloadSerializer<PubSubDefault> { + public: + PubSubDefaultSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubDefaultSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubDefault>) const SWIFTEN_OVERRIDE; + + private: + static std::string serializeType(PubSubDefault::Type); + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.cpp new file mode 100644 index 0000000..a25b71e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + +using namespace Swift; + +PubSubErrorSerializer::PubSubErrorSerializer() { +} + +PubSubErrorSerializer::~PubSubErrorSerializer() { +} + +std::string PubSubErrorSerializer::serializePayload(boost::shared_ptr<PubSubError> payload) const { + if (payload->getType() == PubSubError::UnknownType) { + return ""; + } + XMLElement element(serializeType(payload->getType()), "http://jabber.org/protocol/pubsub#errors"); + if (payload->getType() == PubSubError::Unsupported) { + if (payload->getUnsupportedFeatureType() != PubSubError::UnknownUnsupportedFeatureType) { + element.setAttribute("feature", serializeUnsupportedFeatureType(payload->getUnsupportedFeatureType())); + } + } + return element.serialize(); +} + +std::string PubSubErrorSerializer::serializeType(PubSubError::Type value) { + switch (value) { + case PubSubError::UnknownType: assert(false); return ""; + case PubSubError::ClosedNode: return "closed-node"; + case PubSubError::ConfigurationRequired: return "configuration-required"; + case PubSubError::InvalidJID: return "invalid-jid"; + case PubSubError::InvalidOptions: return "invalid-options"; + case PubSubError::InvalidPayload: return "invalid-payload"; + case PubSubError::InvalidSubscriptionID: return "invalid-subid"; + case PubSubError::ItemForbidden: return "item-forbidden"; + case PubSubError::ItemRequired: return "item-required"; + case PubSubError::JIDRequired: return "jid-required"; + case PubSubError::MaximumItemsExceeded: return "max-items-exceeded"; + case PubSubError::MaximumNodesExceeded: return "max-nodes-exceeded"; + case PubSubError::NodeIDRequired: return "nodeid-required"; + case PubSubError::NotInRosterGroup: return "not-in-roster-group"; + case PubSubError::NotSubscribed: return "not-subscribed"; + case PubSubError::PayloadTooBig: return "payload-too-big"; + case PubSubError::PayloadRequired: return "payload-required"; + case PubSubError::PendingSubscription: return "pending-subscription"; + case PubSubError::PresenceSubscriptionRequired: return "presence-subscription-required"; + case PubSubError::SubscriptionIDRequired: return "subid-required"; + case PubSubError::TooManySubscriptions: return "too-many-subscriptions"; + case PubSubError::Unsupported: return "unsupported"; + case PubSubError::UnsupportedAccessModel: return "unsupported-access-model"; + } + assert(false); + return ""; +} + +std::string PubSubErrorSerializer::serializeUnsupportedFeatureType(PubSubError::UnsupportedFeatureType value) { + switch (value) { + case PubSubError::UnknownUnsupportedFeatureType: assert(false); return ""; + case PubSubError::AccessAuthorize: return "access-authorize"; + case PubSubError::AccessOpen: return "access-open"; + case PubSubError::AccessPresence: return "access-presence"; + case PubSubError::AccessRoster: return "access-roster"; + case PubSubError::AccessWhitelist: return "access-whitelist"; + case PubSubError::AutoCreate: return "auto-create"; + case PubSubError::AutoSubscribe: return "auto-subscribe"; + case PubSubError::Collections: return "collections"; + case PubSubError::ConfigNode: return "config-node"; + case PubSubError::CreateAndConfigure: return "create-and-configure"; + case PubSubError::CreateNodes: return "create-nodes"; + case PubSubError::DeleteItems: return "delete-items"; + case PubSubError::DeleteNodes: return "delete-nodes"; + case PubSubError::FilteredNotifications: return "filtered-notifications"; + case PubSubError::GetPending: return "get-pending"; + case PubSubError::InstantNodes: return "instant-nodes"; + case PubSubError::ItemIDs: return "item-ids"; + case PubSubError::LastPublished: return "last-published"; + case PubSubError::LeasedSubscription: return "leased-subscription"; + case PubSubError::ManageSubscriptions: return "manage-subscriptions"; + case PubSubError::MemberAffiliation: return "member-affiliation"; + case PubSubError::MetaData: return "meta-data"; + case PubSubError::ModifyAffiliations: return "modify-affiliations"; + case PubSubError::MultiCollection: return "multi-collection"; + case PubSubError::MultiSubscribe: return "multi-subscribe"; + case PubSubError::OutcastAffiliation: return "outcast-affiliation"; + case PubSubError::PersistentItems: return "persistent-items"; + case PubSubError::PresenceNotifications: return "presence-notifications"; + case PubSubError::PresenceSubscribe: return "presence-subscribe"; + case PubSubError::Publish: return "publish"; + case PubSubError::PublishOptions: return "publish-options"; + case PubSubError::PublishOnlyAffiliation: return "publish-only-affiliation"; + case PubSubError::PublisherAffiliation: return "publisher-affiliation"; + case PubSubError::PurgeNodes: return "purge-nodes"; + case PubSubError::RetractItems: return "retract-items"; + case PubSubError::RetrieveAffiliations: return "retrieve-affiliations"; + case PubSubError::RetrieveDefault: return "retrieve-default"; + case PubSubError::RetrieveItems: return "retrieve-items"; + case PubSubError::RetrieveSubscriptions: return "retrieve-subscriptions"; + case PubSubError::Subscribe: return "subscribe"; + case PubSubError::SubscriptionOptions: return "subscription-options"; + case PubSubError::SubscriptionNotifications: return "subscription-notifications"; + } + assert(false); + return ""; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h new file mode 100644 index 0000000..3ee09ce --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubErrorSerializer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubError.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubErrorSerializer : public GenericPayloadSerializer<PubSubError> { + public: + PubSubErrorSerializer(); + virtual ~PubSubErrorSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubError>) const SWIFTEN_OVERRIDE; + + private: + static std::string serializeType(PubSubError::Type); + static std::string serializeUnsupportedFeatureType(PubSubError::UnsupportedFeatureType); + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.cpp new file mode 100644 index 0000000..8b3ec16 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubEventAssociateSerializer::PubSubEventAssociateSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventAssociateSerializer::~PubSubEventAssociateSerializer() { +} + +std::string PubSubEventAssociateSerializer::serializePayload(boost::shared_ptr<PubSubEventAssociate> payload) const { + if (!payload) { + return ""; + } + XMLElement element("associate", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("node", payload->getNode()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h new file mode 100644 index 0000000..df79e02 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventAssociate.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventAssociateSerializer : public GenericPayloadSerializer<PubSubEventAssociate> { + public: + PubSubEventAssociateSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventAssociateSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventAssociate>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.cpp new file mode 100644 index 0000000..9e3027a --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventAssociateSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubEventCollectionSerializer::PubSubEventCollectionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventCollectionSerializer::~PubSubEventCollectionSerializer() { +} + +std::string PubSubEventCollectionSerializer::serializePayload(boost::shared_ptr<PubSubEventCollection> payload) const { + if (!payload) { + return ""; + } + XMLElement element("collection", "http://jabber.org/protocol/pubsub#event"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventDisassociateSerializer(serializers).serialize(payload->getDisassociate()))); + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventAssociateSerializer(serializers).serialize(payload->getAssociate()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h new file mode 100644 index 0000000..e2a2dfe --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventCollection.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventCollectionSerializer : public GenericPayloadSerializer<PubSubEventCollection> { + public: + PubSubEventCollectionSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventCollectionSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventCollection>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.cpp new file mode 100644 index 0000000..e0e938c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubEventConfigurationSerializer::PubSubEventConfigurationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventConfigurationSerializer::~PubSubEventConfigurationSerializer() { +} + +std::string PubSubEventConfigurationSerializer::serializePayload(boost::shared_ptr<PubSubEventConfiguration> payload) const { + if (!payload) { + return ""; + } + XMLElement element("configuration", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("node", payload->getNode()); + element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h new file mode 100644 index 0000000..e04cba8 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventConfiguration.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventConfigurationSerializer : public GenericPayloadSerializer<PubSubEventConfiguration> { + public: + PubSubEventConfigurationSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventConfigurationSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventConfiguration>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.cpp new file mode 100644 index 0000000..eef32f8 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubEventDeleteSerializer::PubSubEventDeleteSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventDeleteSerializer::~PubSubEventDeleteSerializer() { +} + +std::string PubSubEventDeleteSerializer::serializePayload(boost::shared_ptr<PubSubEventDelete> payload) const { + if (!payload) { + return ""; + } + XMLElement element("delete", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("node", payload->getNode()); + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventRedirectSerializer(serializers).serialize(payload->getRedirects()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h new file mode 100644 index 0000000..1fc1ae7 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventDelete.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventDeleteSerializer : public GenericPayloadSerializer<PubSubEventDelete> { + public: + PubSubEventDeleteSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventDeleteSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventDelete>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.cpp new file mode 100644 index 0000000..79b13dc --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubEventDisassociateSerializer::PubSubEventDisassociateSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventDisassociateSerializer::~PubSubEventDisassociateSerializer() { +} + +std::string PubSubEventDisassociateSerializer::serializePayload(boost::shared_ptr<PubSubEventDisassociate> payload) const { + if (!payload) { + return ""; + } + XMLElement element("disassociate", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("node", payload->getNode()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h new file mode 100644 index 0000000..2ecdc51 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventDisassociateSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventDisassociate.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventDisassociateSerializer : public GenericPayloadSerializer<PubSubEventDisassociate> { + public: + PubSubEventDisassociateSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventDisassociateSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventDisassociate>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.cpp new file mode 100644 index 0000000..08a3481 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubEventItemSerializer::PubSubEventItemSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventItemSerializer::~PubSubEventItemSerializer() { +} + +std::string PubSubEventItemSerializer::serializePayload(boost::shared_ptr<PubSubEventItem> payload) const { + if (!payload) { + return ""; + } + XMLElement element("item", "http://jabber.org/protocol/pubsub#event"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + if (payload->getPublisher()) { + element.setAttribute("publisher", *payload->getPublisher()); + } + foreach(boost::shared_ptr<Payload> item, payload->getData()) { + element.addNode(boost::make_shared<XMLRawTextNode>(serializers->getPayloadSerializer(item)->serialize(item))); + } + if (payload->getID()) { + element.setAttribute("id", *payload->getID()); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h new file mode 100644 index 0000000..a71e2e9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventItem.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventItemSerializer : public GenericPayloadSerializer<PubSubEventItem> { + public: + PubSubEventItemSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventItemSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventItem>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.cpp new file mode 100644 index 0000000..8399243 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubEventItemsSerializer::PubSubEventItemsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventItemsSerializer::~PubSubEventItemsSerializer() { +} + +std::string PubSubEventItemsSerializer::serializePayload(boost::shared_ptr<PubSubEventItems> payload) const { + if (!payload) { + return ""; + } + XMLElement element("items", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("node", payload->getNode()); + foreach(boost::shared_ptr<PubSubEventItem> item, payload->getItems()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventItemSerializer(serializers).serialize(item))); + } + foreach(boost::shared_ptr<PubSubEventRetract> item, payload->getRetracts()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubEventRetractSerializer(serializers).serialize(item))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h new file mode 100644 index 0000000..ff76a6b --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventItems.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventItemsSerializer : public GenericPayloadSerializer<PubSubEventItems> { + public: + PubSubEventItemsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventItemsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventItems>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.cpp new file mode 100644 index 0000000..25a2686 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubEventPurgeSerializer::PubSubEventPurgeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventPurgeSerializer::~PubSubEventPurgeSerializer() { +} + +std::string PubSubEventPurgeSerializer::serializePayload(boost::shared_ptr<PubSubEventPurge> payload) const { + if (!payload) { + return ""; + } + XMLElement element("purge", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("node", payload->getNode()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h new file mode 100644 index 0000000..ea12a9e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventPurge.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventPurgeSerializer : public GenericPayloadSerializer<PubSubEventPurge> { + public: + PubSubEventPurgeSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventPurgeSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventPurge>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.cpp new file mode 100644 index 0000000..c408a65 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubEventRedirectSerializer::PubSubEventRedirectSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventRedirectSerializer::~PubSubEventRedirectSerializer() { +} + +std::string PubSubEventRedirectSerializer::serializePayload(boost::shared_ptr<PubSubEventRedirect> payload) const { + if (!payload) { + return ""; + } + XMLElement element("redirect", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("uri", payload->getURI()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h new file mode 100644 index 0000000..900403d --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRedirectSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventRedirect.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventRedirectSerializer : public GenericPayloadSerializer<PubSubEventRedirect> { + public: + PubSubEventRedirectSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventRedirectSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventRedirect>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.cpp new file mode 100644 index 0000000..147fcc6 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubEventRetractSerializer::PubSubEventRetractSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventRetractSerializer::~PubSubEventRetractSerializer() { +} + +std::string PubSubEventRetractSerializer::serializePayload(boost::shared_ptr<PubSubEventRetract> payload) const { + if (!payload) { + return ""; + } + XMLElement element("retract", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("id", payload->getID()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h new file mode 100644 index 0000000..1071df3 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventRetractSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventRetract.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventRetractSerializer : public GenericPayloadSerializer<PubSubEventRetract> { + public: + PubSubEventRetractSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventRetractSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventRetract>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.cpp new file mode 100644 index 0000000..da813cd --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventConfigurationSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventPurgeSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventCollectionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventDeleteSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubEventItemsSerializer.h> +#include <Swiften/Base/foreach.h> + +using namespace Swift; + +PubSubEventSerializer::PubSubEventSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { + pubsubSerializers.push_back(boost::make_shared<PubSubEventSubscriptionSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubEventPurgeSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubEventCollectionSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubEventDeleteSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubEventItemsSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubEventConfigurationSerializer>(serializers)); +} + +PubSubEventSerializer::~PubSubEventSerializer() { +} + +std::string PubSubEventSerializer::serializePayload(boost::shared_ptr<PubSubEvent> payload) const { + if (!payload) { + return ""; + } + XMLElement element("event", "http://jabber.org/protocol/pubsub#event"); + boost::shared_ptr<PubSubEventPayload> p = payload->getPayload(); + foreach(boost::shared_ptr<PayloadSerializer> serializer, pubsubSerializers) { + if (serializer->canSerialize(p)) { + element.addNode(boost::make_shared<XMLRawTextNode>(serializer->serialize(p))); + } + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h new file mode 100644 index 0000000..85b5b90 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSerializer.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEvent.h> +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventSerializer : public GenericPayloadSerializer<PubSubEvent> { + public: + PubSubEventSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEvent>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + std::vector< boost::shared_ptr<PayloadSerializer> > pubsubSerializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.cpp new file mode 100644 index 0000000..8f2b7ac --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/DateTime.h> + +using namespace Swift; + +PubSubEventSubscriptionSerializer::PubSubEventSubscriptionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubEventSubscriptionSerializer::~PubSubEventSubscriptionSerializer() { +} + +std::string PubSubEventSubscriptionSerializer::serializePayload(boost::shared_ptr<PubSubEventSubscription> payload) const { + if (!payload) { + return ""; + } + XMLElement element("subscription", "http://jabber.org/protocol/pubsub#event"); + element.setAttribute("node", payload->getNode()); + element.setAttribute("jid", payload->getJID()); + element.setAttribute("subscription", serializeSubscriptionType(payload->getSubscription())); + if (payload->getSubscriptionID()) { + element.setAttribute("subid", *payload->getSubscriptionID()); + } + element.setAttribute("expiry", dateTimeToString(payload->getExpiry())); + return element.serialize(); +} + +std::string PubSubEventSubscriptionSerializer::serializeSubscriptionType(PubSubEventSubscription::SubscriptionType value) { + switch (value) { + case PubSubEventSubscription::None: return "none"; + case PubSubEventSubscription::Pending: return "pending"; + case PubSubEventSubscription::Subscribed: return "subscribed"; + case PubSubEventSubscription::Unconfigured: return "unconfigured"; + } + assert(false); + return ""; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h new file mode 100644 index 0000000..d4b0c9b --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubEventSubscriptionSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubEventSubscription.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubEventSubscriptionSerializer : public GenericPayloadSerializer<PubSubEventSubscription> { + public: + PubSubEventSubscriptionSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubEventSubscriptionSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubEventSubscription>) const SWIFTEN_OVERRIDE; + + private: + static std::string serializeSubscriptionType(PubSubEventSubscription::SubscriptionType); + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp new file mode 100644 index 0000000..fbd4d53 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubItemSerializer::PubSubItemSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubItemSerializer::~PubSubItemSerializer() { +} + +std::string PubSubItemSerializer::serializePayload(boost::shared_ptr<PubSubItem> payload) const { + if (!payload) { + return ""; + } + XMLElement element("item", "http://jabber.org/protocol/pubsub"); + foreach(boost::shared_ptr<Payload> item, payload->getData()) { + element.addNode(boost::make_shared<XMLRawTextNode>(serializers->getPayloadSerializer(item)->serialize(item))); + } + if (!payload->getID().empty()) { + element.setAttribute("id", payload->getID()); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h new file mode 100644 index 0000000..665f6f9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubItem.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubItemSerializer : public GenericPayloadSerializer<PubSubItem> { + public: + PubSubItemSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubItemSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubItem>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp new file mode 100644 index 0000000..7c6d1f1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubItemsSerializer::PubSubItemsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubItemsSerializer::~PubSubItemsSerializer() { +} + +std::string PubSubItemsSerializer::serializePayload(boost::shared_ptr<PubSubItems> payload) const { + if (!payload) { + return ""; + } + XMLElement element("items", "http://jabber.org/protocol/pubsub"); + if (payload->getNode().empty()) { + SWIFT_LOG(warning) << "Serializing PubSubItems with empty node attribute"; + } + element.setAttribute("node", payload->getNode()); + foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubItemSerializer(serializers).serialize(item))); + } + if (payload->getMaximumItems()) { + element.setAttribute("max_items", boost::lexical_cast<std::string>(*payload->getMaximumItems())); + } + if (payload->getSubscriptionID()) { + element.setAttribute("subid", *payload->getSubscriptionID()); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h new file mode 100644 index 0000000..3386581 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubItems.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubItemsSerializer : public GenericPayloadSerializer<PubSubItems> { + public: + PubSubItemsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubItemsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubItems>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.cpp new file mode 100644 index 0000000..120ce1c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubOptionsSerializer::PubSubOptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOptionsSerializer::~PubSubOptionsSerializer() { +} + +std::string PubSubOptionsSerializer::serializePayload(boost::shared_ptr<PubSubOptions> payload) const { + if (!payload) { + return ""; + } + XMLElement element("options", "http://jabber.org/protocol/pubsub"); + element.setAttribute("node", payload->getNode()); + element.setAttribute("jid", payload->getJID()); + element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData()))); + if (payload->getSubscriptionID()) { + element.setAttribute("subid", *payload->getSubscriptionID()); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h new file mode 100644 index 0000000..ef909e9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOptions.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOptionsSerializer : public GenericPayloadSerializer<PubSubOptions> { + public: + PubSubOptionsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOptionsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOptions>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.cpp new file mode 100644 index 0000000..1412959 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubOwnerAffiliationSerializer::PubSubOwnerAffiliationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerAffiliationSerializer::~PubSubOwnerAffiliationSerializer() { +} + +std::string PubSubOwnerAffiliationSerializer::serializePayload(boost::shared_ptr<PubSubOwnerAffiliation> payload) const { + if (!payload) { + return ""; + } + XMLElement element("affiliation", "http://jabber.org/protocol/pubsub#owner"); + element.setAttribute("jid", payload->getJID()); + element.setAttribute("affiliation", serializeType(payload->getType())); + return element.serialize(); +} + +std::string PubSubOwnerAffiliationSerializer::serializeType(PubSubOwnerAffiliation::Type value) { + switch (value) { + case PubSubOwnerAffiliation::None: return "none"; + case PubSubOwnerAffiliation::Member: return "member"; + case PubSubOwnerAffiliation::Outcast: return "outcast"; + case PubSubOwnerAffiliation::Owner: return "owner"; + case PubSubOwnerAffiliation::Publisher: return "publisher"; + case PubSubOwnerAffiliation::PublishOnly: return "publish-only"; + } + assert(false); + return ""; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h new file mode 100644 index 0000000..8509a1e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerAffiliation.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerAffiliationSerializer : public GenericPayloadSerializer<PubSubOwnerAffiliation> { + public: + PubSubOwnerAffiliationSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerAffiliationSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerAffiliation>) const SWIFTEN_OVERRIDE; + + private: + static std::string serializeType(PubSubOwnerAffiliation::Type); + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.cpp new file mode 100644 index 0000000..0f03a34 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubOwnerAffiliationsSerializer::PubSubOwnerAffiliationsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerAffiliationsSerializer::~PubSubOwnerAffiliationsSerializer() { +} + +std::string PubSubOwnerAffiliationsSerializer::serializePayload(boost::shared_ptr<PubSubOwnerAffiliations> payload) const { + if (!payload) { + return ""; + } + XMLElement element("affiliations", "http://jabber.org/protocol/pubsub#owner"); + element.setAttribute("node", payload->getNode()); + foreach(boost::shared_ptr<PubSubOwnerAffiliation> item, payload->getAffiliations()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubOwnerAffiliationSerializer(serializers).serialize(item))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h new file mode 100644 index 0000000..d7cf19e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerAffiliations.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerAffiliationsSerializer : public GenericPayloadSerializer<PubSubOwnerAffiliations> { + public: + PubSubOwnerAffiliationsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerAffiliationsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerAffiliations>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.cpp new file mode 100644 index 0000000..836de35 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubOwnerConfigureSerializer::PubSubOwnerConfigureSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerConfigureSerializer::~PubSubOwnerConfigureSerializer() { +} + +std::string PubSubOwnerConfigureSerializer::serializePayload(boost::shared_ptr<PubSubOwnerConfigure> payload) const { + if (!payload) { + return ""; + } + XMLElement element("configure", "http://jabber.org/protocol/pubsub#owner"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h new file mode 100644 index 0000000..728a723 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerConfigure.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerConfigureSerializer : public GenericPayloadSerializer<PubSubOwnerConfigure> { + public: + PubSubOwnerConfigureSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerConfigureSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerConfigure>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.cpp new file mode 100644 index 0000000..49ec7e1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubOwnerDefaultSerializer::PubSubOwnerDefaultSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerDefaultSerializer::~PubSubOwnerDefaultSerializer() { +} + +std::string PubSubOwnerDefaultSerializer::serializePayload(boost::shared_ptr<PubSubOwnerDefault> payload) const { + if (!payload) { + return ""; + } + XMLElement element("default", "http://jabber.org/protocol/pubsub#owner"); + element.addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(payload->getData()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h new file mode 100644 index 0000000..cd87d07 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerDefault.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerDefaultSerializer : public GenericPayloadSerializer<PubSubOwnerDefault> { + public: + PubSubOwnerDefaultSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerDefaultSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerDefault>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.cpp new file mode 100644 index 0000000..045cdb1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubOwnerDeleteSerializer::PubSubOwnerDeleteSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerDeleteSerializer::~PubSubOwnerDeleteSerializer() { +} + +std::string PubSubOwnerDeleteSerializer::serializePayload(boost::shared_ptr<PubSubOwnerDelete> payload) const { + if (!payload) { + return ""; + } + XMLElement element("delete", "http://jabber.org/protocol/pubsub#owner"); + element.setAttribute("node", payload->getNode()); + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubOwnerRedirectSerializer(serializers).serialize(payload->getRedirect()))); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h new file mode 100644 index 0000000..9e2edae --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerDelete.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerDeleteSerializer : public GenericPayloadSerializer<PubSubOwnerDelete> { + public: + PubSubOwnerDeleteSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerDeleteSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerDelete>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.cpp new file mode 100644 index 0000000..de7d5a5 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDeleteSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerDefaultSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerAffiliationsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerConfigureSerializer.h> +#include <Swiften/Base/foreach.h> + +using namespace Swift; + +PubSubOwnerPubSubSerializer::PubSubOwnerPubSubSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { + pubsubSerializers.push_back(boost::make_shared<PubSubOwnerConfigureSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubOwnerSubscriptionsSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubOwnerDefaultSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubOwnerPurgeSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubOwnerAffiliationsSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubOwnerDeleteSerializer>(serializers)); +} + +PubSubOwnerPubSubSerializer::~PubSubOwnerPubSubSerializer() { +} + +std::string PubSubOwnerPubSubSerializer::serializePayload(boost::shared_ptr<PubSubOwnerPubSub> payload) const { + if (!payload) { + return ""; + } + XMLElement element("pubsub", "http://jabber.org/protocol/pubsub#owner"); + boost::shared_ptr<PubSubOwnerPayload> p = payload->getPayload(); + foreach(boost::shared_ptr<PayloadSerializer> serializer, pubsubSerializers) { + if (serializer->canSerialize(p)) { + element.addNode(boost::make_shared<XMLRawTextNode>(serializer->serialize(p))); + } + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h new file mode 100644 index 0000000..9f5732b --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerPubSub.h> +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerPubSubSerializer : public GenericPayloadSerializer<PubSubOwnerPubSub> { + public: + PubSubOwnerPubSubSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerPubSubSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerPubSub>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + std::vector< boost::shared_ptr<PayloadSerializer> > pubsubSerializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.cpp new file mode 100644 index 0000000..6ca86d8 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubOwnerPurgeSerializer::PubSubOwnerPurgeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerPurgeSerializer::~PubSubOwnerPurgeSerializer() { +} + +std::string PubSubOwnerPurgeSerializer::serializePayload(boost::shared_ptr<PubSubOwnerPurge> payload) const { + if (!payload) { + return ""; + } + XMLElement element("purge", "http://jabber.org/protocol/pubsub#owner"); + element.setAttribute("node", payload->getNode()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h new file mode 100644 index 0000000..6af2b00 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerPurgeSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerPurge.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerPurgeSerializer : public GenericPayloadSerializer<PubSubOwnerPurge> { + public: + PubSubOwnerPurgeSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerPurgeSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerPurge>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.cpp new file mode 100644 index 0000000..b739600 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubOwnerRedirectSerializer::PubSubOwnerRedirectSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerRedirectSerializer::~PubSubOwnerRedirectSerializer() { +} + +std::string PubSubOwnerRedirectSerializer::serializePayload(boost::shared_ptr<PubSubOwnerRedirect> payload) const { + if (!payload) { + return ""; + } + XMLElement element("redirect", "http://jabber.org/protocol/pubsub#owner"); + element.setAttribute("uri", payload->getURI()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h new file mode 100644 index 0000000..3d85b67 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerRedirectSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerRedirect.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerRedirectSerializer : public GenericPayloadSerializer<PubSubOwnerRedirect> { + public: + PubSubOwnerRedirectSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerRedirectSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerRedirect>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.cpp new file mode 100644 index 0000000..3faeaa4 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubOwnerSubscriptionSerializer::PubSubOwnerSubscriptionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerSubscriptionSerializer::~PubSubOwnerSubscriptionSerializer() { +} + +std::string PubSubOwnerSubscriptionSerializer::serializePayload(boost::shared_ptr<PubSubOwnerSubscription> payload) const { + if (!payload) { + return ""; + } + XMLElement element("subscription", "http://jabber.org/protocol/pubsub#owner"); + element.setAttribute("jid", payload->getJID()); + element.setAttribute("subscription", serializeSubscriptionType(payload->getSubscription())); + return element.serialize(); +} + +std::string PubSubOwnerSubscriptionSerializer::serializeSubscriptionType(PubSubOwnerSubscription::SubscriptionType value) { + switch (value) { + case PubSubOwnerSubscription::None: return "none"; + case PubSubOwnerSubscription::Pending: return "pending"; + case PubSubOwnerSubscription::Subscribed: return "subscribed"; + case PubSubOwnerSubscription::Unconfigured: return "unconfigured"; + } + assert(false); + return ""; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h new file mode 100644 index 0000000..9c133d2 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerSubscription.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerSubscriptionSerializer : public GenericPayloadSerializer<PubSubOwnerSubscription> { + public: + PubSubOwnerSubscriptionSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerSubscriptionSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerSubscription>) const SWIFTEN_OVERRIDE; + + private: + static std::string serializeSubscriptionType(PubSubOwnerSubscription::SubscriptionType); + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.cpp new file mode 100644 index 0000000..9f72298 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubOwnerSubscriptionsSerializer::PubSubOwnerSubscriptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubOwnerSubscriptionsSerializer::~PubSubOwnerSubscriptionsSerializer() { +} + +std::string PubSubOwnerSubscriptionsSerializer::serializePayload(boost::shared_ptr<PubSubOwnerSubscriptions> payload) const { + if (!payload) { + return ""; + } + XMLElement element("subscriptions", "http://jabber.org/protocol/pubsub#owner"); + element.setAttribute("node", payload->getNode()); + foreach(boost::shared_ptr<PubSubOwnerSubscription> item, payload->getSubscriptions()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubOwnerSubscriptionSerializer(serializers).serialize(item))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h new file mode 100644 index 0000000..c5dfbca --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubOwnerSubscriptionsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubOwnerSubscriptions.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubOwnerSubscriptionsSerializer : public GenericPayloadSerializer<PubSubOwnerSubscriptions> { + public: + PubSubOwnerSubscriptionsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubOwnerSubscriptionsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubOwnerSubscriptions>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.cpp new file mode 100644 index 0000000..a62f397 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubPublishSerializer::PubSubPublishSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubPublishSerializer::~PubSubPublishSerializer() { +} + +std::string PubSubPublishSerializer::serializePayload(boost::shared_ptr<PubSubPublish> payload) const { + if (!payload) { + return ""; + } + XMLElement element("publish", "http://jabber.org/protocol/pubsub"); + element.setAttribute("node", payload->getNode()); + foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubItemSerializer(serializers).serialize(item))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h new file mode 100644 index 0000000..dabbc8a --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubPublish.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubPublishSerializer : public GenericPayloadSerializer<PubSubPublish> { + public: + PubSubPublishSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubPublishSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubPublish>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.cpp new file mode 100644 index 0000000..35ff169 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubRetractSerializer::PubSubRetractSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubRetractSerializer::~PubSubRetractSerializer() { +} + +std::string PubSubRetractSerializer::serializePayload(boost::shared_ptr<PubSubRetract> payload) const { + if (!payload) { + return ""; + } + XMLElement element("retract", "http://jabber.org/protocol/pubsub"); + element.setAttribute("node", payload->getNode()); + foreach(boost::shared_ptr<PubSubItem> item, payload->getItems()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubItemSerializer(serializers).serialize(item))); + } + element.setAttribute("notify", payload->isNotify() ? "true" : "false"); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h new file mode 100644 index 0000000..c2ae961 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubRetract.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubRetractSerializer : public GenericPayloadSerializer<PubSubRetract> { + public: + PubSubRetractSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubRetractSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubRetract>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.cpp new file mode 100644 index 0000000..0e61331 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubConfigureSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubAffiliationsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubCreateSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubDefaultSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubPublishSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubRetractSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubOptionsSerializer.h> +#include <Swiften/Base/foreach.h> + +using namespace Swift; + +PubSubSerializer::PubSubSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { + pubsubSerializers.push_back(boost::make_shared<PubSubItemsSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubCreateSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubPublishSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubOptionsSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubAffiliationsSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubRetractSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubDefaultSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubSubscriptionsSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubSubscribeSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubUnsubscribeSerializer>(serializers)); + pubsubSerializers.push_back(boost::make_shared<PubSubSubscriptionSerializer>(serializers)); +} + +PubSubSerializer::~PubSubSerializer() { +} + +std::string PubSubSerializer::serializePayload(boost::shared_ptr<PubSub> payload) const { + if (!payload) { + return ""; + } + XMLElement element("pubsub", "http://jabber.org/protocol/pubsub"); + boost::shared_ptr<PubSubPayload> p = payload->getPayload(); + foreach(boost::shared_ptr<PayloadSerializer> serializer, pubsubSerializers) { + if (serializer->canSerialize(p)) { + element.addNode(boost::make_shared<XMLRawTextNode>(serializer->serialize(p))); + if (boost::shared_ptr<PubSubCreate> create = boost::dynamic_pointer_cast<PubSubCreate>(p)) { + element.addNode(boost::make_shared<XMLRawTextNode>(boost::make_shared<PubSubConfigureSerializer>(serializers)->serialize(create->getConfigure()))); + } + if (boost::shared_ptr<PubSubSubscribe> subscribe = boost::dynamic_pointer_cast<PubSubSubscribe>(p)) { + element.addNode(boost::make_shared<XMLRawTextNode>(boost::make_shared<PubSubConfigureSerializer>(serializers)->serialize(subscribe->getOptions()))); + } + } + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.h new file mode 100644 index 0000000..7665800 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSerializer.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSub.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubSerializer : public GenericPayloadSerializer<PubSub> { + public: + PubSubSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSub>) const SWIFTEN_OVERRIDE; + + private: + std::vector< boost::shared_ptr<PayloadSerializer> > pubsubSerializers; + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.cpp new file mode 100644 index 0000000..7898ba4 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +PubSubSubscribeOptionsSerializer::PubSubSubscribeOptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubSubscribeOptionsSerializer::~PubSubSubscribeOptionsSerializer() { +} + +std::string PubSubSubscribeOptionsSerializer::serializePayload(boost::shared_ptr<PubSubSubscribeOptions> payload) const { + if (!payload) { + return ""; + } + XMLElement element("subscribe-options", "http://jabber.org/protocol/pubsub"); + element.addNode(payload->isRequired() ? boost::make_shared<XMLElement>("required", "") : boost::shared_ptr<XMLElement>()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h new file mode 100644 index 0000000..7d6cda0 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubSubscribeOptions.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubSubscribeOptionsSerializer : public GenericPayloadSerializer<PubSubSubscribeOptions> { + public: + PubSubSubscribeOptionsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubSubscribeOptionsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubSubscribeOptions>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.cpp new file mode 100644 index 0000000..7a0e1d8 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubSubscribeSerializer::PubSubSubscribeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubSubscribeSerializer::~PubSubSubscribeSerializer() { +} + +std::string PubSubSubscribeSerializer::serializePayload(boost::shared_ptr<PubSubSubscribe> payload) const { + if (!payload) { + return ""; + } + XMLElement element("subscribe", "http://jabber.org/protocol/pubsub"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + element.setAttribute("jid", payload->getJID()); + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h new file mode 100644 index 0000000..ad684b1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscribeSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubSubscribe.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubSubscribeSerializer : public GenericPayloadSerializer<PubSubSubscribe> { + public: + PubSubSubscribeSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubSubscribeSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubSubscribe>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.cpp new file mode 100644 index 0000000..715acc9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribeOptionsSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubSubscriptionSerializer::PubSubSubscriptionSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubSubscriptionSerializer::~PubSubSubscriptionSerializer() { +} + +std::string PubSubSubscriptionSerializer::serializePayload(boost::shared_ptr<PubSubSubscription> payload) const { + if (!payload) { + return ""; + } + XMLElement element("subscription", "http://jabber.org/protocol/pubsub"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + if (payload->getSubscriptionID()) { + element.setAttribute("subid", *payload->getSubscriptionID()); + } + element.setAttribute("jid", payload->getJID()); + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubSubscribeOptionsSerializer(serializers).serialize(payload->getOptions()))); + element.setAttribute("subscription", serializeSubscriptionType(payload->getSubscription())); + return element.serialize(); +} + +std::string PubSubSubscriptionSerializer::serializeSubscriptionType(PubSubSubscription::SubscriptionType value) { + switch (value) { + case PubSubSubscription::None: return "none"; + case PubSubSubscription::Pending: return "pending"; + case PubSubSubscription::Subscribed: return "subscribed"; + case PubSubSubscription::Unconfigured: return "unconfigured"; + } + assert(false); + return ""; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h new file mode 100644 index 0000000..41372a5 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubSubscription.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubSubscriptionSerializer : public GenericPayloadSerializer<PubSubSubscription> { + public: + PubSubSubscriptionSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubSubscriptionSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubSubscription>) const SWIFTEN_OVERRIDE; + + private: + static std::string serializeSubscriptionType(PubSubSubscription::SubscriptionType); + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.cpp new file mode 100644 index 0000000..44a96cf --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionSerializer.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +using namespace Swift; + +PubSubSubscriptionsSerializer::PubSubSubscriptionsSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubSubscriptionsSerializer::~PubSubSubscriptionsSerializer() { +} + +std::string PubSubSubscriptionsSerializer::serializePayload(boost::shared_ptr<PubSubSubscriptions> payload) const { + if (!payload) { + return ""; + } + XMLElement element("subscriptions", "http://jabber.org/protocol/pubsub"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + foreach(boost::shared_ptr<PubSubSubscription> item, payload->getSubscriptions()) { + element.addNode(boost::make_shared<XMLRawTextNode>(PubSubSubscriptionSerializer(serializers).serialize(item))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h new file mode 100644 index 0000000..928e690 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionsSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubSubscriptions.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubSubscriptionsSerializer : public GenericPayloadSerializer<PubSubSubscriptions> { + public: + PubSubSubscriptionsSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubSubscriptionsSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubSubscriptions>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.cpp new file mode 100644 index 0000000..59b28c6 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + + +using namespace Swift; + +PubSubUnsubscribeSerializer::PubSubUnsubscribeSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +PubSubUnsubscribeSerializer::~PubSubUnsubscribeSerializer() { +} + +std::string PubSubUnsubscribeSerializer::serializePayload(boost::shared_ptr<PubSubUnsubscribe> payload) const { + if (!payload) { + return ""; + } + XMLElement element("unsubscribe", "http://jabber.org/protocol/pubsub"); + if (payload->getNode()) { + element.setAttribute("node", *payload->getNode()); + } + element.setAttribute("jid", payload->getJID()); + if (payload->getSubscriptionID()) { + element.setAttribute("subid", *payload->getSubscriptionID()); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h new file mode 100644 index 0000000..26617de --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/PubSubUnsubscribeSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PubSubUnsubscribe.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API PubSubUnsubscribeSerializer : public GenericPayloadSerializer<PubSubUnsubscribe> { + public: + PubSubUnsubscribeSerializer(PayloadSerializerCollection* serializers); + virtual ~PubSubUnsubscribeSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<PubSubUnsubscribe>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h b/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h index 88ad2b3..85c114c 100644 --- a/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + #pragma once @@ -17,5 +23,5 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<Replace> replace) const { - return "<replace id = '" + replace->getID() + "' xmlns='http://swift.im/protocol/replace'/>"; + return "<replace id = '" + replace->getID() + "' xmlns='urn:xmpp:message-correct:0'/>"; } }; diff --git a/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h b/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h index 133e45e..fcc8563 100644 --- a/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/ResourceBind.h> namespace Swift { - class ResourceBindSerializer : public GenericPayloadSerializer<ResourceBind> { + class SWIFTEN_API ResourceBindSerializer : public GenericPayloadSerializer<ResourceBind> { public: ResourceBindSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp new file mode 100644 index 0000000..0f464a4 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> + +using namespace Swift; + +ResultSetSerializer::ResultSetSerializer() { +} + +ResultSetSerializer::~ResultSetSerializer() { +} + +std::string ResultSetSerializer::serializePayload(boost::shared_ptr<ResultSet> payload) const { + if (!payload) { + return ""; + } + + XMLElement element("set", "http://jabber.org/protocol/rsm"); + + if (payload->getMaxItems()) { + element.addNode(boost::make_shared<XMLElement>("max", "", boost::lexical_cast<std::string>(*payload->getMaxItems()))); + } + + if (payload->getCount()) { + element.addNode(boost::make_shared<XMLElement>("count", "", boost::lexical_cast<std::string>(*payload->getCount()))); + } + + if (payload->getFirstID()) { + boost::shared_ptr<XMLElement> firstElement = boost::make_shared<XMLElement>("first", "", *payload->getFirstID()); + if (payload->getFirstIDIndex()) { + firstElement->setAttribute("index", boost::lexical_cast<std::string>(*payload->getFirstIDIndex())); + } + element.addNode(firstElement); + } + + if (payload->getLastID()) { + element.addNode(boost::make_shared<XMLElement>("last", "", *payload->getLastID())); + } + + if (payload->getBefore()) { + element.addNode(boost::make_shared<XMLElement>("before", "", *payload->getBefore())); + } + + if (payload->getAfter()) { + element.addNode(boost::make_shared<XMLElement>("after", "", *payload->getAfter())); + } + + return element.serialize(); +} diff --git a/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h new file mode 100644 index 0000000..1d476e2 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ResultSet.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API ResultSetSerializer : public GenericPayloadSerializer<ResultSet> { + public: + ResultSetSerializer(); + virtual ~ResultSetSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<ResultSet>) const SWIFTEN_OVERRIDE; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h index f246f9e..71a5b5d 100644 --- a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/RosterItemExchangePayload.h> namespace Swift { - class RosterItemExchangeSerializer : public GenericPayloadSerializer<RosterItemExchangePayload> { + class SWIFTEN_API RosterItemExchangeSerializer : public GenericPayloadSerializer<RosterItemExchangePayload> { public: RosterItemExchangeSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/RosterSerializer.h b/Swiften/Serializer/PayloadSerializers/RosterSerializer.h index 52fdb2a..9e7ea1b 100644 --- a/Swiften/Serializer/PayloadSerializers/RosterSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/RosterSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/RosterPayload.h> namespace Swift { - class RosterSerializer : public GenericPayloadSerializer<RosterPayload> { + class SWIFTEN_API RosterSerializer : public GenericPayloadSerializer<RosterPayload> { public: RosterSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h index e4dbff8..2d8e44b 100644 --- a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h @@ -8,4 +8,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/SearchPayload.h> @@ -14,5 +15,5 @@ namespace Swift { class PayloadSerializerCollection; - class SearchPayloadSerializer : public GenericPayloadSerializer<SearchPayload> { + class SWIFTEN_API SearchPayloadSerializer : public GenericPayloadSerializer<SearchPayload> { public: SearchPayloadSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h b/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h index a1915c7..4606546 100644 --- a/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/SecurityLabel.h> namespace Swift { - class SecurityLabelSerializer : public GenericPayloadSerializer<SecurityLabel> { + class SWIFTEN_API SecurityLabelSerializer : public GenericPayloadSerializer<SecurityLabel> { public: SecurityLabelSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h index 02104df..02d7c71 100644 --- a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/SecurityLabelsCatalog.h> namespace Swift { - class SecurityLabelsCatalogSerializer : public GenericPayloadSerializer<SecurityLabelsCatalog> { + class SWIFTEN_API SecurityLabelsCatalogSerializer : public GenericPayloadSerializer<SecurityLabelsCatalog> { public: SecurityLabelsCatalogSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h b/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h index 98fa243..333059d 100644 --- a/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/SoftwareVersion.h> namespace Swift { - class SoftwareVersionSerializer : public GenericPayloadSerializer<SoftwareVersion> { + class SWIFTEN_API SoftwareVersionSerializer : public GenericPayloadSerializer<SoftwareVersion> { public: SoftwareVersionSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h index 4ac0a0d..1f1e9d7 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h @@ -8,4 +8,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> @@ -16,5 +17,5 @@ namespace Swift { class PayloadSerializerCollection; - class StreamInitiationFileInfoSerializer : public GenericPayloadSerializer<StreamInitiationFileInfo> { + class SWIFTEN_API StreamInitiationFileInfoSerializer : public GenericPayloadSerializer<StreamInitiationFileInfo> { public: StreamInitiationFileInfoSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp index 030b024..973ced9 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -53,5 +53,5 @@ std::string StreamInitiationSerializer::serializePayload(boost::shared_ptr<Strea if (streamInitiation->getProvidedMethods().size() > 0) { Form::ref form(new Form(Form::FormType)); - ListSingleFormField::ref field = ListSingleFormField::create(); + FormField::ref field = boost::make_shared<FormField>(FormField::ListSingleType); field->setName("stream-method"); foreach(const std::string& method, streamInitiation->getProvidedMethods()) { @@ -63,5 +63,6 @@ std::string StreamInitiationSerializer::serializePayload(boost::shared_ptr<Strea else if (!streamInitiation->getRequestedMethod().empty()) { Form::ref form(new Form(Form::SubmitType)); - ListSingleFormField::ref field = ListSingleFormField::create(streamInitiation->getRequestedMethod()); + FormField::ref field = boost::make_shared<FormField>(FormField::ListSingleType); + field->addValue(streamInitiation->getRequestedMethod()); field->setName("stream-method"); form->addField(field); diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h index 76f0f45..63f845f 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/StreamInitiation.h> namespace Swift { - class StreamInitiationSerializer : public GenericPayloadSerializer<StreamInitiation> { + class SWIFTEN_API StreamInitiationSerializer : public GenericPayloadSerializer<StreamInitiation> { public: StreamInitiationSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp new file mode 100644 index 0000000..7772381 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/BlockSerializerTest.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Serializer/PayloadSerializers/BlockSerializer.h> +#include <Swiften/Elements/BlockListPayload.h> +#include <Swiften/Elements/BlockPayload.h> +#include <Swiften/Elements/UnblockPayload.h> +#include <Swiften/JID/JID.h> + +using namespace Swift; + +class BlockSerializerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(BlockSerializerTest); + CPPUNIT_TEST(testExample4); + CPPUNIT_TEST(testExample6); + CPPUNIT_TEST(testExample10); + CPPUNIT_TEST_SUITE_END(); + + public: + BlockSerializerTest() {} + + void testExample4() { + BlockSerializer<BlockListPayload> testling("blocklist"); + boost::shared_ptr<BlockListPayload> blocklist = boost::make_shared<BlockListPayload>(); + blocklist->addItem(JID("romeo@montague.net")); + blocklist->addItem(JID("iago@shakespeare.lit")); + + CPPUNIT_ASSERT_EQUAL(std::string("<blocklist xmlns=\"urn:xmpp:blocking\"><item jid=\"romeo@montague.net\"/><item jid=\"iago@shakespeare.lit\"/></blocklist>"), testling.serialize(blocklist)); + } + + void testExample6() { + BlockSerializer<BlockPayload> testling("block"); + boost::shared_ptr<BlockPayload> block = boost::make_shared<BlockPayload>(); + block->addItem(JID("romeo@montague.net")); + + CPPUNIT_ASSERT_EQUAL(std::string("<block xmlns=\"urn:xmpp:blocking\"><item jid=\"romeo@montague.net\"/></block>"), testling.serialize(block)); + } + + void testExample10() { + BlockSerializer<UnblockPayload> testling("unblock"); + boost::shared_ptr<UnblockPayload> unblock = boost::make_shared<UnblockPayload>(); + unblock->addItem(JID("romeo@montague.net")); + + CPPUNIT_ASSERT_EQUAL(std::string("<unblock xmlns=\"urn:xmpp:blocking\"><item jid=\"romeo@montague.net\"/></unblock>"), testling.serialize(unblock)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BlockSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp index 27d4ac5..d1408f7 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2012 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,24 +7,38 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Elements/Delay.h> using namespace Swift; -class ErrorSerializerTest : public CppUnit::TestFixture -{ +class ErrorSerializerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ErrorSerializerTest); CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST(testSerialize_Payload); CPPUNIT_TEST_SUITE_END(); public: - ErrorSerializerTest() {} - void testSerialize() { - ErrorSerializer testling; + ErrorSerializer testling(&serializers); boost::shared_ptr<ErrorPayload> error(new ErrorPayload(ErrorPayload::BadRequest, ErrorPayload::Cancel, "My Error")); CPPUNIT_ASSERT_EQUAL(std::string("<error type=\"cancel\"><bad-request xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/><text xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">My Error</text></error>"), testling.serialize(error)); } + + void testSerialize_Payload() { + ErrorSerializer testling(&serializers); + boost::shared_ptr<ErrorPayload> error = boost::make_shared<ErrorPayload>(); + error->setPayload(boost::make_shared<Delay>()); + + CPPUNIT_ASSERT_EQUAL(std::string( + "<error type=\"cancel\"><undefined-condition xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/><delay stamp=\"not-a-date-timeZ\" xmlns=\"urn:xmpp:delay\"/></error>" + ), testling.serialize(error)); + } + + private: + FullPayloadSerializerCollection serializers; }; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp index 4608522..e4ce2c8 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> @@ -37,21 +38,22 @@ class FormSerializerTest : public CppUnit::TestFixture { boost::shared_ptr<Form> form(new Form(Form::FormType)); - FormField::ref field = HiddenFormField::create("jabber:bot"); + FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:bot"); field->setName("FORM_TYPE"); form->addField(field); - form->addField(FixedFormField::create("Section 1: Bot Info")); + form->addField(boost::make_shared<FormField>(FormField::FixedType, "Section 1: Bot Info")); - field = TextSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::TextSingleType); field->setName("botname"); field->setLabel("The name of your bot"); form->addField(field); - field = TextMultiFormField::create("This is a bot.\nA quite good one actually"); + field = boost::make_shared<FormField>(FormField::TextMultiType); + field->setTextMultiValue("This is a bot.\nA quite good one actually"); field->setName("description"); field->setLabel("Helpful description of your bot"); form->addField(field); - field = BooleanFormField::create(true); + field = boost::make_shared<FormField>(FormField::BooleanType, "1"); field->setName("public"); field->setLabel("Public bot?"); @@ -59,13 +61,12 @@ class FormSerializerTest : public CppUnit::TestFixture { form->addField(field); - field = TextPrivateFormField::create(); + field = boost::make_shared<FormField>(FormField::TextPrivateType); field->setName("password"); field->setLabel("Password for special access"); form->addField(field); - std::vector<std::string> values; - values.push_back("news"); - values.push_back("search"); - field = ListMultiFormField::create(values); + field = boost::make_shared<FormField>(FormField::ListMultiType); + field->addValue("news"); + field->addValue("search"); field->setName("features"); field->setLabel("What features will the bot support?"); @@ -77,5 +78,5 @@ class FormSerializerTest : public CppUnit::TestFixture { form->addField(field); - field = ListSingleFormField::create("20"); + field = boost::make_shared<FormField>(FormField::ListSingleType, "20"); field->setName("maxsubs"); field->setLabel("Maximum number of subscribers"); @@ -89,7 +90,7 @@ class FormSerializerTest : public CppUnit::TestFixture { std::vector<JID> jids; - jids.push_back(JID("foo@bar.com")); - jids.push_back(JID("baz@fum.org")); - field = JIDMultiFormField::create(jids); + field = boost::make_shared<FormField>(FormField::JIDMultiType); + field->addValue("foo@bar.com"); + field->addValue("baz@fum.org"); field->setName("invitelist"); field->setLabel("People to invite"); @@ -141,25 +142,25 @@ class FormSerializerTest : public CppUnit::TestFixture { - FormField::ref field = HiddenFormField::create("jabber:iq:search"); + FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:iq:search"); field->setName("FORM_TYPE"); form->addField(field); // reported fields - field = TextSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::TextSingleType); field->setName("first"); field->setLabel("Given Name"); form->addReportedField(field); - field = TextSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::TextSingleType); field->setName("last"); field->setLabel("Family Name"); form->addReportedField(field); - field = JIDSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::JIDSingleType); field->setName("jid"); field->setLabel("Jabber ID"); form->addReportedField(field); - field = ListSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::ListSingleType); field->setName("x-gender"); field->setLabel("Gender"); @@ -167,34 +168,34 @@ class FormSerializerTest : public CppUnit::TestFixture { Form::FormItem firstItem; - field = TextSingleFormField::create("Benvolio"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Benvolio"); field->setName("first"); firstItem.push_back(field); - field = TextSingleFormField::create("Montague"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague"); field->setName("last"); firstItem.push_back(field); - field = JIDSingleFormField::create(JID("benvolio@montague.net")); + field = boost::make_shared<FormField>(FormField::JIDSingleType, JID("benvolio@montague.net")); field->setName("jid"); firstItem.push_back(field); - field = ListSingleFormField::create("male"); + field = boost::make_shared<FormField>(FormField::ListSingleType, "male"); field->setName("x-gender"); firstItem.push_back(field); Form::FormItem secondItem; - field = TextSingleFormField::create("Romeo"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Romeo"); field->setName("first"); secondItem.push_back(field); - field = TextSingleFormField::create("Montague"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague"); field->setName("last"); secondItem.push_back(field); - field = JIDSingleFormField::create(JID("romeo@montague.net")); + field = boost::make_shared<FormField>(FormField::JIDSingleType, JID("romeo@montague.net")); field->setName("jid"); secondItem.push_back(field); - field = ListSingleFormField::create("male"); + field = boost::make_shared<FormField>(FormField::ListSingleType, "male"); field->setName("x-gender"); secondItem.push_back(field); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp new file mode 100644 index 0000000..8af1672 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ForwardedSerializerTest.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/Forwarded.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Serializer/PayloadSerializers/ForwardedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class ForwardedSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ForwardedSerializerTest); + CPPUNIT_TEST(testSerializeIQ); + CPPUNIT_TEST(testSerializeMessage); + CPPUNIT_TEST(testSerializeMessageNoDelay); + CPPUNIT_TEST(testSerializePresence); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerializeIQ() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<IQ> iq = IQ::createResult(JID("juliet@capulet.lit/balcony"), JID("romeo@montague.lit/orchard"), "id0"); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(iq); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<iq from=\"romeo@montague.lit/orchard\" id=\"id0\" to=\"juliet@capulet.lit/balcony\" type=\"result\" xmlns=\"jabber:client\"/>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + void testSerializeMessage() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<Message> message(boost::make_shared<Message>()); + message->setType(Message::Chat); + message->setTo(JID("juliet@capulet.lit/balcony")); + message->setFrom(JID("romeo@montague.lit/orchard")); + message->setBody("Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(message); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<message from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\" xmlns=\"jabber:client\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + void testSerializeMessageNoDelay() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<Message> message(boost::make_shared<Message>()); + message->setType(Message::Chat); + message->setTo(JID("juliet@capulet.lit/balcony")); + message->setFrom(JID("romeo@montague.lit/orchard")); + message->setBody("Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(message); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<message from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\" xmlns=\"jabber:client\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + void testSerializePresence() { + ForwardedSerializer serializer(&serializers); + + boost::shared_ptr<Presence> presence(boost::make_shared<Presence>()); + presence->setType(Presence::Subscribe); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(presence); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + std::string expectedResult = + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<presence type=\"subscribe\" xmlns=\"jabber:client\"/>" + "</forwarded>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(forwarded)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ForwardedSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/IdleSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/IdleSerializerTest.cpp new file mode 100644 index 0000000..9700869 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/IdleSerializerTest.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializers/IdleSerializer.h> + +using namespace Swift; + +class IdleSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(IdleSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + IdleSerializerTest() {} + + void testSerialize() { + IdleSerializer testling; + Idle::ref idle = boost::make_shared<Idle>(stringToDateTime("1969-07-21T02:56:15Z")); + + CPPUNIT_ASSERT_EQUAL(std::string("<idle xmlns='urn:xmpp:idle:1' since='1969-07-21T02:56:15Z'/>"), testling.serialize(idle)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(IdleSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp index df43e69..7cbce35 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h> @@ -39,5 +40,5 @@ class InBandRegistrationPayloadSerializerTest : public CppUnit::TestFixture { form->setTitle("Contest Registration"); - FormField::ref field = HiddenFormField::create("jabber:iq:register"); + FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:iq:register"); field->setName("FORM_TYPE"); form->addField(field); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp new file mode 100644 index 0000000..2bd5c6a --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMArchivedSerializerTest.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Serializer/PayloadSerializers/MAMArchivedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class MAMArchivedSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(MAMArchivedSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + MAMArchivedSerializer serializer; + + boost::shared_ptr<MAMArchived> archived(boost::make_shared<MAMArchived>()); + archived->setBy("juliet@capulet.lit"); + archived->setID("28482-98726-73623"); + + std::string expectedResult = + "<archived by=\"juliet@capulet.lit\" id=\"28482-98726-73623\" xmlns=\"urn:xmpp:mam:0\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(archived)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMArchivedSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp new file mode 100644 index 0000000..7f6cbd9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMQuerySerializerTest.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Serializer/PayloadSerializers/MAMQuerySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class MAMQuerySerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(MAMQuerySerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + MAMQuerySerializer serializer; + + boost::shared_ptr<Form> parameters(boost::make_shared<Form>()); + + boost::shared_ptr<FormField> fieldType = boost::make_shared<FormField>(FormField::TextSingleType); + fieldType->setName("FORM_TYPE"); + fieldType->addValue("urn:xmpp:mam:0"); + parameters->addField(fieldType); + + boost::shared_ptr<FormField> fieldStart = boost::make_shared<FormField>(FormField::TextSingleType); + fieldStart->setName("start"); + fieldStart->addValue("2010-08-07T00:00:00Z"); + parameters->addField(fieldStart); + + boost::shared_ptr<ResultSet> set = boost::make_shared<ResultSet>(); + set->setMaxItems(10); + + boost::shared_ptr<MAMQuery> query(boost::make_shared<MAMQuery>()); + query->setQueryID(std::string("id0")); + query->setForm(parameters); + query->setResultSet(set); + + std::string expectedResult = + "<query queryid=\"id0\" xmlns=\"urn:xmpp:mam:0\">" + "<x type=\"form\" xmlns=\"jabber:x:data\">" + "<field type=\"text-single\" var=\"FORM_TYPE\">" + "<value>urn:xmpp:mam:0</value>" + "</field>" + "<field type=\"text-single\" var=\"start\">" + "<value>2010-08-07T00:00:00Z</value>" + "</field>" + "</x>" + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>10</max>" + "</set>" + "</query>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(query)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMQuerySerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp new file mode 100644 index 0000000..2060c97 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MAMResultSerializerTest.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/MAMResult.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Serializer/PayloadSerializers/MAMResultSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class MAMResultSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(MAMResultSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + MAMResultSerializer serializer(&serializers); + + boost::shared_ptr<Message> message(boost::make_shared<Message>()); + message->setType(Message::Chat); + message->setTo(JID("juliet@capulet.lit/balcony")); + message->setFrom(JID("romeo@montague.lit/orchard")); + message->setBody("Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."); + + boost::shared_ptr<Forwarded> forwarded(boost::make_shared<Forwarded>()); + forwarded->setStanza(message); + forwarded->setDelay(boost::make_shared<Delay>(stringToDateTime(std::string("2010-07-10T23:08:25Z")))); + + boost::shared_ptr<MAMResult> result(boost::make_shared<MAMResult>()); + result->setID("28482-98726-73623"); + result->setQueryID(std::string("f27")); + result->setPayload(forwarded); + + std::string expectedResult = + "<result id=\"28482-98726-73623\" queryid=\"f27\" xmlns=\"urn:xmpp:mam:0\">" + "<forwarded xmlns=\"urn:xmpp:forward:0\">" + "<delay stamp=\"2010-07-10T23:08:25Z\" xmlns=\"urn:xmpp:delay\"/>" + "<message from=\"romeo@montague.lit/orchard\" to=\"juliet@capulet.lit/balcony\" type=\"chat\" xmlns=\"jabber:client\">" + "<body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>" + "</message>" + "</forwarded>" + "</result>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(result)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MAMResultSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/PubSubItemSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/PubSubItemSerializerTest.cpp new file mode 100644 index 0000000..4ece9db --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/PubSubItemSerializerTest.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Elements/PubSubItem.h> +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class PubSubItemSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(PubSubItemSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST(testSerializeEmptyID); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + PubSubItemSerializer serializer(&serializers); + + boost::shared_ptr<RawXMLPayload> payload(boost::make_shared<RawXMLPayload>()); + payload->setRawXML("<payload xmlns=\"tmp\"/>"); + + boost::shared_ptr<PubSubItem> item(boost::make_shared<PubSubItem>()); + item->addData(payload); + item->setID("pubsub-item-1"); + + std::string expectedResult = + "<item id=\"pubsub-item-1\" xmlns=\"http://jabber.org/protocol/pubsub\">" + "<payload xmlns=\"tmp\"/>" + "</item>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(item)); + } + + void testSerializeEmptyID() { + PubSubItemSerializer serializer(&serializers); + + boost::shared_ptr<PubSubItem> item(boost::make_shared<PubSubItem>()); + + std::string expectedResult = + "<item xmlns=\"http://jabber.org/protocol/pubsub\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(item)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PubSubItemSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/PubSubItemsSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/PubSubItemsSerializerTest.cpp new file mode 100644 index 0000000..dff2bce --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/PubSubItemsSerializerTest.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Elements/PubSubItems.h> +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Serializer/PayloadSerializers/PubSubItemsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + +using namespace Swift; + +class PubSubItemsSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(PubSubItemsSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST(testSerializeEmptyItems); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerialize() { + PubSubItemsSerializer serializer(&serializers); + + boost::shared_ptr<RawXMLPayload> payload1(boost::make_shared<RawXMLPayload>()); + payload1->setRawXML("<payload xmlns=\"tmp\"/>"); + + boost::shared_ptr<PubSubItem> item1(boost::make_shared<PubSubItem>()); + item1->addData(payload1); + item1->setID("pubsub-item-1"); + + boost::shared_ptr<RawXMLPayload> payload2(boost::make_shared<RawXMLPayload>()); + payload2->setRawXML("<payload xmlns=\"other-tmp\"/>"); + + boost::shared_ptr<PubSubItem> item2(boost::make_shared<PubSubItem>()); + item2->addData(payload2); + item2->setID("pubsub-item-2"); + + boost::shared_ptr<PubSubItems> items(boost::make_shared<PubSubItems>()); + items->setNode("test-node"); + items->setSubscriptionID(std::string("sub-id")); + items->addItem(item1); + items->addItem(item2); + + std::string expectedResult = + "<items node=\"test-node\" subid=\"sub-id\" xmlns=\"http://jabber.org/protocol/pubsub\">" + "<item id=\"pubsub-item-1\" xmlns=\"http://jabber.org/protocol/pubsub\">" + "<payload xmlns=\"tmp\"/>" + "</item>" + "<item id=\"pubsub-item-2\" xmlns=\"http://jabber.org/protocol/pubsub\">" + "<payload xmlns=\"other-tmp\"/>" + "</item>" + "</items>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(items)); + } + + void testSerializeEmptyItems() { + PubSubItemsSerializer serializer(&serializers); + + boost::shared_ptr<PubSubItems> items(boost::make_shared<PubSubItems>()); + + std::string expectedResult = + "<items node=\"\" xmlns=\"http://jabber.org/protocol/pubsub\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(items)); + } + + private: + FullPayloadSerializerCollection serializers; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PubSubItemsSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp index 3d054cc..70f351c 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp @@ -5,4 +5,10 @@ */ +/* + * Copyright (c) 2012 Kevin Smith + * 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> @@ -24,5 +30,5 @@ class ReplaceSerializerTest: public CppUnit::TestFixture { boost::shared_ptr<Replace> replace(new Replace()); replace->setID("bad1"); - CPPUNIT_ASSERT_EQUAL(std::string("<replace id = 'bad1' xmlns='http://swift.im/protocol/replace'/>"), testling.serialize(replace)); + CPPUNIT_ASSERT_EQUAL(std::string("<replace id = 'bad1' xmlns='urn:xmpp:message-correct:0'/>"), testling.serialize(replace)); } }; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp new file mode 100644 index 0000000..354db85 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ResultSetSerializerTest.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Serializer/PayloadSerializers/ResultSetSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Elements/ResultSet.h> + +using namespace Swift; + +class ResultSetSerializerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ResultSetSerializerTest); + CPPUNIT_TEST(testSerializeFull); + CPPUNIT_TEST(testSerializeMaxItems); + CPPUNIT_TEST(testSerializeEmptyBefore); + CPPUNIT_TEST(testSerializeFirst); + CPPUNIT_TEST(testSerializeFirstWithIndex); + CPPUNIT_TEST_SUITE_END(); + + public: + void testSerializeFull() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setMaxItems(100); + resultSet->setCount(800); + resultSet->setFirstIDIndex(123); + resultSet->setFirstID(std::string("stpeter@jabber.org")); + resultSet->setLastID(std::string("peterpan@neverland.lit")); + resultSet->setAfter(std::string("09af3-cc343-b409f")); + resultSet->setBefore(std::string("decaf-badba-dbad1")); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>100</max>" + "<count>800</count>" + "<first index=\"123\">stpeter@jabber.org</first>" + "<last>peterpan@neverland.lit</last>" + "<before>decaf-badba-dbad1</before>" + "<after>09af3-cc343-b409f</after>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } + + void testSerializeMaxItems() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setMaxItems(100); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<max>100</max>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } + + void testSerializeEmptyBefore() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setBefore(std::string()); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<before/>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } + + void testSerializeFirst() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setFirstID(std::string("stpeter@jabber.org")); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<first>stpeter@jabber.org</first>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } + + void testSerializeFirstWithIndex() { + ResultSetSerializer serializer; + + boost::shared_ptr<ResultSet> resultSet(boost::make_shared<ResultSet>()); + + resultSet->setFirstID(std::string("stpeter@jabber.org")); + resultSet->setFirstIDIndex(123); + + std::string expectedResult = + "<set xmlns=\"http://jabber.org/protocol/rsm\">" + "<first index=\"123\">stpeter@jabber.org</first>" + "</set>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, serializer.serialize(resultSet)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ResultSetSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp index 42bff72..29e20c9 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,4 +7,5 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h> @@ -79,25 +80,25 @@ class SearchPayloadSerializerTest : public CppUnit::TestFixture { boost::shared_ptr<Form> form(new Form(Form::ResultType)); - FormField::ref field = HiddenFormField::create("jabber:iq:search"); + FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:iq:search"); field->setName("FORM_TYPE"); form->addField(field); // reported fields - field = TextSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::TextSingleType); field->setName("first"); field->setLabel("Given Name"); form->addReportedField(field); - field = TextSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::TextSingleType); field->setName("last"); field->setLabel("Family Name"); form->addReportedField(field); - field = JIDSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::JIDSingleType); field->setName("jid"); field->setLabel("Jabber ID"); form->addReportedField(field); - field = ListSingleFormField::create(); + field = boost::make_shared<FormField>(FormField::ListSingleType); field->setName("x-gender"); field->setLabel("Gender"); @@ -105,34 +106,34 @@ class SearchPayloadSerializerTest : public CppUnit::TestFixture { Form::FormItem firstItem; - field = TextSingleFormField::create("Benvolio"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Benvolio"); field->setName("first"); firstItem.push_back(field); - field = TextSingleFormField::create("Montague"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague"); field->setName("last"); firstItem.push_back(field); - field = TextSingleFormField::create("benvolio@montague.net"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "benvolio@montague.net"); field->setName("jid"); firstItem.push_back(field); - field = ListSingleFormField::create("male"); + field = boost::make_shared<FormField>(FormField::ListSingleType, "male"); field->setName("x-gender"); firstItem.push_back(field); Form::FormItem secondItem; - field = TextSingleFormField::create("Romeo"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Romeo"); field->setName("first"); secondItem.push_back(field); - field = TextSingleFormField::create("Montague"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague"); field->setName("last"); secondItem.push_back(field); - field = TextSingleFormField::create("romeo@montague.net"); + field = boost::make_shared<FormField>(FormField::TextSingleType, "romeo@montague.net"); field->setName("jid"); secondItem.push_back(field); - field = ListSingleFormField::create("male"); + field = boost::make_shared<FormField>(FormField::ListSingleType, "male"); field->setName("x-gender"); secondItem.push_back(field); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp index 3ac1d77..01c8e77 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp @@ -32,12 +32,13 @@ class VCardSerializerTest : public CppUnit::TestFixture vcard->setPhoto(createByteArray("abcdef")); vcard->setPhotoType("image/png"); - vcard->addUnknownContent("<BDAY>1234</BDAY><MAILER>mutt</MAILER>"); + vcard->setBirthday(boost::posix_time::ptime(boost::gregorian::date(1865, 5, 4))); + vcard->addUnknownContent("<MAILER>mutt</MAILER>"); - VCard::EMailAddress address1; - address1.address = "alice@wonderland.lit"; - address1.isHome = true; - address1.isPreferred = true; - address1.isInternet = true; - vcard->addEMailAddress(address1); + VCard::EMailAddress emailAddress1; + emailAddress1.address = "alice@wonderland.lit"; + emailAddress1.isHome = true; + emailAddress1.isPreferred = true; + emailAddress1.isInternet = true; + vcard->addEMailAddress(emailAddress1); VCard::EMailAddress address2; @@ -47,4 +48,39 @@ class VCardSerializerTest : public CppUnit::TestFixture vcard->addEMailAddress(address2); + VCard::Telephone telephone1; + telephone1.number = "555-6273"; + telephone1.isHome = true; + telephone1.isVoice = true; + vcard->addTelephone(telephone1); + + VCard::Address address1; + address1.locality = "Any Town"; + address1.street = "Fake Street 123"; + address1.postalCode = "12345"; + address1.country = "USA"; + address1.isHome = true; + vcard->addAddress(address1); + + VCard::AddressLabel label1; + label1.lines.push_back("Fake Street 123"); + label1.lines.push_back("12345 Any Town"); + label1.lines.push_back("USA"); + label1.isHome = true; + vcard->addAddressLabel(label1); + + vcard->addJID(JID("alice@teaparty.lit")); + vcard->addJID(JID("alice@wonderland.lit")); + + vcard->setDescription("I once fell down a rabbit hole."); + + VCard::Organization org1; + org1.name = "Alice In Wonderland Inc."; + vcard->addOrganization(org1); + + vcard->addTitle("Some Title"); + vcard->addRole("Main Character"); + vcard->addURL("http://wonderland.lit/~alice"); + vcard->addURL("http://teaparty.lit/~alice2"); + std::string expectedResult = "<vCard xmlns=\"vcard-temp\">" @@ -74,5 +110,33 @@ class VCardSerializerTest : public CppUnit::TestFixture "<BINVAL>YWJjZGVm</BINVAL>" "</PHOTO>" - "<BDAY>1234</BDAY>" + "<BDAY>1865-05-04T00:00:00Z</BDAY>" + "<TEL>" + "<NUMBER>555-6273</NUMBER>" + "<HOME/>" + "<VOICE/>" + "</TEL>" + "<ADR>" + "<STREET>Fake Street 123</STREET>" + "<LOCALITY>Any Town</LOCALITY>" + "<PCODE>12345</PCODE>" + "<CTRY>USA</CTRY>" + "<HOME/>" + "</ADR>" + "<LABEL>" + "<LINE>Fake Street 123</LINE>" + "<LINE>12345 Any Town</LINE>" + "<LINE>USA</LINE>" + "<HOME/>" + "</LABEL>" + "<JID>alice@teaparty.lit</JID>" + "<JID>alice@wonderland.lit</JID>" + "<DESC>I once fell down a rabbit hole.</DESC>" + "<ORG>" + "<ORGNAME>Alice In Wonderland Inc.</ORGNAME>" + "</ORG>" + "<TITLE>Some Title</TITLE>" + "<ROLE>Main Character</ROLE>" + "<URL>http://wonderland.lit/~alice</URL>" + "<URL>http://teaparty.lit/~alice2</URL>" "<MAILER>mutt</MAILER>" "</vCard>"; diff --git a/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.cpp new file mode 100644 index 0000000..3c8dde1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Base/DateTime.h> +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +UserLocationSerializer::UserLocationSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +UserLocationSerializer::~UserLocationSerializer() { +} + +std::string UserLocationSerializer::serializePayload(boost::shared_ptr<UserLocation> payload) const { + if (!payload) { + return ""; + } + XMLElement element("geoloc", "http://jabber.org/protocol/geoloc"); + if (payload->getArea()) { + element.addNode(boost::make_shared<XMLElement>("area", "", *payload->getArea())); + } + if (payload->getAltitude()) { + element.addNode(boost::make_shared<XMLElement>("alt", "", boost::lexical_cast<std::string>(*payload->getAltitude()))); + } + if (payload->getLocality()) { + element.addNode(boost::make_shared<XMLElement>("locality", "", *payload->getLocality())); + } + if (payload->getLatitude()) { + element.addNode(boost::make_shared<XMLElement>("lat", "", boost::lexical_cast<std::string>(*payload->getLatitude()))); + } + if (payload->getAccuracy()) { + element.addNode(boost::make_shared<XMLElement>("accuracy", "", boost::lexical_cast<std::string>(*payload->getAccuracy()))); + } + if (payload->getDescription()) { + element.addNode(boost::make_shared<XMLElement>("description", "", *payload->getDescription())); + } + if (payload->getCountryCode()) { + element.addNode(boost::make_shared<XMLElement>("countrycode", "", *payload->getCountryCode())); + } + if (payload->getTimestamp()) { + element.addNode(boost::make_shared<XMLElement>("timestamp", "", dateTimeToString(*payload->getTimestamp()))); + } + if (payload->getFloor()) { + element.addNode(boost::make_shared<XMLElement>("floor", "", *payload->getFloor())); + } + if (payload->getBuilding()) { + element.addNode(boost::make_shared<XMLElement>("building", "", *payload->getBuilding())); + } + if (payload->getRoom()) { + element.addNode(boost::make_shared<XMLElement>("room", "", *payload->getRoom())); + } + if (payload->getCountry()) { + element.addNode(boost::make_shared<XMLElement>("country", "", *payload->getCountry())); + } + if (payload->getRegion()) { + element.addNode(boost::make_shared<XMLElement>("region", "", *payload->getRegion())); + } + if (payload->getURI()) { + element.addNode(boost::make_shared<XMLElement>("uri", "", *payload->getURI())); + } + if (payload->getLongitude()) { + element.addNode(boost::make_shared<XMLElement>("lon", "", boost::lexical_cast<std::string>(*payload->getLongitude()))); + } + if (payload->getError()) { + element.addNode(boost::make_shared<XMLElement>("error", "", boost::lexical_cast<std::string>(*payload->getError()))); + } + if (payload->getPostalCode()) { + element.addNode(boost::make_shared<XMLElement>("postalcode", "", *payload->getPostalCode())); + } + if (payload->getBearing()) { + element.addNode(boost::make_shared<XMLElement>("bearing", "", boost::lexical_cast<std::string>(*payload->getBearing()))); + } + if (payload->getText()) { + element.addNode(boost::make_shared<XMLElement>("text", "", *payload->getText())); + } + if (payload->getDatum()) { + element.addNode(boost::make_shared<XMLElement>("datum", "", *payload->getDatum())); + } + if (payload->getStreet()) { + element.addNode(boost::make_shared<XMLElement>("street", "", *payload->getStreet())); + } + if (payload->getSpeed()) { + element.addNode(boost::make_shared<XMLElement>("speed", "", boost::lexical_cast<std::string>(*payload->getSpeed()))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h new file mode 100644 index 0000000..d00187e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/UserLocation.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API UserLocationSerializer : public GenericPayloadSerializer<UserLocation> { + public: + UserLocationSerializer(PayloadSerializerCollection* serializers); + virtual ~UserLocationSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<UserLocation>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp new file mode 100644 index 0000000..c27259c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma clang diagnostic ignored "-Wunused-private-field" + +#include <Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +UserTuneSerializer::UserTuneSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +UserTuneSerializer::~UserTuneSerializer() { +} + +std::string UserTuneSerializer::serializePayload(boost::shared_ptr<UserTune> payload) const { + if (!payload) { + return ""; + } + XMLElement element("tune", "http://jabber.org/protocol/tune"); + if (payload->getRating()) { + element.addNode(boost::make_shared<XMLElement>("rating", "", boost::lexical_cast<std::string>(*payload->getRating()))); + } + if (payload->getTitle()) { + element.addNode(boost::make_shared<XMLElement>("title", "", *payload->getTitle())); + } + if (payload->getTrack()) { + element.addNode(boost::make_shared<XMLElement>("track", "", *payload->getTrack())); + } + if (payload->getArtist()) { + element.addNode(boost::make_shared<XMLElement>("artist", "", *payload->getArtist())); + } + if (payload->getURI()) { + element.addNode(boost::make_shared<XMLElement>("uri", "", *payload->getURI())); + } + if (payload->getSource()) { + element.addNode(boost::make_shared<XMLElement>("source", "", *payload->getSource())); + } + if (payload->getLength()) { + element.addNode(boost::make_shared<XMLElement>("length", "", boost::lexical_cast<std::string>(*payload->getLength()))); + } + return element.serialize(); +} + + diff --git a/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h new file mode 100644 index 0000000..62be6f2 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/UserTune.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API UserTuneSerializer : public GenericPayloadSerializer<UserTune> { + public: + UserTuneSerializer(PayloadSerializerCollection* serializers); + virtual ~UserTuneSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<UserTune>) const SWIFTEN_OVERRIDE; + + private: + + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp index 1512c6c..22d59b4 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp @@ -14,4 +14,5 @@ #include <Swiften/Serializer/XML/XMLRawTextNode.h> #include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Base/DateTime.h> #include <Swiften/Base/foreach.h> @@ -24,39 +25,25 @@ std::string VCardSerializer::serializePayload(boost::shared_ptr<VCard> vcard) c XMLElement queryElement("vCard", "vcard-temp"); if (!vcard->getVersion().empty()) { - boost::shared_ptr<XMLElement> versionElement(new XMLElement("VERSION")); - versionElement->addNode(boost::make_shared<XMLTextNode>(vcard->getVersion())); - queryElement.addNode(versionElement); + queryElement.addNode(boost::make_shared<XMLElement>("VERSION", "", vcard->getVersion())); } if (!vcard->getFullName().empty()) { - boost::shared_ptr<XMLElement> fullNameElement(new XMLElement("FN")); - fullNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getFullName())); - queryElement.addNode(fullNameElement); + queryElement.addNode(boost::make_shared<XMLElement>("FN", "", vcard->getFullName())); } if (!vcard->getGivenName().empty() || !vcard->getFamilyName().empty() || !vcard->getMiddleName().empty() || !vcard->getPrefix().empty() || !vcard->getSuffix().empty()) { boost::shared_ptr<XMLElement> nameElement(new XMLElement("N")); if (!vcard->getFamilyName().empty()) { - boost::shared_ptr<XMLElement> familyNameElement(new XMLElement("FAMILY")); - familyNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getFamilyName())); - nameElement->addNode(familyNameElement); + nameElement->addNode(boost::make_shared<XMLElement>("FAMILY", "", vcard->getFamilyName())); } if (!vcard->getGivenName().empty()) { - boost::shared_ptr<XMLElement> givenNameElement(new XMLElement("GIVEN")); - givenNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getGivenName())); - nameElement->addNode(givenNameElement); + nameElement->addNode(boost::make_shared<XMLElement>("GIVEN", "", vcard->getGivenName())); } if (!vcard->getMiddleName().empty()) { - boost::shared_ptr<XMLElement> middleNameElement(new XMLElement("MIDDLE")); - middleNameElement->addNode(boost::make_shared<XMLTextNode>(vcard->getMiddleName())); - nameElement->addNode(middleNameElement); + nameElement->addNode(boost::make_shared<XMLElement>("MIDDLE", "", vcard->getMiddleName())); } if (!vcard->getPrefix().empty()) { - boost::shared_ptr<XMLElement> prefixElement(new XMLElement("PREFIX")); - prefixElement->addNode(boost::make_shared<XMLTextNode>(vcard->getPrefix())); - nameElement->addNode(prefixElement); + nameElement->addNode(boost::make_shared<XMLElement>("PREFIX", "", vcard->getPrefix())); } if (!vcard->getSuffix().empty()) { - boost::shared_ptr<XMLElement> suffixElement(new XMLElement("SUFFIX")); - suffixElement->addNode(boost::make_shared<XMLTextNode>(vcard->getSuffix())); - nameElement->addNode(suffixElement); + nameElement->addNode(boost::make_shared<XMLElement>("SUFFIX", "", vcard->getSuffix())); } queryElement.addNode(nameElement); @@ -64,7 +51,5 @@ std::string VCardSerializer::serializePayload(boost::shared_ptr<VCard> vcard) c foreach(const VCard::EMailAddress& emailAddress, vcard->getEMailAddresses()) { boost::shared_ptr<XMLElement> emailElement(new XMLElement("EMAIL")); - boost::shared_ptr<XMLElement> userIDElement(new XMLElement("USERID")); - userIDElement->addNode(boost::make_shared<XMLTextNode>(emailAddress.address)); - emailElement->addNode(userIDElement); + emailElement->addNode(boost::make_shared<XMLElement>("USERID", "", emailAddress.address)); if (emailAddress.isHome) { emailElement->addNode(boost::make_shared<XMLElement>("HOME")); @@ -85,22 +70,177 @@ std::string VCardSerializer::serializePayload(boost::shared_ptr<VCard> vcard) c } if (!vcard->getNickname().empty()) { - boost::shared_ptr<XMLElement> nickElement(new XMLElement("NICKNAME")); - nickElement->addNode(boost::make_shared<XMLTextNode>(vcard->getNickname())); - queryElement.addNode(nickElement); + queryElement.addNode(boost::make_shared<XMLElement>("NICKNAME", "", vcard->getNickname())); } if (!vcard->getPhoto().empty() || !vcard->getPhotoType().empty()) { XMLElement::ref photoElement(new XMLElement("PHOTO")); if (!vcard->getPhotoType().empty()) { - XMLElement::ref typeElement(new XMLElement("TYPE")); - typeElement->addNode(XMLTextNode::ref(new XMLTextNode(vcard->getPhotoType()))); - photoElement->addNode(typeElement); + photoElement->addNode(boost::make_shared<XMLElement>("TYPE", "", vcard->getPhotoType())); } if (!vcard->getPhoto().empty()) { - XMLElement::ref binvalElement(new XMLElement("BINVAL")); - binvalElement->addNode(XMLTextNode::ref(new XMLTextNode(Base64::encode(vcard->getPhoto())))); - photoElement->addNode(binvalElement); + photoElement->addNode(boost::make_shared<XMLElement>("BINVAL", "", Base64::encode(vcard->getPhoto()))); } queryElement.addNode(photoElement); } + if (!vcard->getBirthday().is_not_a_date_time()) { + queryElement.addNode(boost::make_shared<XMLElement>("BDAY", "", dateTimeToString(vcard->getBirthday()))); + } + + foreach(const VCard::Telephone& telephone, vcard->getTelephones()) { + boost::shared_ptr<XMLElement> telElement(new XMLElement("TEL")); + telElement->addNode(boost::make_shared<XMLElement>("NUMBER", "", telephone.number)); + if (telephone.isHome) { + telElement->addNode(boost::make_shared<XMLElement>("HOME")); + } + if (telephone.isWork) { + telElement->addNode(boost::make_shared<XMLElement>("WORK")); + } + if (telephone.isVoice) { + telElement->addNode(boost::make_shared<XMLElement>("VOICE")); + } + if (telephone.isFax) { + telElement->addNode(boost::make_shared<XMLElement>("FAX")); + } + if (telephone.isPager) { + telElement->addNode(boost::make_shared<XMLElement>("PAGER")); + } + if (telephone.isMSG) { + telElement->addNode(boost::make_shared<XMLElement>("MSG")); + } + if (telephone.isCell) { + telElement->addNode(boost::make_shared<XMLElement>("CELL")); + } + if (telephone.isVideo) { + telElement->addNode(boost::make_shared<XMLElement>("VIDEO")); + } + if (telephone.isBBS) { + telElement->addNode(boost::make_shared<XMLElement>("BBS")); + } + if (telephone.isModem) { + telElement->addNode(boost::make_shared<XMLElement>("MODEM")); + } + if (telephone.isISDN) { + telElement->addNode(boost::make_shared<XMLElement>("ISDN")); + } + if (telephone.isPCS) { + telElement->addNode(boost::make_shared<XMLElement>("PCS")); + } + if (telephone.isPreferred) { + telElement->addNode(boost::make_shared<XMLElement>("PREF")); + } + queryElement.addNode(telElement); + } + + foreach(const VCard::Address& address, vcard->getAddresses()) { + boost::shared_ptr<XMLElement> adrElement = boost::make_shared<XMLElement>("ADR"); + if (!address.poBox.empty()) { + adrElement->addNode(boost::make_shared<XMLElement>("POBOX", "", address.poBox)); + } + if (!address.addressExtension.empty()) { + adrElement->addNode(boost::make_shared<XMLElement>("EXTADD", "", address.addressExtension)); + } + if (!address.street.empty()) { + adrElement->addNode(boost::make_shared<XMLElement>("STREET", "", address.street)); + } + if (!address.locality.empty()) { + adrElement->addNode(boost::make_shared<XMLElement>("LOCALITY", "", address.locality)); + } + if (!address.region.empty()) { + adrElement->addNode(boost::make_shared<XMLElement>("REGION", "", address.region)); + } + if (!address.postalCode.empty()) { + adrElement->addNode(boost::make_shared<XMLElement>("PCODE", "", address.postalCode)); + } + if (!address.country.empty()) { + adrElement->addNode(boost::make_shared<XMLElement>("CTRY", "", address.country)); + } + + if (address.isHome) { + adrElement->addNode(boost::make_shared<XMLElement>("HOME")); + } + if (address.isWork) { + adrElement->addNode(boost::make_shared<XMLElement>("WORK")); + } + if (address.isPostal) { + adrElement->addNode(boost::make_shared<XMLElement>("POSTAL")); + } + if (address.isParcel) { + adrElement->addNode(boost::make_shared<XMLElement>("PARCEL")); + } + if (address.deliveryType == VCard::DomesticDelivery) { + adrElement->addNode(boost::make_shared<XMLElement>("DOM")); + } + if (address.deliveryType == VCard::InternationalDelivery) { + adrElement->addNode(boost::make_shared<XMLElement>("INTL")); + } + if (address.isPreferred) { + adrElement->addNode(boost::make_shared<XMLElement>("PREF")); + } + queryElement.addNode(adrElement); + } + + foreach(const VCard::AddressLabel& addressLabel, vcard->getAddressLabels()) { + boost::shared_ptr<XMLElement> labelElement = boost::make_shared<XMLElement>("LABEL"); + + foreach(const std::string& line, addressLabel.lines) { + labelElement->addNode(boost::make_shared<XMLElement>("LINE", "", line)); + } + + if (addressLabel.isHome) { + labelElement->addNode(boost::make_shared<XMLElement>("HOME")); + } + if (addressLabel.isWork) { + labelElement->addNode(boost::make_shared<XMLElement>("WORK")); + } + if (addressLabel.isPostal) { + labelElement->addNode(boost::make_shared<XMLElement>("POSTAL")); + } + if (addressLabel.isParcel) { + labelElement->addNode(boost::make_shared<XMLElement>("PARCEL")); + } + if (addressLabel.deliveryType == VCard::DomesticDelivery) { + labelElement->addNode(boost::make_shared<XMLElement>("DOM")); + } + if (addressLabel.deliveryType == VCard::InternationalDelivery) { + labelElement->addNode(boost::make_shared<XMLElement>("INTL")); + } + if (addressLabel.isPreferred) { + labelElement->addNode(boost::make_shared<XMLElement>("PREF")); + } + queryElement.addNode(labelElement); + } + + foreach(const JID& jid, vcard->getJIDs()) { + queryElement.addNode(boost::make_shared<XMLElement>("JID", "", jid.toString())); + } + + if (!vcard->getDescription().empty()) { + queryElement.addNode(boost::make_shared<XMLElement>("DESC", "", vcard->getDescription())); + } + + foreach(const VCard::Organization& org, vcard->getOrganizations()) { + boost::shared_ptr<XMLElement> orgElement = boost::make_shared<XMLElement>("ORG"); + if (!org.name.empty()) { + orgElement->addNode(boost::make_shared<XMLElement>("ORGNAME", "", org.name)); + } + if (!org.units.empty()) { + foreach(const std::string& unit, org.units) { + orgElement->addNode(boost::make_shared<XMLElement>("ORGUNIT", "", unit)); + } + } + queryElement.addNode(orgElement); + } + + foreach(const std::string& title, vcard->getTitles()) { + queryElement.addNode(boost::make_shared<XMLElement>("TITLE", "", title)); + } + + foreach(const std::string& role, vcard->getRoles()) { + queryElement.addNode(boost::make_shared<XMLElement>("ROLE", "", role)); + } + + foreach(const std::string& url, vcard->getURLs()) { + queryElement.addNode(boost::make_shared<XMLElement>("URL", "", url)); + } + if (!vcard->getUnknownContent().empty()) { queryElement.addNode(boost::make_shared<XMLRawTextNode>(vcard->getUnknownContent())); diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.h b/Swiften/Serializer/PayloadSerializers/VCardSerializer.h index c73ff18..04c1843 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.h @@ -10,6 +10,8 @@ #include <Swiften/Elements/VCard.h> +#include <Swiften/Base/API.h> + namespace Swift { - class VCardSerializer : public GenericPayloadSerializer<VCard> { + class SWIFTEN_API VCardSerializer : public GenericPayloadSerializer<VCard> { public: VCardSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h b/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h index 68084f0..6a63236 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h @@ -7,9 +7,10 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Serializer/GenericPayloadSerializer.h> #include <Swiften/Elements/VCardUpdate.h> namespace Swift { - class VCardUpdateSerializer : public GenericPayloadSerializer<VCardUpdate> { + class SWIFTEN_API VCardUpdateSerializer : public GenericPayloadSerializer<VCardUpdate> { public: VCardUpdateSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp new file mode 100644 index 0000000..97dc94e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h> + +#include <iostream> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/lexical_cast.hpp> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h> + +namespace Swift { + void WhiteboardElementSerializingVisitor::visit(WhiteboardLineElement& line) { + element = boost::make_shared<XMLElement>("line"); + try { + element->setAttribute("x1", boost::lexical_cast<std::string>(line.x1())); + element->setAttribute("y1", boost::lexical_cast<std::string>(line.y1())); + element->setAttribute("x2", boost::lexical_cast<std::string>(line.x2())); + element->setAttribute("y2", boost::lexical_cast<std::string>(line.y2())); + element->setAttribute("id", line.getID()); + element->setAttribute("stroke", line.getColor().toHex()); + element->setAttribute("stroke-width", boost::lexical_cast<std::string>(line.getPenWidth())); + element->setAttribute("opacity", alphaToOpacity(line.getColor().getAlpha())); + } catch (boost::bad_lexical_cast&) { + } + } + + void WhiteboardElementSerializingVisitor::visit(WhiteboardFreehandPathElement& path) { + element = boost::make_shared<XMLElement>("path"); + element->setAttribute("id", path.getID()); + element->setAttribute("stroke", path.getColor().toHex()); + try { + element->setAttribute("stroke-width", boost::lexical_cast<std::string>(path.getPenWidth())); + element->setAttribute("opacity", alphaToOpacity(path.getColor().getAlpha())); + std::string pathData; + if (path.getPoints().size() != 0) { + std::vector<std::pair<int, int> >::const_iterator it = path.getPoints().begin(); + pathData = "M"+boost::lexical_cast<std::string>(it->first)+" "+boost::lexical_cast<std::string>(it->second)+"L"; + for (; it != path.getPoints().end(); ++it) { + pathData += boost::lexical_cast<std::string>(it->first)+" "+boost::lexical_cast<std::string>(it->second)+" "; + } + } + element->setAttribute("d", pathData); + } catch (boost::bad_lexical_cast&) { + } + } + + void WhiteboardElementSerializingVisitor::visit(WhiteboardRectElement& rect) { + element = boost::make_shared<XMLElement>("rect"); + try { + element->setAttribute("x", boost::lexical_cast<std::string>(rect.getX())); + element->setAttribute("y", boost::lexical_cast<std::string>(rect.getY())); + element->setAttribute("width", boost::lexical_cast<std::string>(rect.getWidth())); + element->setAttribute("height", boost::lexical_cast<std::string>(rect.getHeight())); + element->setAttribute("id", rect.getID()); + element->setAttribute("stroke", rect.getPenColor().toHex()); + element->setAttribute("fill", rect.getBrushColor().toHex());; + element->setAttribute("stroke-width", boost::lexical_cast<std::string>(rect.getPenWidth())); + element->setAttribute("opacity", alphaToOpacity(rect.getPenColor().getAlpha())); + element->setAttribute("fill-opacity", alphaToOpacity(rect.getBrushColor().getAlpha())); + } catch (boost::bad_lexical_cast&) { + } + } + + void WhiteboardElementSerializingVisitor::visit(WhiteboardPolygonElement& polygon) { + element = boost::make_shared<XMLElement>("polygon"); + try { + element->setAttribute("id", polygon.getID()); + element->setAttribute("stroke", polygon.getPenColor().toHex()); + element->setAttribute("fill", polygon.getBrushColor().toHex());; + element->setAttribute("stroke-width", boost::lexical_cast<std::string>(polygon.getPenWidth())); + element->setAttribute("opacity", alphaToOpacity(polygon.getPenColor().getAlpha())); + element->setAttribute("fill-opacity", alphaToOpacity(polygon.getBrushColor().getAlpha())); + std::string points; + std::vector<std::pair<int, int> >::const_iterator it = polygon.getPoints().begin(); + for (; it != polygon.getPoints().end(); ++it) { + points += boost::lexical_cast<std::string>(it->first)+","+boost::lexical_cast<std::string>(it->second)+" "; + } + element->setAttribute("points", points); + } catch (boost::bad_lexical_cast&) { + } + } + + void WhiteboardElementSerializingVisitor::visit(WhiteboardTextElement& text) { + element = boost::make_shared<XMLElement>("text"); + try { + element->setAttribute("x", boost::lexical_cast<std::string>(text.getX())); + element->setAttribute("y", boost::lexical_cast<std::string>(text.getY())); + element->setAttribute("font-size", boost::lexical_cast<std::string>(text.getSize())); + element->setAttribute("id", text.getID()); + element->setAttribute("fill", text.getColor().toHex()); + element->setAttribute("opacity", alphaToOpacity(text.getColor().getAlpha())); + element->addNode(boost::make_shared<XMLTextNode>(text.getText())); + } catch (boost::bad_lexical_cast&) { + } + } + + void WhiteboardElementSerializingVisitor::visit(WhiteboardEllipseElement& ellipse) { + element = boost::make_shared<XMLElement>("ellipse"); + try { + element->setAttribute("cx", boost::lexical_cast<std::string>(ellipse.getCX())); + element->setAttribute("cy", boost::lexical_cast<std::string>(ellipse.getCY())); + element->setAttribute("rx", boost::lexical_cast<std::string>(ellipse.getRX())); + element->setAttribute("ry", boost::lexical_cast<std::string>(ellipse.getRY())); + element->setAttribute("id", ellipse.getID()); + element->setAttribute("stroke", ellipse.getPenColor().toHex()); + element->setAttribute("fill", ellipse.getBrushColor().toHex());; + element->setAttribute("stroke-width", boost::lexical_cast<std::string>(ellipse.getPenWidth())); + element->setAttribute("opacity", alphaToOpacity(ellipse.getPenColor().getAlpha())); + element->setAttribute("fill-opacity", alphaToOpacity(ellipse.getBrushColor().getAlpha())); + } catch (boost::bad_lexical_cast&) { + } + } + + XMLElement::ref WhiteboardElementSerializingVisitor::getResult() const { + return element; + } + + std::string WhiteboardElementSerializingVisitor::alphaToOpacity(int alpha) const { + int opacity = 100*alpha/254; + if (opacity == 100) { + return "1"; + } else { + return "."+boost::lexical_cast<std::string>(opacity); + } + } + + std::string WhiteboardSerializer::serializePayload(boost::shared_ptr<WhiteboardPayload> payload) const { + XMLElement element("wb", "http://swift.im/whiteboard"); + if (payload->getType() == WhiteboardPayload::Data) { + XMLElement::ref operationNode = boost::make_shared<XMLElement>("operation"); + WhiteboardElementSerializingVisitor visitor; +// payload->getElement()->accept(visitor); + WhiteboardInsertOperation::ref insertOp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(payload->getOperation()); + if (insertOp) { + try { + operationNode->setAttribute("type", "insert"); + operationNode->setAttribute("pos", boost::lexical_cast<std::string>(insertOp->getPos())); + operationNode->setAttribute("id", insertOp->getID()); + operationNode->setAttribute("parentid", insertOp->getParentID()); + } catch (boost::bad_lexical_cast&) { + } + insertOp->getElement()->accept(visitor); + operationNode->addNode(visitor.getResult()); + } + WhiteboardUpdateOperation::ref updateOp = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(payload->getOperation()); + if (updateOp) { + try { + operationNode->setAttribute("type", "update"); + operationNode->setAttribute("pos", boost::lexical_cast<std::string>(updateOp->getPos())); + operationNode->setAttribute("id", updateOp->getID()); + operationNode->setAttribute("parentid", updateOp->getParentID()); + operationNode->setAttribute("newpos", boost::lexical_cast<std::string>(updateOp->getNewPos())); + } catch (boost::bad_lexical_cast&) { + } + updateOp->getElement()->accept(visitor); + operationNode->addNode(visitor.getResult()); + + } + + WhiteboardDeleteOperation::ref deleteOp = boost::dynamic_pointer_cast<WhiteboardDeleteOperation>(payload->getOperation()); + if (deleteOp) { + try { + operationNode->setAttribute("type", "delete"); + operationNode->setAttribute("pos", boost::lexical_cast<std::string>(deleteOp->getPos())); + operationNode->setAttribute("id", deleteOp->getID()); + operationNode->setAttribute("parentid", deleteOp->getParentID()); + operationNode->setAttribute("elementid", deleteOp->getElementID()); + } catch (boost::bad_lexical_cast&) { + } + } + element.addNode(operationNode); + } + element.setAttribute("type", typeToString(payload->getType())); + return element.serialize(); + } + + std::string WhiteboardSerializer::typeToString(WhiteboardPayload::Type type) const { + switch (type) { + case WhiteboardPayload::Data: + return "data"; + case WhiteboardPayload::SessionRequest: + return "session-request"; + case WhiteboardPayload::SessionAccept: + return "session-accept"; + case WhiteboardPayload::SessionTerminate: + return "session-terminate"; + case WhiteboardPayload::UnknownType: + std::cerr << "Warning: Serializing unknown action value." << std::endl; + return ""; + } + assert(false); + return ""; + } +} diff --git a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h new file mode 100644 index 0000000..26b76cb --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/WhiteboardPayload.h> +#include <Swiften/Elements/Whiteboard/WhiteboardLineElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardFreehandPathElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardRectElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardPolygonElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardTextElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardEllipseElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardElementVisitor.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +namespace Swift { + class WhiteboardElementSerializingVisitor : public WhiteboardElementVisitor { + public: + void visit(WhiteboardLineElement& line); + void visit(WhiteboardFreehandPathElement& path); + void visit(WhiteboardRectElement& rect); + void visit(WhiteboardPolygonElement& polygon); + void visit(WhiteboardTextElement& text); + void visit(WhiteboardEllipseElement& ellipse); + XMLElement::ref getResult() const; + + private: + std::string alphaToOpacity(int alpha) const; + + XMLElement::ref element; + }; + + class WhiteboardSerializer : public GenericPayloadSerializer<WhiteboardPayload> { + public: + std::string serializePayload(boost::shared_ptr<WhiteboardPayload> payload) const; + + private: + std::string typeToString(WhiteboardPayload::Type type) const; + }; +} diff --git a/Swiften/Serializer/PresenceSerializer.cpp b/Swiften/Serializer/PresenceSerializer.cpp index 20eda4b..a192bb5 100644 --- a/Swiften/Serializer/PresenceSerializer.cpp +++ b/Swiften/Serializer/PresenceSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -7,11 +7,12 @@ #include <Swiften/Serializer/PresenceSerializer.h> #include <Swiften/Serializer/XML/XMLElement.h> - +#include <Swiften/Base/Log.h> #include <boost/shared_ptr.hpp> namespace Swift { -PresenceSerializer::PresenceSerializer(PayloadSerializerCollection* payloadSerializers) : - GenericStanzaSerializer<Presence>("presence", payloadSerializers) { +PresenceSerializer::PresenceSerializer(PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explicitNS) : + GenericStanzaSerializer<Presence>("presence", payloadSerializers, explicitNS) { + } diff --git a/Swiften/Serializer/PresenceSerializer.h b/Swiften/Serializer/PresenceSerializer.h index e5d9f30..b3ed721 100644 --- a/Swiften/Serializer/PresenceSerializer.h +++ b/Swiften/Serializer/PresenceSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,8 +10,11 @@ #include <Swiften/Elements/Presence.h> +#include <boost/optional.hpp> + namespace Swift { class PresenceSerializer : public GenericStanzaSerializer<Presence> { public: - PresenceSerializer(PayloadSerializerCollection* payloadSerializers); + PresenceSerializer(PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explicitNS = boost::optional<std::string>()); + ~PresenceSerializer() {} private: diff --git a/Swiften/Serializer/StanzaAckRequestSerializer.h b/Swiften/Serializer/StanzaAckRequestSerializer.h index fff2a83..9766308 100644 --- a/Swiften/Serializer/StanzaAckRequestSerializer.h +++ b/Swiften/Serializer/StanzaAckRequestSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("r", "urn:xmpp:sm:2").serialize()); } diff --git a/Swiften/Serializer/StanzaAckSerializer.h b/Swiften/Serializer/StanzaAckSerializer.h index ea1e8ad..ad2add6 100644 --- a/Swiften/Serializer/StanzaAckSerializer.h +++ b/Swiften/Serializer/StanzaAckSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -20,5 +20,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const { StanzaAck::ref stanzaAck(boost::dynamic_pointer_cast<StanzaAck>(element)); assert(stanzaAck->isValid()); diff --git a/Swiften/Serializer/StanzaSerializer.cpp b/Swiften/Serializer/StanzaSerializer.cpp index 9a4fd2c..d097bbf 100644 --- a/Swiften/Serializer/StanzaSerializer.cpp +++ b/Swiften/Serializer/StanzaSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -20,11 +20,20 @@ namespace Swift { -StanzaSerializer::StanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers) : tag_(tag), payloadSerializers_(payloadSerializers) { +StanzaSerializer::StanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explicitNS) : tag_(tag), payloadSerializers_(payloadSerializers), explicitDefaultNS_(explicitNS) { } -SafeByteArray StanzaSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray StanzaSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { + if (explicitDefaultNS_) { + return serialize(element, explicitDefaultNS_.get()); + } + else { + return serialize(element, ""); + } +} + +SafeByteArray StanzaSerializer::serialize(boost::shared_ptr<ToplevelElement> element, const std::string& xmlns) const { boost::shared_ptr<Stanza> stanza(boost::dynamic_pointer_cast<Stanza>(element)); - XMLElement stanzaElement(tag_); + XMLElement stanzaElement(tag_, explicitDefaultNS_ ? explicitDefaultNS_.get() : xmlns); if (stanza->getFrom().isValid()) { stanzaElement.setAttribute("from", stanza->getFrom()); diff --git a/Swiften/Serializer/StanzaSerializer.h b/Swiften/Serializer/StanzaSerializer.h index db18aa2..766b58c 100644 --- a/Swiften/Serializer/StanzaSerializer.h +++ b/Swiften/Serializer/StanzaSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2013-2014 Kevin Smith and Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,5 +9,7 @@ #include <Swiften/Elements/Stanza.h> #include <Swiften/Serializer/ElementSerializer.h> + #include <string> +#include <boost/optional.hpp> namespace Swift { @@ -17,12 +19,14 @@ namespace Swift { class StanzaSerializer : public ElementSerializer { public: - StanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers); + StanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers, const boost::optional<std::string>& explicitNS = boost::optional<std::string>()); - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; - virtual void setStanzaSpecificAttributes(boost::shared_ptr<Element>, XMLElement&) const = 0; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element, const std::string& xmlns) const; + virtual void setStanzaSpecificAttributes(boost::shared_ptr<ToplevelElement>, XMLElement&) const = 0; private: std::string tag_; PayloadSerializerCollection* payloadSerializers_; + boost::optional<std::string> explicitDefaultNS_; }; } diff --git a/Swiften/Serializer/StartTLSFailureSerializer.h b/Swiften/Serializer/StartTLSFailureSerializer.h index 779be92..f924545 100644 --- a/Swiften/Serializer/StartTLSFailureSerializer.h +++ b/Swiften/Serializer/StartTLSFailureSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("failure", "urn:ietf:params:xml:ns:xmpp-tls").serialize()); } diff --git a/Swiften/Serializer/StartTLSRequestSerializer.h b/Swiften/Serializer/StartTLSRequestSerializer.h index df914ce..80745e3 100644 --- a/Swiften/Serializer/StartTLSRequestSerializer.h +++ b/Swiften/Serializer/StartTLSRequestSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("starttls", "urn:ietf:params:xml:ns:xmpp-tls").serialize()); } diff --git a/Swiften/Serializer/StreamErrorSerializer.cpp b/Swiften/Serializer/StreamErrorSerializer.cpp index b3d62a0..37ac3ca 100644 --- a/Swiften/Serializer/StreamErrorSerializer.cpp +++ b/Swiften/Serializer/StreamErrorSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,5 +16,5 @@ StreamErrorSerializer::StreamErrorSerializer() : GenericElementSerializer<Stream } -SafeByteArray StreamErrorSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray StreamErrorSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { StreamError::ref error = boost::dynamic_pointer_cast<StreamError>(element); XMLElement errorElement("error", "http://etherx.jabber.org/streams"); diff --git a/Swiften/Serializer/StreamErrorSerializer.h b/Swiften/Serializer/StreamErrorSerializer.h index bdaa831..d82cd02 100644 --- a/Swiften/Serializer/StreamErrorSerializer.h +++ b/Swiften/Serializer/StreamErrorSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -15,5 +15,5 @@ namespace Swift { StreamErrorSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> error) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> error) const; }; } diff --git a/Swiften/Serializer/StreamFeaturesSerializer.cpp b/Swiften/Serializer/StreamFeaturesSerializer.cpp index 2344349..a93247a 100644 --- a/Swiften/Serializer/StreamFeaturesSerializer.cpp +++ b/Swiften/Serializer/StreamFeaturesSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,5 +18,5 @@ StreamFeaturesSerializer::StreamFeaturesSerializer() { } -SafeByteArray StreamFeaturesSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray StreamFeaturesSerializer::serialize(boost::shared_ptr<ToplevelElement> element) const { boost::shared_ptr<StreamFeatures> streamFeatures(boost::dynamic_pointer_cast<StreamFeatures>(element)); diff --git a/Swiften/Serializer/StreamFeaturesSerializer.h b/Swiften/Serializer/StreamFeaturesSerializer.h index 5ea3ab1..b69a218 100644 --- a/Swiften/Serializer/StreamFeaturesSerializer.h +++ b/Swiften/Serializer/StreamFeaturesSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,13 +9,14 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/StreamFeatures.h> #include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { - class StreamFeaturesSerializer : public GenericElementSerializer<StreamFeatures> { + class SWIFTEN_API StreamFeaturesSerializer : public GenericElementSerializer<StreamFeatures> { public: StreamFeaturesSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement> element) const; }; } diff --git a/Swiften/Serializer/StreamManagementEnabledSerializer.cpp b/Swiften/Serializer/StreamManagementEnabledSerializer.cpp index b559721..9d4ee94 100644 --- a/Swiften/Serializer/StreamManagementEnabledSerializer.cpp +++ b/Swiften/Serializer/StreamManagementEnabledSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ StreamManagementEnabledSerializer::StreamManagementEnabledSerializer() : Generic } -SafeByteArray StreamManagementEnabledSerializer::serialize(boost::shared_ptr<Element> el) const { +SafeByteArray StreamManagementEnabledSerializer::serialize(boost::shared_ptr<ToplevelElement> el) const { boost::shared_ptr<StreamManagementEnabled> e(boost::dynamic_pointer_cast<StreamManagementEnabled>(el)); XMLElement element("enabled", "urn:xmpp:sm:2"); diff --git a/Swiften/Serializer/StreamManagementEnabledSerializer.h b/Swiften/Serializer/StreamManagementEnabledSerializer.h index 5f28a2b..ee2a980 100644 --- a/Swiften/Serializer/StreamManagementEnabledSerializer.h +++ b/Swiften/Serializer/StreamManagementEnabledSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ namespace Swift { StreamManagementEnabledSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const; }; } diff --git a/Swiften/Serializer/StreamManagementFailedSerializer.h b/Swiften/Serializer/StreamManagementFailedSerializer.h index f3dcce0..f6e7b0e 100644 --- a/Swiften/Serializer/StreamManagementFailedSerializer.h +++ b/Swiften/Serializer/StreamManagementFailedSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("failed", "urn:xmpp:sm:2").serialize()); } diff --git a/Swiften/Serializer/StreamResumeSerializer.cpp b/Swiften/Serializer/StreamResumeSerializer.cpp index e9e520d..229b826 100644 --- a/Swiften/Serializer/StreamResumeSerializer.cpp +++ b/Swiften/Serializer/StreamResumeSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,10 +18,10 @@ StreamResumeSerializer::StreamResumeSerializer() : GenericElementSerializer<Stre } -SafeByteArray StreamResumeSerializer::serialize(boost::shared_ptr<Element> el) const { +SafeByteArray StreamResumeSerializer::serialize(boost::shared_ptr<ToplevelElement> el) const { boost::shared_ptr<StreamResume> e(boost::dynamic_pointer_cast<StreamResume>(el)); XMLElement element("resume", "urn:xmpp:sm:2"); element.setAttribute("previd", e->getResumeID()); if (e->getHandledStanzasCount()) { - element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount())); + element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount().get())); } return createSafeByteArray(element.serialize()); diff --git a/Swiften/Serializer/StreamResumeSerializer.h b/Swiften/Serializer/StreamResumeSerializer.h index 501d8b6..17baa44 100644 --- a/Swiften/Serializer/StreamResumeSerializer.h +++ b/Swiften/Serializer/StreamResumeSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ namespace Swift { StreamResumeSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const; }; } diff --git a/Swiften/Serializer/StreamResumedSerializer.cpp b/Swiften/Serializer/StreamResumedSerializer.cpp index 7ae82d1..48dbe8f 100644 --- a/Swiften/Serializer/StreamResumedSerializer.cpp +++ b/Swiften/Serializer/StreamResumedSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -18,10 +18,10 @@ StreamResumedSerializer::StreamResumedSerializer() : GenericElementSerializer<St } -SafeByteArray StreamResumedSerializer::serialize(boost::shared_ptr<Element> el) const { +SafeByteArray StreamResumedSerializer::serialize(boost::shared_ptr<ToplevelElement> el) const { boost::shared_ptr<StreamResumed> e(boost::dynamic_pointer_cast<StreamResumed>(el)); XMLElement element("resumed", "urn:xmpp:sm:2"); element.setAttribute("previd", e->getResumeID()); if (e->getHandledStanzasCount()) { - element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount())); + element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount().get())); } return createSafeByteArray(element.serialize()); diff --git a/Swiften/Serializer/StreamResumedSerializer.h b/Swiften/Serializer/StreamResumedSerializer.h index 7828694..bdca891 100644 --- a/Swiften/Serializer/StreamResumedSerializer.h +++ b/Swiften/Serializer/StreamResumedSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Remko Tronçon + * Copyright (c) 2011-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,5 +17,5 @@ namespace Swift { StreamResumedSerializer(); - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const; }; } diff --git a/Swiften/Serializer/TLSProceedSerializer.h b/Swiften/Serializer/TLSProceedSerializer.h index 21a8420..15db3dc 100644 --- a/Swiften/Serializer/TLSProceedSerializer.h +++ b/Swiften/Serializer/TLSProceedSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -19,5 +19,5 @@ namespace Swift { } - virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + virtual SafeByteArray serialize(boost::shared_ptr<ToplevelElement>) const { return createSafeByteArray(XMLElement("proceed", "urn:ietf:params:xml:ns:xmpp-tls").serialize()); } diff --git a/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp b/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp index c0ab841..83daf36 100644 --- a/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -66,5 +66,5 @@ class XMPPSerializerTest : public CppUnit::TestFixture { private: XMPPSerializer* createSerializer(StreamType type) { - return new XMPPSerializer(payloadSerializerCollection, type); + return new XMPPSerializer(payloadSerializerCollection, type, false); } diff --git a/Swiften/Serializer/XML/XMLElement.cpp b/Swiften/Serializer/XML/XMLElement.cpp index d39ec39..42b602a 100644 --- a/Swiften/Serializer/XML/XMLElement.cpp +++ b/Swiften/Serializer/XML/XMLElement.cpp @@ -53,6 +53,8 @@ void XMLElement::setAttribute(const std::string& attribute, const std::string& v void XMLElement::addNode(boost::shared_ptr<XMLNode> node) { + if (node) { childNodes_.push_back(node); } +} } diff --git a/Swiften/Serializer/XML/XMLElement.h b/Swiften/Serializer/XML/XMLElement.h index 6eacb82..305932a 100644 --- a/Swiften/Serializer/XML/XMLElement.h +++ b/Swiften/Serializer/XML/XMLElement.h @@ -13,8 +13,9 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Serializer/XML/XMLNode.h> namespace Swift { - class XMLElement : public XMLNode { + class SWIFTEN_API XMLElement : public XMLNode { public: typedef boost::shared_ptr<XMLElement> ref; diff --git a/Swiften/Serializer/XML/XMLNode.h b/Swiften/Serializer/XML/XMLNode.h index d222faf..9d9e1a0 100644 --- a/Swiften/Serializer/XML/XMLNode.h +++ b/Swiften/Serializer/XML/XMLNode.h @@ -9,6 +9,8 @@ #include <string> +#include <Swiften/Base/API.h> + namespace Swift { - class XMLNode { + class SWIFTEN_API XMLNode { public: virtual ~XMLNode(); diff --git a/Swiften/Serializer/XMPPSerializer.cpp b/Swiften/Serializer/XMPPSerializer.cpp index 389f7cc..1fb79e4 100644 --- a/Swiften/Serializer/XMPPSerializer.cpp +++ b/Swiften/Serializer/XMPPSerializer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -40,8 +40,8 @@ namespace Swift { -XMPPSerializer::XMPPSerializer(PayloadSerializerCollection* payloadSerializers, StreamType type) : type_(type) { - serializers_.push_back(boost::make_shared<PresenceSerializer>(payloadSerializers)); - serializers_.push_back(boost::make_shared<IQSerializer>(payloadSerializers)); - serializers_.push_back(boost::make_shared<MessageSerializer>(payloadSerializers)); +XMPPSerializer::XMPPSerializer(PayloadSerializerCollection* payloadSerializers, StreamType type, bool setExplictNSonTopLevelElements) : type_(type) { + serializers_.push_back(boost::make_shared<PresenceSerializer>(payloadSerializers, setExplictNSonTopLevelElements ? getDefaultNamespace() : boost::optional<std::string>())); + serializers_.push_back(boost::make_shared<IQSerializer>(payloadSerializers, setExplictNSonTopLevelElements ? getDefaultNamespace() : boost::optional<std::string>())); + serializers_.push_back(boost::make_shared<MessageSerializer>(payloadSerializers, setExplictNSonTopLevelElements ? getDefaultNamespace() : boost::optional<std::string>())); serializers_.push_back(boost::make_shared<CompressRequestSerializer>()); serializers_.push_back(boost::make_shared<CompressFailureSerializer>()); @@ -84,5 +84,5 @@ std::string XMPPSerializer::serializeHeader(const ProtocolHeader& header) const } -SafeByteArray XMPPSerializer::serializeElement(boost::shared_ptr<Element> element) const { +SafeByteArray XMPPSerializer::serializeElement(boost::shared_ptr<ToplevelElement> element) const { std::vector< boost::shared_ptr<ElementSerializer> >::const_iterator i = std::find_if(serializers_.begin(), serializers_.end(), boost::bind(&ElementSerializer::canSerialize, _1, element)); if (i != serializers_.end()) { diff --git a/Swiften/Serializer/XMPPSerializer.h b/Swiften/Serializer/XMPPSerializer.h index 8727f7a..d1aa386 100644 --- a/Swiften/Serializer/XMPPSerializer.h +++ b/Swiften/Serializer/XMPPSerializer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,5 +10,6 @@ #include <vector> -#include <Swiften/Elements/Element.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Elements/StreamType.h> #include <string> @@ -20,10 +21,10 @@ namespace Swift { class ProtocolHeader; - class XMPPSerializer { + class SWIFTEN_API XMPPSerializer { public: - XMPPSerializer(PayloadSerializerCollection*, StreamType type); + XMPPSerializer(PayloadSerializerCollection*, StreamType type, bool setExplictNSonTopLevelElements); std::string serializeHeader(const ProtocolHeader&) const; - SafeByteArray serializeElement(boost::shared_ptr<Element> stanza) const; + SafeByteArray serializeElement(boost::shared_ptr<ToplevelElement> stanza) const; std::string serializeFooter() const; diff --git a/Swiften/Session/BOSHSessionStream.cpp b/Swiften/Session/BOSHSessionStream.cpp index 237a394..63e35b8 100644 --- a/Swiften/Session/BOSHSessionStream.cpp +++ b/Swiften/Session/BOSHSessionStream.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -42,9 +42,4 @@ BOSHSessionStream::BOSHSessionStream( const SafeString& boshHTTPConnectProxyAuthPassword) : available(false), - payloadParserFactories(payloadParserFactories), - payloadSerializers(payloadSerializers), - tlsContextFactory(tlsContextFactory), - timerFactory(timerFactory), - xmlParserFactory(xmlParserFactory), eventLoop(eventLoop), firstHeader(true) { @@ -52,5 +47,5 @@ BOSHSessionStream::BOSHSessionStream( boost::mt19937 random; boost::uniform_int<unsigned long long> dist(0, (1LL<<53) - 1); - random.seed(time(NULL)); + random.seed(static_cast<unsigned int>(time(NULL))); unsigned long long initialRID = boost::variate_generator<boost::mt19937&, boost::uniform_int<unsigned long long> >(random, dist)(); @@ -62,5 +57,5 @@ BOSHSessionStream::BOSHSessionStream( connectionPool->onBOSHDataWritten.connect(boost::bind(&BOSHSessionStream::handlePoolBOSHDataWritten, this, _1)); - xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, ClientStreamType); + xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, ClientStreamType, true); xmppLayer->onStreamStart.connect(boost::bind(&BOSHSessionStream::handleStreamStartReceived, this, _1)); xmppLayer->onElement.connect(boost::bind(&BOSHSessionStream::handleElementReceived, this, _1)); @@ -92,5 +87,5 @@ void BOSHSessionStream::handlePoolXMPPDataRead(const SafeByteArray& data) { } -void BOSHSessionStream::writeElement(boost::shared_ptr<Element> element) { +void BOSHSessionStream::writeElement(boost::shared_ptr<ToplevelElement> element) { assert(available); xmppLayer->writeElement(element); @@ -130,4 +125,8 @@ Certificate::ref BOSHSessionStream::getPeerCertificate() const { } +std::vector<Certificate::ref> BOSHSessionStream::getPeerCertificateChain() const { + return std::vector<Certificate::ref>(); +} + boost::shared_ptr<CertificateVerificationError> BOSHSessionStream::getPeerCertificateVerificationError() const { return boost::shared_ptr<CertificateVerificationError>(); @@ -158,5 +157,5 @@ void BOSHSessionStream::handleStreamStartReceived(const ProtocolHeader& header) } -void BOSHSessionStream::handleElementReceived(boost::shared_ptr<Element> element) { +void BOSHSessionStream::handleElementReceived(boost::shared_ptr<ToplevelElement> element) { onElementReceived(element); } @@ -214,3 +213,3 @@ void BOSHSessionStream::handlePoolBOSHDataWritten(const SafeByteArray& data) { } -}; +} diff --git a/Swiften/Session/BOSHSessionStream.h b/Swiften/Session/BOSHSessionStream.h index 497d391..e74d534 100644 --- a/Swiften/Session/BOSHSessionStream.h +++ b/Swiften/Session/BOSHSessionStream.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -51,5 +51,5 @@ namespace Swift { virtual void writeHeader(const ProtocolHeader& header); - virtual void writeElement(boost::shared_ptr<Element>); + virtual void writeElement(boost::shared_ptr<ToplevelElement>); virtual void writeFooter(); virtual void writeData(const std::string& data); @@ -62,4 +62,5 @@ namespace Swift { virtual bool isTLSEncrypted(); virtual Certificate::ref getPeerCertificate() const; + virtual std::vector<Certificate::ref> getPeerCertificateChain() const; virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const; virtual ByteArray getTLSFinishMessage() const; @@ -72,5 +73,5 @@ namespace Swift { void handleXMPPError(); void handleStreamStartReceived(const ProtocolHeader&); - void handleElementReceived(boost::shared_ptr<Element>); + void handleElementReceived(boost::shared_ptr<ToplevelElement>); void handlePoolXMPPDataRead(const SafeByteArray& data); void handleXMPPLayerDataWritten(const SafeByteArray& data); @@ -87,9 +88,4 @@ namespace Swift { BOSHConnectionPool* connectionPool; bool available; - PayloadParserFactoryCollection* payloadParserFactories; - PayloadSerializerCollection* payloadSerializers; - TLSContextFactory* tlsContextFactory; - TimerFactory* timerFactory; - XMLParserFactory* xmlParserFactory; XMPPLayer* xmppLayer; ProtocolHeader streamHeader; diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp index b49ffc9..5b4b7d5 100644 --- a/Swiften/Session/BasicSessionStream.cpp +++ b/Swiften/Session/BasicSessionStream.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -31,9 +31,6 @@ BasicSessionStream::BasicSessionStream( available(false), connection(connection), - payloadParserFactories(payloadParserFactories), - payloadSerializers(payloadSerializers), tlsContextFactory(tlsContextFactory), timerFactory(timerFactory), - streamType(streamType), compressionLayer(NULL), tlsLayer(NULL), @@ -58,5 +55,5 @@ BasicSessionStream::~BasicSessionStream() { if (tlsLayer) { - tlsLayer->onError.disconnect(boost::bind(&BasicSessionStream::handleTLSError, this)); + tlsLayer->onError.disconnect(boost::bind(&BasicSessionStream::handleTLSError, this, _1)); tlsLayer->onConnected.disconnect(boost::bind(&BasicSessionStream::handleTLSConnected, this)); delete tlsLayer; @@ -81,5 +78,5 @@ void BasicSessionStream::writeHeader(const ProtocolHeader& header) { } -void BasicSessionStream::writeElement(boost::shared_ptr<Element> element) { +void BasicSessionStream::writeElement(boost::shared_ptr<ToplevelElement> element) { assert(available); xmppLayer->writeElement(element); @@ -130,4 +127,8 @@ Certificate::ref BasicSessionStream::getPeerCertificate() const { } +std::vector<Certificate::ref> BasicSessionStream::getPeerCertificateChain() const { + return tlsLayer->getPeerCertificateChain(); +} + boost::shared_ptr<CertificateVerificationError> BasicSessionStream::getPeerCertificateVerificationError() const { return tlsLayer->getPeerCertificateVerificationError(); @@ -168,5 +169,5 @@ void BasicSessionStream::handleStreamStartReceived(const ProtocolHeader& header) } -void BasicSessionStream::handleElementReceived(boost::shared_ptr<Element> element) { +void BasicSessionStream::handleElementReceived(boost::shared_ptr<ToplevelElement> element) { onElementReceived(element); } @@ -207,3 +208,3 @@ void BasicSessionStream::handleDataWritten(const SafeByteArray& data) { } -}; +} diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h index e1f32f4..e5f8004 100644 --- a/Swiften/Session/BasicSessionStream.h +++ b/Swiften/Session/BasicSessionStream.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -45,5 +45,5 @@ namespace Swift { virtual void writeHeader(const ProtocolHeader& header); - virtual void writeElement(boost::shared_ptr<Element>); + virtual void writeElement(boost::shared_ptr<ToplevelElement>); virtual void writeFooter(); virtual void writeData(const std::string& data); @@ -56,4 +56,6 @@ namespace Swift { virtual bool isTLSEncrypted(); virtual Certificate::ref getPeerCertificate() const; + virtual std::vector<Certificate::ref> getPeerCertificateChain() const; + virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const; virtual ByteArray getTLSFinishMessage() const; @@ -69,5 +71,5 @@ namespace Swift { void handleTLSError(boost::shared_ptr<TLSError>); void handleStreamStartReceived(const ProtocolHeader&); - void handleElementReceived(boost::shared_ptr<Element>); + void handleElementReceived(boost::shared_ptr<ToplevelElement>); void handleDataRead(const SafeByteArray& data); void handleDataWritten(const SafeByteArray& data); @@ -76,9 +78,6 @@ namespace Swift { bool available; boost::shared_ptr<Connection> connection; - PayloadParserFactoryCollection* payloadParserFactories; - PayloadSerializerCollection* payloadSerializers; TLSContextFactory* tlsContextFactory; TimerFactory* timerFactory; - StreamType streamType; XMPPLayer* xmppLayer; ConnectionLayer* connectionLayer; diff --git a/Swiften/Session/Session.cpp b/Swiften/Session/Session.cpp index acc73f1..de54c5f 100644 --- a/Swiften/Session/Session.cpp +++ b/Swiften/Session/Session.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -77,5 +77,5 @@ void Session::initializeStreamStack() { } -void Session::sendElement(boost::shared_ptr<Element> stanza) { +void Session::sendElement(boost::shared_ptr<ToplevelElement> stanza) { xmppLayer->writeElement(stanza); } diff --git a/Swiften/Session/Session.h b/Swiften/Session/Session.h index c937430..63a6a02 100644 --- a/Swiften/Session/Session.h +++ b/Swiften/Session/Session.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -12,6 +12,7 @@ #include <boost/enable_shared_from_this.hpp> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Network/Connection.h> #include <Swiften/StreamStack/ConnectionLayer.h> @@ -28,5 +29,5 @@ namespace Swift { class XMLParserFactory; - class Session : public boost::enable_shared_from_this<Session> { + class SWIFTEN_API Session : public boost::enable_shared_from_this<Session> { public: enum SessionError { @@ -54,5 +55,5 @@ namespace Swift { void finishSession(); - void sendElement(boost::shared_ptr<Element>); + void sendElement(boost::shared_ptr<ToplevelElement>); const JID& getLocalJID() const { @@ -64,5 +65,5 @@ namespace Swift { } - boost::signal<void (boost::shared_ptr<Element>)> onElementReceived; + boost::signal<void (boost::shared_ptr<ToplevelElement>)> onElementReceived; boost::signal<void (const boost::optional<SessionError>&)> onSessionFinished; boost::signal<void (const SafeByteArray&)> onDataWritten; @@ -82,5 +83,5 @@ namespace Swift { virtual void handleSessionStarted() {} virtual void handleSessionFinished(const boost::optional<SessionError>&) {} - virtual void handleElement(boost::shared_ptr<Element>) = 0; + virtual void handleElement(boost::shared_ptr<ToplevelElement>) = 0; virtual void handleStreamStart(const ProtocolHeader&) = 0; diff --git a/Swiften/Session/SessionStream.cpp b/Swiften/Session/SessionStream.cpp index 0d73b63..7378680 100644 --- a/Swiften/Session/SessionStream.cpp +++ b/Swiften/Session/SessionStream.cpp @@ -12,3 +12,3 @@ SessionStream::~SessionStream() { } -}; +} diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h index 32cb6b6..2394295 100644 --- a/Swiften/Session/SessionStream.h +++ b/Swiften/Session/SessionStream.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010-2012 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,6 +11,7 @@ #include <boost/optional.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/ProtocolHeader.h> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Base/Error.h> #include <Swiften/Base/SafeByteArray.h> @@ -20,5 +21,5 @@ namespace Swift { - class SessionStream { + class SWIFTEN_API SessionStream { public: class SessionStreamError : public Swift::Error { @@ -46,5 +47,5 @@ namespace Swift { virtual void writeHeader(const ProtocolHeader& header) = 0; virtual void writeFooter() = 0; - virtual void writeElement(boost::shared_ptr<Element>) = 0; + virtual void writeElement(boost::shared_ptr<ToplevelElement>) = 0; virtual void writeData(const std::string& data) = 0; @@ -68,4 +69,5 @@ namespace Swift { virtual Certificate::ref getPeerCertificate() const = 0; + virtual std::vector<Certificate::ref> getPeerCertificateChain() const = 0; virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const = 0; @@ -73,5 +75,5 @@ namespace Swift { boost::signal<void (const ProtocolHeader&)> onStreamStartReceived; - boost::signal<void (boost::shared_ptr<Element>)> onElementReceived; + boost::signal<void (boost::shared_ptr<ToplevelElement>)> onElementReceived; boost::signal<void (boost::shared_ptr<Error>)> onClosed; boost::signal<void ()> onTLSEncrypted; diff --git a/Swiften/StreamManagement/StanzaAckRequester.h b/Swiften/StreamManagement/StanzaAckRequester.h index e8e4997..591dc17 100644 --- a/Swiften/StreamManagement/StanzaAckRequester.h +++ b/Swiften/StreamManagement/StanzaAckRequester.h @@ -10,9 +10,10 @@ #include <deque> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Stanza.h> #include <Swiften/Base/boost_bsignals.h> namespace Swift { - class StanzaAckRequester { + class SWIFTEN_API StanzaAckRequester { public: StanzaAckRequester(); diff --git a/Swiften/StreamManagement/StanzaAckResponder.h b/Swiften/StreamManagement/StanzaAckResponder.h index b5888b7..d8edd2c 100644 --- a/Swiften/StreamManagement/StanzaAckResponder.h +++ b/Swiften/StreamManagement/StanzaAckResponder.h @@ -9,9 +9,10 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Stanza.h> #include <Swiften/Base/boost_bsignals.h> namespace Swift { - class StanzaAckResponder { + class SWIFTEN_API StanzaAckResponder { public: StanzaAckResponder(); diff --git a/Swiften/StreamStack/HighLayer.h b/Swiften/StreamStack/HighLayer.h index 06b1d25..5669592 100644 --- a/Swiften/StreamStack/HighLayer.h +++ b/Swiften/StreamStack/HighLayer.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> @@ -12,5 +13,5 @@ namespace Swift { class LowLayer; - class HighLayer { + class SWIFTEN_API HighLayer { friend class StreamStack; diff --git a/Swiften/StreamStack/LowLayer.h b/Swiften/StreamStack/LowLayer.h index 00960ea..ee3f7d3 100644 --- a/Swiften/StreamStack/LowLayer.h +++ b/Swiften/StreamStack/LowLayer.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> @@ -12,5 +13,5 @@ namespace Swift { class HighLayer; - class LowLayer { + class SWIFTEN_API LowLayer { friend class StreamStack; diff --git a/Swiften/StreamStack/StreamStack.h b/Swiften/StreamStack/StreamStack.h index 30e17ce..8bbb235 100644 --- a/Swiften/StreamStack/StreamStack.h +++ b/Swiften/StreamStack/StreamStack.h @@ -11,4 +11,5 @@ #include <vector> +#include <Swiften/Base/API.h> #include <Swiften/Elements/Stanza.h> @@ -18,5 +19,5 @@ namespace Swift { class StreamLayer; - class StreamStack { + class SWIFTEN_API StreamStack { public: StreamStack(XMPPLayer* xmppLayer, LowLayer* physicalLayer); diff --git a/Swiften/StreamStack/TLSLayer.cpp b/Swiften/StreamStack/TLSLayer.cpp index 6d416bc..86221ea 100644 --- a/Swiften/StreamStack/TLSLayer.cpp +++ b/Swiften/StreamStack/TLSLayer.cpp @@ -46,4 +46,8 @@ Certificate::ref TLSLayer::getPeerCertificate() const { } +std::vector<Certificate::ref> TLSLayer::getPeerCertificateChain() const { + return context->getPeerCertificateChain(); +} + boost::shared_ptr<CertificateVerificationError> TLSLayer::getPeerCertificateVerificationError() const { return context->getPeerCertificateVerificationError(); diff --git a/Swiften/StreamStack/TLSLayer.h b/Swiften/StreamStack/TLSLayer.h index ce0c89b..24978e0 100644 --- a/Swiften/StreamStack/TLSLayer.h +++ b/Swiften/StreamStack/TLSLayer.h @@ -27,4 +27,5 @@ namespace Swift { Certificate::ref getPeerCertificate() const; + std::vector<Certificate::ref> getPeerCertificateChain() const; boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const; diff --git a/Swiften/StreamStack/UnitTest/StreamStackTest.cpp b/Swiften/StreamStack/UnitTest/StreamStackTest.cpp index 213948a..35146d6 100644 --- a/Swiften/StreamStack/UnitTest/StreamStackTest.cpp +++ b/Swiften/StreamStack/UnitTest/StreamStackTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -127,5 +127,5 @@ class StreamStackTest : public CppUnit::TestFixture { } - void handleElement(boost::shared_ptr<Element>) { + void handleElement(boost::shared_ptr<ToplevelElement>) { ++elementsReceived_; } diff --git a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp index a6098f1..ced9ec3 100644 --- a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp +++ b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -95,9 +95,9 @@ class XMPPLayerTest : public CppUnit::TestFixture { } - void handleElement(boost::shared_ptr<Element>) { + void handleElement(boost::shared_ptr<ToplevelElement>) { ++elementsReceived_; } - void handleElementAndReset(boost::shared_ptr<Element>) { + void handleElementAndReset(boost::shared_ptr<ToplevelElement>) { ++elementsReceived_; testling_->resetParser(); diff --git a/Swiften/StreamStack/XMPPLayer.cpp b/Swiften/StreamStack/XMPPLayer.cpp index 94afcf9..1f06b06 100644 --- a/Swiften/StreamStack/XMPPLayer.cpp +++ b/Swiften/StreamStack/XMPPLayer.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,12 +16,14 @@ XMPPLayer::XMPPLayer( PayloadSerializerCollection* payloadSerializers, XMLParserFactory* xmlParserFactory, - StreamType streamType) : + StreamType streamType, + bool setExplictNSonTopLevelElements) : payloadParserFactories_(payloadParserFactories), payloadSerializers_(payloadSerializers), xmlParserFactory_(xmlParserFactory), + setExplictNSonTopLevelElements_(setExplictNSonTopLevelElements), resetParserAfterParse_(false), inParser_(false) { xmppParser_ = new XMPPParser(this, payloadParserFactories_, xmlParserFactory); - xmppSerializer_ = new XMPPSerializer(payloadSerializers_, streamType); + xmppSerializer_ = new XMPPSerializer(payloadSerializers_, streamType, setExplictNSonTopLevelElements); } @@ -39,5 +41,5 @@ void XMPPLayer::writeFooter() { } -void XMPPLayer::writeElement(boost::shared_ptr<Element> element) { +void XMPPLayer::writeElement(boost::shared_ptr<ToplevelElement> element) { writeDataInternal(xmppSerializer_->serializeElement(element)); } @@ -79,5 +81,5 @@ void XMPPLayer::handleStreamStart(const ProtocolHeader& header) { } -void XMPPLayer::handleElement(boost::shared_ptr<Element> stanza) { +void XMPPLayer::handleElement(boost::shared_ptr<ToplevelElement> stanza) { onElement(stanza); } diff --git a/Swiften/StreamStack/XMPPLayer.h b/Swiften/StreamStack/XMPPLayer.h index 81f0457..13266e4 100644 --- a/Swiften/StreamStack/XMPPLayer.h +++ b/Swiften/StreamStack/XMPPLayer.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -11,7 +11,8 @@ #include <boost/noncopyable.hpp> +#include <Swiften/Base/API.h> #include <Swiften/StreamStack/HighLayer.h> #include <Swiften/Base/SafeByteArray.h> -#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/ToplevelElement.h> #include <Swiften/Elements/StreamType.h> #include <Swiften/Parser/XMPPParserClient.h> @@ -26,5 +27,5 @@ namespace Swift { class BOSHSessionStream; - class XMPPLayer : public XMPPParserClient, public HighLayer, boost::noncopyable { + class SWIFTEN_API XMPPLayer : public XMPPParserClient, public HighLayer, boost::noncopyable { friend class BOSHSessionStream; public: @@ -33,10 +34,11 @@ namespace Swift { PayloadSerializerCollection* payloadSerializers, XMLParserFactory* xmlParserFactory, - StreamType streamType); + StreamType streamType, + bool setExplictNSonTopLevelElements = false); ~XMPPLayer(); void writeHeader(const ProtocolHeader& header); void writeFooter(); - void writeElement(boost::shared_ptr<Element>); + void writeElement(boost::shared_ptr<ToplevelElement>); void writeData(const std::string& data); @@ -49,5 +51,5 @@ namespace Swift { public: boost::signal<void (const ProtocolHeader&)> onStreamStart; - boost::signal<void (boost::shared_ptr<Element>)> onElement; + boost::signal<void (boost::shared_ptr<ToplevelElement>)> onElement; boost::signal<void (const SafeByteArray&)> onWriteData; boost::signal<void (const SafeByteArray&)> onDataRead; @@ -56,5 +58,5 @@ namespace Swift { private: void handleStreamStart(const ProtocolHeader&); - void handleElement(boost::shared_ptr<Element>); + void handleElement(boost::shared_ptr<ToplevelElement>); void handleStreamEnd(); @@ -67,4 +69,5 @@ namespace Swift { XMLParserFactory* xmlParserFactory_; XMPPSerializer* xmppSerializer_; + bool setExplictNSonTopLevelElements_; bool resetParserAfterParse_; bool inParser_; diff --git a/Swiften/StringCodecs/Base64.cpp b/Swiften/StringCodecs/Base64.cpp index e4eaa4e..e1d70a0 100644 --- a/Swiften/StringCodecs/Base64.cpp +++ b/Swiften/StringCodecs/Base64.cpp @@ -1,129 +1,101 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <boost/numeric/conversion/cast.hpp> - -#include <algorithm> - #include <Swiften/StringCodecs/Base64.h> -#include <Swiften/Base/Algorithm.h> -namespace Swift { +#pragma clang diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wold-style-cast" +using namespace Swift; namespace { - template<typename TargetType, typename SourceType> - TargetType base64Encode(const SourceType& s) { - int i; - int len = s.size(); - char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - int a, b, c; + const char* encodeMap = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char decodeMap[255] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255 + }; - TargetType p; - p.resize((len+2)/3*4); - int at = 0; - for( i = 0; i < len; i += 3 ) { - a = ((unsigned char) (s[i]) & 3) << 4; - if(i + 1 < len) { - a += (unsigned char) (s[i + 1]) >> 4; - b = ((unsigned char) (s[i + 1]) & 0xF) << 2; - if(i + 2 < len) { - b += (unsigned char) (s[i + 2]) >> 6; - c = (unsigned char) (s[i + 2]) & 0x3F; + template<typename ResultType, typename InputType> + ResultType encodeDetail(const InputType& input) { + ResultType result; + size_t i = 0; + for (; i < (input.size()/3)*3; i += 3) { + unsigned int c = input[i+2] | (input[i+1]<<8) | (input[i]<<16); + result.push_back(encodeMap[(c&0xFC0000)>>18]); + result.push_back(encodeMap[(c&0x3F000)>>12]); + result.push_back(encodeMap[(c&0xFC0)>>6]); + result.push_back(encodeMap[c&0x3F]); } - else - c = 64; + if (input.size() % 3 == 2) { + unsigned int c = (input[i+1]<<8) | (input[i]<<16); + result.push_back(encodeMap[(c&0xFC0000)>>18]); + result.push_back(encodeMap[(c&0x3F000)>>12]); + result.push_back(encodeMap[(c&0xFC0)>>6]); + result.push_back('='); } - else { - b = c = 64; - } - - p[at++] = tbl[(unsigned char) (s[i]) >> 2]; - p[at++] = tbl[a]; - p[at++] = tbl[b]; - p[at++] = tbl[c]; + else if (input.size() % 3 == 1) { + unsigned int c = input[i]<<16; + result.push_back(encodeMap[(c&0xFC0000)>>18]); + result.push_back(encodeMap[(c&0x3F000)>>12]); + result.push_back('='); + result.push_back('='); } - return p; + return result; } } + std::string Base64::encode(const ByteArray& s) { - return base64Encode<std::string, ByteArray>(s); + return encodeDetail<std::string>(s); } SafeByteArray Base64::encode(const SafeByteArray& s) { - return base64Encode<SafeByteArray, SafeByteArray>(s); + return encodeDetail<SafeByteArray>(s); } ByteArray Base64::decode(const std::string& input) { - std::string inputWithoutNewlines(input); - erase(inputWithoutNewlines, '\n'); - - const std::string& s = inputWithoutNewlines; - ByteArray p; - - // -1 specifies invalid - // 64 specifies eof - // everything else specifies data - - char tbl[] = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, - 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, - 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, - -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, - 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - }; + ByteArray result; - // this should be a multiple of 4 - int len = s.size(); - - if(len % 4) { - return p; + if (input.size() % 4) { + return ByteArray(); } - - p.resize(len / 4 * 3); - - int i; - int at = 0; - - int a, b, c, d; - c = d = 0; - - for( i = 0; i < len; i += 4 ) { - a = tbl[boost::numeric_cast<int>(s[i])]; - b = tbl[boost::numeric_cast<int>(s[i + 1])]; - c = tbl[boost::numeric_cast<int>(s[i + 2])]; - d = tbl[boost::numeric_cast<int>(s[i + 3])]; - if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { - p.resize(0); - return p; + for (size_t i = 0; i < input.size(); i += 4) { + unsigned char c1 = input[i+0]; + unsigned char c2 = input[i+1]; + unsigned char c3 = input[i+2]; + unsigned char c4 = input[i+3]; + if (c3 == '=') { + unsigned int c = (((decodeMap[c1]<<6)|decodeMap[c2])&0xFF0)>>4; + result.push_back(c); } - p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); - p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); - p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); + else if (c4 == '=') { + unsigned int c = (((decodeMap[c1]<<12)|(decodeMap[c2]<<6)|decodeMap[c3])&0x3FFFC)>>2; + result.push_back((c&0xFF00) >> 8); + result.push_back(c&0xFF); } - - if(c & 64) - p.resize(at - 2); - else if(d & 64) - p.resize(at - 1); - - return p; + else { + unsigned int c = (decodeMap[c1]<<18) | (decodeMap[c2]<<12) | (decodeMap[c3]<<6) | decodeMap[c4]; + result.push_back((c&0xFF0000) >> 16); + result.push_back((c&0xFF00) >> 8); + result.push_back(c&0xFF); } - + } + return result; } diff --git a/Swiften/StringCodecs/Base64.h b/Swiften/StringCodecs/Base64.h index 2d67971..7d5ab51 100644 --- a/Swiften/StringCodecs/Base64.h +++ b/Swiften/StringCodecs/Base64.h @@ -8,11 +8,12 @@ #include <vector> - #include <string> + +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> #include <Swiften/Base/SafeByteArray.h> namespace Swift { - class Base64 { + class SWIFTEN_API Base64 { public: static std::string encode(const ByteArray& s); diff --git a/Swiften/StringCodecs/HMAC.h b/Swiften/StringCodecs/HMAC.h deleted file mode 100644 index cf0abfe..0000000 --- a/Swiften/StringCodecs/HMAC.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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/Base/ByteArray.h> -#include <Swiften/Base/Algorithm.h> -#include <cassert> - -namespace Swift { - namespace HMAC_Detail { - template<typename KeyType> struct KeyWrapper; - template<> struct KeyWrapper<ByteArray> { - ByteArray wrap(const ByteArray& hash) const { - return hash; - } - }; - template<> struct KeyWrapper<SafeByteArray> { - SafeByteArray wrap(const ByteArray& hash) const { - return createSafeByteArray(hash); - } - }; - - template<typename Hash, typename KeyType, int BlockSize> - static ByteArray getHMAC(const KeyType& key, const ByteArray& data) { - Hash hash; - - // Create the padded key - KeyType paddedKey(key.size() <= BlockSize ? key : KeyWrapper<KeyType>().wrap(hash(key))); - paddedKey.resize(BlockSize, 0x0); - - // Create the first value - KeyType x(paddedKey); - for (unsigned int i = 0; i < x.size(); ++i) { - x[i] ^= 0x36; - } - append(x, data); - - // Create the second value - KeyType y(paddedKey); - for (unsigned int i = 0; i < y.size(); ++i) { - y[i] ^= 0x5c; - } - append(y, hash(x)); - - return hash(y); - } - }; - - template<typename Hash, int BlockSize> - class HMAC { - private: - - public: - ByteArray operator()(const ByteArray& key, const ByteArray& data) const { - return HMAC_Detail::getHMAC<Hash,ByteArray,BlockSize>(key, data); - } - - ByteArray operator()(const SafeByteArray& key, const ByteArray& data) const { - return HMAC_Detail::getHMAC<Hash,SafeByteArray,BlockSize>(key, data); - } - }; -} diff --git a/Swiften/StringCodecs/HMAC_SHA1.h b/Swiften/StringCodecs/HMAC_SHA1.h deleted file mode 100644 index 8f403c6..0000000 --- a/Swiften/StringCodecs/HMAC_SHA1.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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/StringCodecs/HMAC.h> -#include <Swiften/StringCodecs/SHA1.h> - -namespace Swift { - typedef HMAC<SHA1, 64> HMAC_SHA1; -} diff --git a/Swiften/StringCodecs/HMAC_SHA256.h b/Swiften/StringCodecs/HMAC_SHA256.h deleted file mode 100644 index 2d856cb..0000000 --- a/Swiften/StringCodecs/HMAC_SHA256.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <Swiften/StringCodecs/HMAC.h> -#include <Swiften/StringCodecs/SHA256.h> - -namespace Swift { - typedef HMAC<SHA256, 64> HMAC_SHA256; -} diff --git a/Swiften/StringCodecs/Hexify.cpp b/Swiften/StringCodecs/Hexify.cpp index 668079b..ed2b2a3 100644 --- a/Swiften/StringCodecs/Hexify.cpp +++ b/Swiften/StringCodecs/Hexify.cpp @@ -14,4 +14,6 @@ #include <Swiften/Base/ByteArray.h> +#pragma clang diagnostic ignored "-Wconversion" + namespace Swift { @@ -32,18 +34,37 @@ std::string Hexify::hexify(const ByteArray& data) { } -ByteArray Hexify::unhexify(const std::string& hexstring) { - if (hexstring.size() % 2) { + +static const unsigned char map[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 +}; + +ByteArray Hexify::unhexify(const std::string& in) { + if (in.size() % 2) { return ByteArray(); } - ByteArray result = ByteArray(hexstring.size() / 2); - for (size_t pos = 0; pos < hexstring.size() - 1; pos += 2) { - char c; - c = hexstring[pos]; - int a = (c>='0'&&c<='9') ? c-'0' : (c>='A'&&c<='Z') ? c-'A' + 10 : (c>='a'&&c<='z') ? c-'a' + 10 : -1; - c = hexstring[pos+1]; - int b = (c>='0'&&c<='9') ? c-'0' : (c>='A'&&c<='Z') ? c-'A' + 10 : (c>='a'&&c<='z') ? c-'a' + 10 : -1; - if (a == -1 || b == -1) return ByteArray(); // fail - result[pos/2] = (a<<4) | b; + ByteArray result(in.size() / 2); + for (size_t pos = 0; pos < in.size() - 1; pos += 2) { + unsigned char a = map[static_cast<size_t>(in[pos])]; + unsigned char b = map[static_cast<size_t>(in[pos+1])]; + if (a == 255 || b == 255) { + return ByteArray(); + } + result[pos/2] = (a<<4) | b; } return result; diff --git a/Swiften/StringCodecs/Hexify.h b/Swiften/StringCodecs/Hexify.h index c016448..3b9a751 100644 --- a/Swiften/StringCodecs/Hexify.h +++ b/Swiften/StringCodecs/Hexify.h @@ -7,8 +7,9 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> namespace Swift { - class Hexify { + class SWIFTEN_API Hexify { public: static std::string hexify(unsigned char byte); diff --git a/Swiften/StringCodecs/MD5.cpp b/Swiften/StringCodecs/MD5.cpp deleted file mode 100644 index bd03314..0000000 --- a/Swiften/StringCodecs/MD5.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (c) 2010-2012 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -/* - * This implementation is shamelessly copied from L. Peter Deutsch's - * implementation, and altered to use our own defines and datastructures. - * Original license below. - *//* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - */ - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -#include <Swiften/StringCodecs/MD5.h> - -#include <cassert> -#include <string.h> - -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Base/Platform.h> - -#ifdef SWIFTEN_PLATFORM_WIN32 -#include <Swiften/Base/WindowsRegistry.h> -#endif - -namespace Swift { - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#ifdef SWIFTEN_LITTLE_ENDIAN - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#else - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#endif - - { -#ifdef SWIFTEN_LITTLE_ENDIAN - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#else - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - - for (i = 0; i < 16; ++i, xp += 4) - X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} - -namespace { - template<typename SourceType> - ByteArray getMD5Hash(const SourceType& data) { - ByteArray digest; - digest.resize(16); - - md5_state_t state; - md5_init(&state); - md5_append(&state, reinterpret_cast<const md5_byte_t*>(vecptr(data)), data.size()); - md5_finish(&state, reinterpret_cast<md5_byte_t*>(vecptr(digest))); - - return digest; - } -} - -MD5::MD5() { - state = new md5_state_t; - md5_init(state); -} - -MD5::~MD5() { - delete state; -} - -MD5& MD5::update(const std::vector<unsigned char>& input) { - md5_append(state, reinterpret_cast<const md5_byte_t*>(vecptr(input)), input.size()); - return *this; -} - -std::vector<unsigned char> MD5::getHash() { - ByteArray digest; - digest.resize(16); - md5_finish(state, reinterpret_cast<md5_byte_t*>(vecptr(digest))); - return digest; -} - -ByteArray MD5::getHash(const ByteArray& data) { - return getMD5Hash(data); -} - -ByteArray MD5::getHash(const SafeByteArray& data) { - return getMD5Hash(data); -} - -bool MD5::isAllowedForCrypto() { -#ifdef SWIFTEN_PLATFORM_WIN32 - return !WindowsRegistry::isFIPSEnabled(); -#else - return true; -#endif -} - -} diff --git a/Swiften/StringCodecs/MD5.h b/Swiften/StringCodecs/MD5.h deleted file mode 100644 index 5044173..0000000 --- a/Swiften/StringCodecs/MD5.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2010-2012 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Base/SafeByteArray.h> - -namespace Swift { - struct md5_state_s; - - class MD5 { - public: - MD5(); - ~MD5(); - - MD5& update(const std::vector<unsigned char>& data); - std::vector<unsigned char> getHash(); - - static ByteArray getHash(const ByteArray& data); - static ByteArray getHash(const SafeByteArray& data); - static bool isAllowedForCrypto(); - - private: - md5_state_s* state; - }; -} diff --git a/Swiften/StringCodecs/PBKDF2.h b/Swiften/StringCodecs/PBKDF2.h index 0c04145..ae0bb17 100644 --- a/Swiften/StringCodecs/PBKDF2.h +++ b/Swiften/StringCodecs/PBKDF2.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,16 +9,15 @@ #include <Swiften/Base/SafeByteArray.h> #include <Swiften/Base/Concat.h> +#include <Swiften/Crypto/CryptoProvider.h> namespace Swift { class PBKDF2 { public: - template<typename PRF> - static ByteArray encode(const SafeByteArray& password, const ByteArray& salt, int iterations) { - PRF prf; - ByteArray u = prf(password, concat(salt, createByteArray("\0\0\0\1", 4))); + static ByteArray encode(const SafeByteArray& password, const ByteArray& salt, int iterations, CryptoProvider* crypto) { + ByteArray u = crypto->getHMACSHA1(password, concat(salt, createByteArray("\0\0\0\1", 4))); ByteArray result(u); int i = 1; while (i < iterations) { - u = prf(password, u); + u = crypto->getHMACSHA1(password, u); for (unsigned int j = 0; j < u.size(); ++j) { result[j] ^= u[j]; diff --git a/Swiften/StringCodecs/SHA1.cpp b/Swiften/StringCodecs/SHA1.cpp deleted file mode 100644 index e4081f4..0000000 --- a/Swiften/StringCodecs/SHA1.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/StringCodecs/SHA1.h> - -#include <Swiften/Base/Platform.h> - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -using namespace Swift; - -/* -SHA-1 in C -By Steve Reid <steve@edmweb.com> -100% Public Domain - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#include <stdio.h> -#include <string.h> - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#ifdef SWIFTEN_LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1::Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]) -{ -boost::uint32_t a, b, c, d, e; -typedef union { - boost::uint8_t c[64]; - boost::uint32_t l[16]; -} CHAR64LONG16; -CHAR64LONG16* block; -#ifdef SHA1HANDSOFF -static boost::uint8_t workspace[64]; - block = (CHAR64LONG16*)workspace; - memcpy(block, buffer, 64); -#else - block = reinterpret_cast<CHAR64LONG16*>(buffer); -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -} - - -/* SHA1Init - Initialize new context */ - -void SHA1::Init(SHA1::CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1::Update(SHA1::CTX* context, boost::uint8_t* data, unsigned int len) -{ -unsigned int i, j; - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1::Final(boost::uint8_t digest[20], SHA1::CTX* context) -{ -boost::uint32_t i, j; -boost::uint8_t finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (boost::uint8_t) ((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - Update(context, (boost::uint8_t *)("\200"), 1); - while ((context->count[0] & 504) != 448) { - Update(context, (boost::uint8_t *)("\0"), 1); - } - Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (boost::uint8_t) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - i = j = 0; - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); -#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - Transform(context->state, context->buffer); -#endif -} - -// ----------------------------------------------------------------------------- - -namespace Swift { - -SHA1::SHA1() { - Init(&context); -} - -SHA1& SHA1::update(const std::vector<unsigned char>& input) { - std::vector<unsigned char> inputCopy(input); - Update(&context, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); - return *this; -} - -std::vector<unsigned char> SHA1::getHash() const { - std::vector<unsigned char> digest; - digest.resize(20); - CTX contextCopy(context); - Final((boost::uint8_t*) vecptr(digest), &contextCopy); - return digest; -} - -template<typename Container> -ByteArray SHA1::getHashInternal(const Container& input) { - CTX context; - Init(&context); - - Container inputCopy(input); - Update(&context, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); - - ByteArray digest; - digest.resize(20); - Final((boost::uint8_t*) vecptr(digest), &context); - - return digest; -} - -ByteArray SHA1::getHash(const ByteArray& input) { - return getHashInternal(input); -} - -ByteArray SHA1::getHash(const SafeByteArray& input) { - return getHashInternal(input); -} - - -} diff --git a/Swiften/StringCodecs/SHA1.h b/Swiften/StringCodecs/SHA1.h deleted file mode 100644 index 9edcbb2..0000000 --- a/Swiften/StringCodecs/SHA1.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2010-2012 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#ifdef SWIFTEN_PLATFORM_WIN32 -#include "SHA1_Windows.h" -#else - -#include <vector> -#include <boost/cstdint.hpp> - -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Base/SafeByteArray.h> - -namespace Swift { - class SHA1 { - public: - SHA1(); - - SHA1& update(const std::vector<unsigned char>& data); - std::vector<unsigned char> getHash() const; - - /** - * Equivalent of: - * SHA1().update(data),getHash(), but slightly more efficient and - * convenient. - */ - static ByteArray getHash(const ByteArray& data); - static ByteArray getHash(const SafeByteArray& data); - - ByteArray operator()(const SafeByteArray& data) { - return getHash(data); - } - - ByteArray operator()(const ByteArray& data) { - return getHash(data); - } - - private: - typedef struct { - boost::uint32_t state[5]; - boost::uint32_t count[2]; - boost::uint8_t buffer[64]; - } CTX; - static void Init(CTX* context); - static void Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]); - static void Update(CTX* context, boost::uint8_t* data, unsigned int len); - static void Final(boost::uint8_t digest[20], CTX* context); - - template<typename Container> static ByteArray getHashInternal(const Container& input); - - private: - CTX context; - }; -} - -#endif diff --git a/Swiften/StringCodecs/SHA1_Windows.cpp b/Swiften/StringCodecs/SHA1_Windows.cpp index 8bd3dd2..fef415a 100644 --- a/Swiften/StringCodecs/SHA1_Windows.cpp +++ b/Swiften/StringCodecs/SHA1_Windows.cpp @@ -10,9 +10,22 @@ #include <Swiften/StringCodecs/SHA1_Windows.h> +namespace { + HCRYPTPROV context = 0; + + struct ContextDeleter { + ~ContextDeleter() { + if (context) { + CryptReleaseContext(context, 0); + context = 0; + } + } + } contextDeleter; +} + namespace Swift { -SHA1::SHA1() : hCryptProv(NULL), hHash(NULL) { - bool hasContext = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); - if (!hasContext) { +SHA1::SHA1() : hash(NULL) { + if (!context) { + if (!CryptAcquireContext(&context, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { // DWORD error = GetLastError(); // switch (error) { @@ -20,20 +33,17 @@ SHA1::SHA1() : hCryptProv(NULL), hHash(NULL) { // } // assert(false); - hCryptProv = NULL; + context = 0; + } } - if (!CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash)) { - hHash = NULL; + if (!CryptCreateHash(context, CALG_SHA1, 0, 0, &hash)) { + hash = NULL; } } SHA1::~SHA1() { - if(hHash) { - CryptDestroyHash(hHash); - } - if(hCryptProv) { - CryptReleaseContext(hCryptProv,0); + if (hash) { + CryptDestroyHash(hash); } - } @@ -44,11 +54,8 @@ SHA1& SHA1::update(const std::vector<unsigned char>& data) { SHA1& SHA1::update(const unsigned char* data, size_t dataSize) { - if (!hHash || !hCryptProv) { + if (!hash || !context) { return *this; } - BYTE* byteData = (BYTE *)data; - DWORD dataLength = dataSize; - bool hasHashed = CryptHashData(hHash, byteData, dataLength, 0); -// if (!hasHashed) { + if (!CryptHashData(hash, const_cast<BYTE*>(data), dataSize, 0)) { // DWORD error = GetLastError(); // switch (error) { @@ -57,9 +64,10 @@ SHA1& SHA1::update(const unsigned char* data, size_t dataSize) { // assert(false); // } + } return *this; } std::vector<unsigned char> SHA1::getHash() const { - if (!hHash || !hCryptProv) { + if (!hash || !context) { return std::vector<unsigned char>(); } @@ -67,8 +75,7 @@ std::vector<unsigned char> SHA1::getHash() const { DWORD hashLength = sizeof(DWORD); DWORD hashSize; - CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashSize, &hashLength, 0); + CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &hashLength, 0); result.resize(static_cast<size_t>(hashSize)); - bool hasHashed = CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)vecptr(result), &hashSize, 0); - if (!hasHashed) { + if (!CryptGetHashParam(hash, HP_HASHVAL, vecptr(result), &hashSize, 0)) { // DWORD error = GetLastError(); // switch (error) { diff --git a/Swiften/StringCodecs/SHA1_Windows.h b/Swiften/StringCodecs/SHA1_Windows.h index a24779f..51786ca 100644 --- a/Swiften/StringCodecs/SHA1_Windows.h +++ b/Swiften/StringCodecs/SHA1_Windows.h @@ -13,9 +13,9 @@ #include <Wincrypt.h> - +#include <Swiften/Base/API.h> #include <Swiften/Base/SafeByteArray.h> namespace Swift { - class SHA1 { + class SWIFTEN_API SHA1 { public: SHA1(); @@ -40,6 +40,5 @@ namespace Swift { private: - HCRYPTPROV hCryptProv; - HCRYPTHASH hHash; + HCRYPTHASH hash; }; } diff --git a/Swiften/StringCodecs/SHA256.cpp b/Swiften/StringCodecs/SHA256.cpp deleted file mode 100644 index f92e7af..0000000 --- a/Swiften/StringCodecs/SHA256.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/StringCodecs/SHA256.h> - -#include <cassert> -#include <algorithm> -#include <string.h> - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -using namespace Swift; - -// Copied & adapted from LibTomCrypt, by Tom St Denis, tomstdenis@gmail.com, http://libtom.org -// Substituted some macros by the platform-independent (slower) variants - -#include <stdlib.h> - -#define CRYPT_OK 0 -#define CRYPT_INVALID_ARG -1 -#define LTC_ARGCHK assert - -#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) -#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) - -#define LOAD32H(x, y) \ - { x = ((unsigned long)((y)[0] & 255)<<24) | \ - ((unsigned long)((y)[1] & 255)<<16) | \ - ((unsigned long)((y)[2] & 255)<<8) | \ - ((unsigned long)((y)[3] & 255)); } - -#define STORE32H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ - (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } - -#define STORE64H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ - (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ - (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ - (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } - -/* a simple macro for making hash "process" functions */ -#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \ -int func_name (State * md, const unsigned char *in, unsigned int inlen) \ -{ \ - unsigned long n; \ - int err; \ - LTC_ARGCHK(md != NULL); \ - LTC_ARGCHK(in != NULL || inlen == 0); \ - if (md-> curlen > sizeof(md->buf)) { \ - return CRYPT_INVALID_ARG; \ - } \ - while (inlen > 0) { \ - if (md->curlen == 0 && inlen >= block_size) { \ - if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) { \ - return err; \ - } \ - md-> length += block_size * 8; \ - in += block_size; \ - inlen -= block_size; \ - } else { \ - n = std::min(inlen, (block_size - md-> curlen)); \ - memcpy(md-> buf + md-> curlen, in, (size_t)n); \ - md-> curlen += n; \ - in += n; \ - inlen -= n; \ - if (md-> curlen == block_size) { \ - if ((err = compress_name (md, md-> buf)) != CRYPT_OK) { \ - return err; \ - } \ - md-> length += 8*block_size; \ - md-> curlen = 0; \ - } \ - } \ - } \ - return CRYPT_OK; \ -} - -#ifdef LTC_SMALL_CODE -/* the K array */ -static const boost::uint32_t K[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, - 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, - 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, - 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, - 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, - 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, - 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, - 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, - 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, - 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; -#endif - -/* Various logical functions */ -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) RORc((x),(n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) - -#ifdef LTC_CLEAN_STACK -int SHA256::_compress(State * md, unsigned char *buf) -#else -int SHA256::compress(State * md, unsigned char *buf) -#endif -{ - boost::uint32_t S[8], W[64], t0, t1; -#ifdef LTC_SMALL_CODE - boost::uint32_t t; -#endif - int i; - - /* copy state into S */ - for (i = 0; i < 8; i++) { - S[i] = md->state[i]; - } - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD32H(W[i], buf + (4*i)); - } - - /* fill W[16..63] */ - for (i = 16; i < 64; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } - - /* Compress */ -#ifdef LTC_SMALL_CODE -#define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - - for (i = 0; i < 64; ++i) { - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); - t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; - S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; - } -#else -#define RND(a,b,c,d,e,f,g,h,i,ki) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); - -#undef RND - -#endif - - /* feedback */ - for (i = 0; i < 8; i++) { - md->state[i] = md->state[i] + S[i]; - } - return CRYPT_OK; -} - -#ifdef LTC_CLEAN_STACK -int SHA256::compress(State * md, unsigned char *buf) -{ - int err; - err = SHA256::_compress(md, buf); - burn_stack(sizeof(boost::uint32_t) * 74); - return err; -} -#endif - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return CRYPT_OK if successful -*/ -int SHA256::init(State * md) -{ - LTC_ARGCHK(md != NULL); - - md->curlen = 0; - md->length = 0; - md->state[0] = 0x6A09E667UL; - md->state[1] = 0xBB67AE85UL; - md->state[2] = 0x3C6EF372UL; - md->state[3] = 0xA54FF53AUL; - md->state[4] = 0x510E527FUL; - md->state[5] = 0x9B05688CUL; - md->state[6] = 0x1F83D9ABUL; - md->state[7] = 0x5BE0CD19UL; - return CRYPT_OK; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ -HASH_PROCESS(SHA256::process, SHA256::compress, sha256, 64) - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (32 bytes) - @return CRYPT_OK if successful -*/ -int SHA256::done(State * md, unsigned char *out) -{ - int i; - - LTC_ARGCHK(md != NULL); - LTC_ARGCHK(out != NULL); - - if (md->curlen >= sizeof(md->buf)) { - return CRYPT_INVALID_ARG; - } - - - /* increase the length of the message */ - md->length += md->curlen * 8; - - /* append the '1' bit */ - md->buf[md->curlen++] = (unsigned char)0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->curlen > 56) { - while (md->curlen < 64) { - md->buf[md->curlen++] = (unsigned char)0; - } - SHA256::compress(md, md->buf); - md->curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (md->curlen < 56) { - md->buf[md->curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64H(md->length, md->buf+56); - SHA256::compress(md, md->buf); - - /* copy output */ - for (i = 0; i < 8; i++) { - STORE32H(md->state[i], out+(4*i)); - } -#ifdef LTC_CLEAN_STACK - zeromem(md, sizeof(State)); -#endif - return CRYPT_OK; -} - -// End copied code - -namespace Swift { - -SHA256::SHA256() { - init(&state); -} - -SHA256& SHA256::update(const std::vector<unsigned char>& input) { - std::vector<unsigned char> inputCopy(input); - process(&state, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); - return *this; -} - -std::vector<unsigned char> SHA256::getHash() const { - std::vector<unsigned char> digest; - digest.resize(256/8); - State contextCopy(state); - done(&contextCopy, (boost::uint8_t*) vecptr(digest)); - return digest; -} - -template<typename Container> -ByteArray SHA256::getHashInternal(const Container& input) { - State context; - init(&context); - - Container inputCopy(input); - process(&context, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); - - ByteArray digest; - digest.resize(256/8); - done(&context, (boost::uint8_t*) vecptr(digest)); - - return digest; -} - -ByteArray SHA256::getHash(const ByteArray& input) { - return getHashInternal(input); -} - -ByteArray SHA256::getHash(const SafeByteArray& input) { - return getHashInternal(input); -} - -} diff --git a/Swiften/StringCodecs/SHA256.h b/Swiften/StringCodecs/SHA256.h deleted file mode 100644 index 28a0e05..0000000 --- a/Swiften/StringCodecs/SHA256.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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 <vector> -#include <boost/cstdint.hpp> - -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Base/SafeByteArray.h> - -namespace Swift { - class SHA256 { - public: - SHA256(); - - SHA256& update(const std::vector<unsigned char>& data); - std::vector<unsigned char> getHash() const; - - /** - * Equivalent of: - * SHA256().update(data),getHash(), but slightly more efficient and - * convenient. - */ - static ByteArray getHash(const ByteArray& data); - static ByteArray getHash(const SafeByteArray& data); - - ByteArray operator()(const SafeByteArray& data) { - return getHash(data); - } - - ByteArray operator()(const ByteArray& data) { - return getHash(data); - } - - private: - struct State { - boost::uint64_t length; - boost::uint32_t state[8], curlen; - unsigned char buf[64]; - }; - - static int init(State *md); - static int process(State * md, const unsigned char *in, unsigned int inlen); - static int compress(State *md, unsigned char *buf); - static int done(State * md, unsigned char *out); - - template<typename Container> static ByteArray getHashInternal(const Container& input); - - private: - State state; - }; -} diff --git a/Swiften/StringCodecs/UnitTest/Base64Test.cpp b/Swiften/StringCodecs/UnitTest/Base64Test.cpp index f6a424b..4005047 100644 --- a/Swiften/StringCodecs/UnitTest/Base64Test.cpp +++ b/Swiften/StringCodecs/UnitTest/Base64Test.cpp @@ -17,20 +17,39 @@ using namespace Swift; class Base64Test : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(Base64Test); - CPPUNIT_TEST(testEncode); - CPPUNIT_TEST(testEncode_NonAscii); + CPPUNIT_TEST(testEncodeDecodeAllChars); + CPPUNIT_TEST(testEncodeDecodeOneBytePadding); + CPPUNIT_TEST(testEncodeDecodeTwoBytesPadding); CPPUNIT_TEST(testEncode_NoData); - CPPUNIT_TEST(testDecode); CPPUNIT_TEST(testDecode_NoData); CPPUNIT_TEST_SUITE_END(); public: - void testEncode() { - std::string result(Base64::encode(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"))); - CPPUNIT_ASSERT_EQUAL(std::string("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA="), result); + void testEncodeDecodeAllChars() { + ByteArray input; + for (unsigned char i = 0; i < 255; ++i) { + input.push_back(i); } + std::string result(Base64::encode(input)); - void testEncode_NonAscii() { - std::string result(Base64::encode(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"))); - CPPUNIT_ASSERT_EQUAL(std::string("QgayPKawpkPSDYmwT/WM94uAlu0="), result); + CPPUNIT_ASSERT_EQUAL(std::string("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+"), result); + CPPUNIT_ASSERT_EQUAL(input, Base64::decode(result)); + } + + void testEncodeDecodeOneBytePadding() { + ByteArray input = createByteArray("ABCDE", 5); + + std::string result = Base64::encode(input); + + CPPUNIT_ASSERT_EQUAL(std::string("QUJDREU="), result); + CPPUNIT_ASSERT_EQUAL(input, Base64::decode(result)); + } + + void testEncodeDecodeTwoBytesPadding() { + ByteArray input = createByteArray("ABCD", 4); + + std::string result = Base64::encode(input); + + CPPUNIT_ASSERT_EQUAL(std::string("QUJDRA=="), result); + CPPUNIT_ASSERT_EQUAL(input, Base64::decode(result)); } @@ -40,9 +59,4 @@ class Base64Test : public CppUnit::TestFixture { } - void testDecode() { - ByteArray result(Base64::decode("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA=")); - CPPUNIT_ASSERT_EQUAL(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"), result); - } - void testDecode_NoData() { ByteArray result(Base64::decode("")); diff --git a/Swiften/StringCodecs/UnitTest/HMACTest.cpp b/Swiften/StringCodecs/UnitTest/HMACTest.cpp deleted file mode 100644 index 50b1330..0000000 --- a/Swiften/StringCodecs/UnitTest/HMACTest.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Base/ByteArray.h> -#include <QA/Checker/IO.h> - -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> - -#include <Swiften/Base/ByteArray.h> -#include <Swiften/StringCodecs/HMAC_SHA1.h> -#include <Swiften/StringCodecs/HMAC_SHA256.h> - -using namespace Swift; - -class HMACTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(HMACTest); - CPPUNIT_TEST(testGetResult); - CPPUNIT_TEST(testGetResult_KeyLongerThanBlockSize); - CPPUNIT_TEST(testGetResult_RFC4231_1); - CPPUNIT_TEST(testGetResult_RFC4231_7); - CPPUNIT_TEST_SUITE_END(); - - public: - void testGetResult() { - ByteArray result(HMAC_SHA1()(createSafeByteArray("foo"), createByteArray("foobar"))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\xa4\xee\xba\x8e\x63\x3d\x77\x88\x69\xf5\x68\xd0\x5a\x1b\x3d\xc7\x2b\xfd\x4\xdd"), result); - } - - void testGetResult_KeyLongerThanBlockSize() { - ByteArray result(HMAC_SHA1()(createSafeByteArray("---------|---------|---------|---------|---------|----------|---------|"), createByteArray("foobar"))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\xd6""n""\x8f""P|1""\xd3"",""\x6"" ""\xb9\xe3""gg""\x8e\xcf"" ]+""\xa"), result); - } - - void testGetResult_RFC4231_1() { - ByteArray result(HMAC_SHA256()(createSafeByteArray("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20), createByteArray("Hi There"))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7", 32), result); - } - - void testGetResult_RFC4231_7() { - ByteArray result(HMAC_SHA256()(createSafeByteArray("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131), createByteArray("This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2", 32), result); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(HMACTest); diff --git a/Swiften/StringCodecs/UnitTest/MD5Test.cpp b/Swiften/StringCodecs/UnitTest/MD5Test.cpp deleted file mode 100644 index c62c46a..0000000 --- a/Swiften/StringCodecs/UnitTest/MD5Test.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Base/ByteArray.h> -#include <QA/Checker/IO.h> - -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> - -#include <Swiften/StringCodecs/MD5.h> -#include <Swiften/Base/ByteArray.h> - -using namespace Swift; - -class MD5Test : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(MD5Test); - CPPUNIT_TEST(testGetHash_Empty); - CPPUNIT_TEST(testGetHash_Alphabet); - CPPUNIT_TEST(testIncrementalTest); - CPPUNIT_TEST_SUITE_END(); - - public: - void testGetHash_Empty() { - ByteArray result(MD5::getHash(createByteArray(""))); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e", 16), result); - } - - void testGetHash_Alphabet() { - ByteArray result(MD5::getHash(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"))); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", 16), result); - } - - void testIncrementalTest() { - MD5 testling; - testling.update(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); - testling.update(createByteArray("abcdefghijklmnopqrstuvwxyz0123456789")); - - ByteArray result = testling.getHash(); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", 16), result); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(MD5Test); diff --git a/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp b/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp index 608ca62..1172679 100644 --- a/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp +++ b/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,5 +13,6 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/StringCodecs/PBKDF2.h> -#include <Swiften/StringCodecs/HMAC_SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -25,6 +26,10 @@ class PBKDF2Test : public CppUnit::TestFixture { public: + void setUp() { + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); + } + void testGetResult_I1() { - ByteArray result(PBKDF2::encode<HMAC_SHA1 >(createSafeByteArray("password"), createByteArray("salt"), 1)); + ByteArray result(PBKDF2::encode(createSafeByteArray("password"), createByteArray("salt"), 1, crypto.get())); CPPUNIT_ASSERT_EQUAL(createByteArray("\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6"), result); @@ -32,5 +37,5 @@ class PBKDF2Test : public CppUnit::TestFixture { void testGetResult_I2() { - ByteArray result(PBKDF2::encode<HMAC_SHA1 >(createSafeByteArray("password"), createByteArray("salt"), 2)); + ByteArray result(PBKDF2::encode(createSafeByteArray("password"), createByteArray("salt"), 2, crypto.get())); CPPUNIT_ASSERT_EQUAL(createByteArray("\xea\x6c\x1\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57"), result); @@ -38,8 +43,11 @@ class PBKDF2Test : public CppUnit::TestFixture { void testGetResult_I4096() { - ByteArray result(PBKDF2::encode<HMAC_SHA1 >(createSafeByteArray("password"), createByteArray("salt"), 4096)); + ByteArray result(PBKDF2::encode(createSafeByteArray("password"), createByteArray("salt"), 4096, crypto.get())); CPPUNIT_ASSERT_EQUAL(createByteArray("\x4b\x00\x79\x1\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20), result); } + + private: + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp deleted file mode 100644 index cb1a6f4..0000000 --- a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Base/ByteArray.h> -#include <QA/Checker/IO.h> - -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> - -#include <Swiften/StringCodecs/SHA1.h> - -using namespace Swift; - -class SHA1Test : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(SHA1Test); - CPPUNIT_TEST(testGetHash); - CPPUNIT_TEST(testGetHash_TwoUpdates); - //CPPUNIT_TEST(testGetHash_TwoGetHash); - CPPUNIT_TEST(testGetHash_NoData); - //CPPUNIT_TEST(testGetHash_InterleavedUpdate); - CPPUNIT_TEST(testGetHashStatic); - CPPUNIT_TEST(testGetHashStatic_Twice); - CPPUNIT_TEST(testGetHashStatic_NoData); - CPPUNIT_TEST_SUITE_END(); - - public: - void testGetHash() { - SHA1 sha; - sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); - } - - void testGetHash_TwoUpdates() { - SHA1 sha; - sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); - sha.update(createByteArray("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); - } - - void testGetHash_TwoGetHash() { - SHA1 sha; - sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); - - sha.getHash(); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); - } - - void testGetHash_InterleavedUpdate() { - SHA1 sha; - - sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); - sha.getHash(); - sha.update(createByteArray("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); - } - - - void testGetHash_NoData() { - SHA1 sha; - sha.update(std::vector<unsigned char>()); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), sha.getHash()); - } - - void testGetHashStatic() { - ByteArray result(SHA1::getHash(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<"))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); - } - - - void testGetHashStatic_Twice() { - ByteArray input(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); - SHA1::getHash(input); - ByteArray result(SHA1::getHash(input)); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); - } - - void testGetHashStatic_NoData() { - ByteArray result(SHA1::getHash(ByteArray())); - - CPPUNIT_ASSERT_EQUAL(createByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), result); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(SHA1Test); diff --git a/Swiften/StringCodecs/UnitTest/SHA256Test.cpp b/Swiften/StringCodecs/UnitTest/SHA256Test.cpp deleted file mode 100644 index 5bcdd11..0000000 --- a/Swiften/StringCodecs/UnitTest/SHA256Test.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Base/ByteArray.h> -#include <QA/Checker/IO.h> - -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> - -#include <Swiften/StringCodecs/SHA256.h> - -using namespace Swift; - -class SHA256Test : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(SHA256Test); - CPPUNIT_TEST(testGetHashStatic_Empty); - CPPUNIT_TEST(testGetHashStatic_Small); - CPPUNIT_TEST(testGetHashStatic_Large); - CPPUNIT_TEST_SUITE_END(); - - public: - void testGetHashStatic_Empty() { - ByteArray result(SHA256::getHash(createByteArray(""))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\xe3\xb0\xc4" "B" "\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99" "o" "\xb9" "$'" "\xae" "A" "\xe4" "d" "\x9b\x93" "L" "\xa4\x95\x99\x1b" "xR" "\xb8" "U", 32), result); - } - - void testGetHashStatic_Small() { - ByteArray result(SHA256::getHash(createByteArray("abc"))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad", 32), result); - } - - void testGetHashStatic_Large() { - ByteArray result(SHA256::getHash(createByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1", 32), result); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(SHA256Test); diff --git a/Swiften/Swiften.rc b/Swiften/Swiften.rc new file mode 100644 index 0000000..2a67a34 --- /dev/null +++ b/Swiften/Swiften.rc @@ -0,0 +1,35 @@ +#include "Swiften/Version.h" + +1 VERSIONINFO + FILEVERSION SWIFTEN_VERSION_MAJOR, SWIFTEN_VERSION_MINOR, SWIFTEN_VERSION_PATCH + PRODUCTVERSION 1,2,3 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Swiften XMPP Library\0" + VALUE "CompanyName", "Swift\0" + VALUE "FileDescription", "Swiften\0" + VALUE "FileVersion", SWIFTEN_VERSION_STRING + VALUE "InternalName", "Swiften\0" + VALUE "LegalCopyright", "Copyright \251 " SWIFTEN_COPYRIGHT_YEAR " Swift Team\0" + VALUE "OriginalFilename", SWIFTEN_LIBRARY_FILE + VALUE "ProductName", "Swiften\0" + VALUE "ProductVersion", SWIFTEN_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Swiften/TLS/BlindCertificateTrustChecker.h b/Swiften/TLS/BlindCertificateTrustChecker.h index 3177322..d91ec25 100644 --- a/Swiften/TLS/BlindCertificateTrustChecker.h +++ b/Swiften/TLS/BlindCertificateTrustChecker.h @@ -20,5 +20,5 @@ namespace Swift { class BlindCertificateTrustChecker : public CertificateTrustChecker { public: - virtual bool isCertificateTrusted(Certificate::ref) { + virtual bool isCertificateTrusted(const std::vector<Certificate::ref>&) { return true; } diff --git a/Swiften/TLS/CAPICertificate.h b/Swiften/TLS/CAPICertificate.h index 5f24b7e..aebfb41 100644 --- a/Swiften/TLS/CAPICertificate.h +++ b/Swiften/TLS/CAPICertificate.h @@ -7,4 +7,5 @@ #pragma once +#include <Swiften/Base/API.h> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/SafeByteArray.h> @@ -22,5 +23,5 @@ namespace Swift { class TimerFactory; - class CAPICertificate : public Swift::CertificateWithKey { + class SWIFTEN_API CAPICertificate : public Swift::CertificateWithKey { public: CAPICertificate(const std::string& capiUri, TimerFactory* timerFactory); diff --git a/Swiften/TLS/Certificate.cpp b/Swiften/TLS/Certificate.cpp index a796463..ec268c8 100644 --- a/Swiften/TLS/Certificate.cpp +++ b/Swiften/TLS/Certificate.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,5 +9,5 @@ #include <sstream> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/StringCodecs/Hexify.h> @@ -20,6 +20,6 @@ Certificate::~Certificate() { } -std::string Certificate::getSHA1Fingerprint() const { - ByteArray hash = SHA1::getHash(toDER()); +std::string Certificate::getSHA1Fingerprint(Certificate::ref certificate, CryptoProvider* crypto) { + ByteArray hash = crypto->getSHA1Hash(certificate->toDER()); std::ostringstream s; for (size_t i = 0; i < hash.size(); ++i) { diff --git a/Swiften/TLS/Certificate.h b/Swiften/TLS/Certificate.h index ec59a39..f558c12 100644 --- a/Swiften/TLS/Certificate.h +++ b/Swiften/TLS/Certificate.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -10,8 +10,11 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/Base/ByteArray.h> namespace Swift { - class Certificate { + class CryptoProvider; + + class SWIFTEN_API Certificate { public: typedef boost::shared_ptr<Certificate> ref; @@ -32,5 +35,5 @@ namespace Swift { virtual ByteArray toDER() const = 0; - virtual std::string getSHA1Fingerprint() const; + static std::string getSHA1Fingerprint(Certificate::ref, CryptoProvider* crypto); protected: diff --git a/Swiften/TLS/CertificateFactory.h b/Swiften/TLS/CertificateFactory.h index 3e94082..e8971c3 100644 --- a/Swiften/TLS/CertificateFactory.h +++ b/Swiften/TLS/CertificateFactory.h @@ -14,5 +14,5 @@ namespace Swift { virtual ~CertificateFactory(); - virtual Certificate::ref createCertificateFromDER(const ByteArray& der) = 0; + virtual Certificate* createCertificateFromDER(const ByteArray& der) = 0; }; } diff --git a/Swiften/TLS/CertificateTrustChecker.h b/Swiften/TLS/CertificateTrustChecker.h index 06c0c32..4ec0b39 100644 --- a/Swiften/TLS/CertificateTrustChecker.h +++ b/Swiften/TLS/CertificateTrustChecker.h @@ -8,6 +8,8 @@ #include <boost/shared_ptr.hpp> - #include <string> +#include <vector> + +#include <Swiften/Base/API.h> #include <Swiften/TLS/Certificate.h> @@ -16,14 +18,17 @@ namespace Swift { * A class to implement a check for certificate trust. */ - class CertificateTrustChecker { + class SWIFTEN_API CertificateTrustChecker { public: virtual ~CertificateTrustChecker(); /** - * This method is called to find out whether a certificate is + * This method is called to find out whether a certificate (chain) is * trusted. This usually happens when a certificate's validation * fails, to check whether to proceed with the connection or not. + * + * certificateChain contains the chain of certificates. The first certificate + * is the subject certificate. */ - virtual bool isCertificateTrusted(Certificate::ref certificate) = 0; + virtual bool isCertificateTrusted(const std::vector<Certificate::ref>& certificateChain) = 0; }; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp index 76b8bb9..d654787 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -14,4 +14,7 @@ #pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wcast-align" +#pragma clang diagnostic ignored "-Wsign-conversion" namespace Swift { @@ -56,5 +59,5 @@ void OpenSSLCertificate::parse() { ByteArray subjectNameData; subjectNameData.resize(256); - X509_NAME_oneline(X509_get_subject_name(cert.get()), reinterpret_cast<char*>(vecptr(subjectNameData)), subjectNameData.size()); + X509_NAME_oneline(X509_get_subject_name(cert.get()), reinterpret_cast<char*>(vecptr(subjectNameData)), static_cast<unsigned int>(subjectNameData.size())); this->subjectName = byteArrayToString(subjectNameData); diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h index 52f134c..98376ae 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,6 +13,6 @@ namespace Swift { class OpenSSLCertificateFactory : public CertificateFactory { public: - virtual Certificate::ref createCertificateFromDER(const ByteArray& der) { - return Certificate::ref(new OpenSSLCertificate(der)); + virtual Certificate* createCertificateFromDER(const ByteArray& der) { + return new OpenSSLCertificate(der); } }; diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp index 8c03052..54fb7bd 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -16,5 +16,5 @@ #include <boost/smart_ptr/make_shared.hpp> -#if defined(SWIFTEN_PLATFORM_MACOSX) && OPENSSL_VERSION_NUMBER < 0x00908000 +#if defined(SWIFTEN_PLATFORM_MACOSX) #include <Security/Security.h> #endif @@ -26,4 +26,8 @@ #pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wcast-align" +#pragma clang diagnostic ignored "-Wsign-conversion" namespace Swift { @@ -32,5 +36,5 @@ static const int MAX_FINISHED_SIZE = 4096; static const int SSL_READ_BUFFERSIZE = 8192; -void freeX509Stack(STACK_OF(X509)* stack) { +static void freeX509Stack(STACK_OF(X509)* stack) { sk_X509_free(stack); } @@ -38,6 +42,13 @@ void freeX509Stack(STACK_OF(X509)* stack) { OpenSSLContext::OpenSSLContext() : state_(Start), context_(0), handle_(0), readBIO_(0), writeBIO_(0) { ensureLibraryInitialized(); - context_ = SSL_CTX_new(TLSv1_client_method()); + context_ = SSL_CTX_new(SSLv23_client_method()); + SSL_CTX_set_options(context_, SSL_OP_NO_SSLv2); + // TODO: implement CRL checking + // TODO: download CRL (HTTP transport) + // TODO: cache CRL downloads for configurable time period + + // TODO: implement OCSP support + // TODO: handle OCSP stapling see https://www.rfc-editor.org/rfc/rfc4366.txt // Load system certs #if defined(SWIFTEN_PLATFORM_WINDOWS) @@ -59,7 +70,11 @@ OpenSSLContext::OpenSSLContext() : state_(Start), context_(0), handle_(0), readB #elif !defined(SWIFTEN_PLATFORM_MACOSX) SSL_CTX_load_verify_locations(context_, NULL, "/etc/ssl/certs"); -#elif defined(SWIFTEN_PLATFORM_MACOSX) && OPENSSL_VERSION_NUMBER < 0x00908000 +#elif defined(SWIFTEN_PLATFORM_MACOSX) // On Mac OS X 10.5 (OpenSSL < 0.9.8), OpenSSL does not automatically look in the system store. - // We therefore add all certs from the system store ourselves. + // On Mac OS X 10.6 (OpenSSL >= 0.9.8), OpenSSL *does* look in the system store to determine trust. + // However, if there is a certificate error, it will always emit the "Invalid CA" error if we didn't add + // the certificates first. See + // http://opensource.apple.com/source/OpenSSL098/OpenSSL098-27/src/crypto/x509/x509_vfy_apple.c + // to understand why. We therefore add all certs from the system store ourselves. X509_STORE* store = SSL_CTX_get_cert_store(context_); CFArrayRef anchorCertificates; @@ -206,5 +221,7 @@ bool OpenSSLContext::setClientCertificate(CertificateWithKey::ref certificate) { EVP_PKEY* privateKeyPtr = 0; STACK_OF(X509)* caCertsPtr = 0; - int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(pkcs12Certificate->getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr); + SafeByteArray password(pkcs12Certificate->getPassword()); + password.push_back(0); + int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(password)), &privateKeyPtr, &certPtr, &caCertsPtr); if (result != 1) { return false; @@ -227,12 +244,14 @@ bool OpenSSLContext::setClientCertificate(CertificateWithKey::ref certificate) { } -Certificate::ref OpenSSLContext::getPeerCertificate() const { - boost::shared_ptr<X509> x509Cert(SSL_get_peer_certificate(handle_), X509_free); - if (x509Cert) { - return boost::make_shared<OpenSSLCertificate>(x509Cert); - } - else { - return Certificate::ref(); +std::vector<Certificate::ref> OpenSSLContext::getPeerCertificateChain() const { + std::vector<Certificate::ref> result; + STACK_OF(X509)* chain = SSL_get_peer_cert_chain(handle_); + for (int i = 0; i < sk_X509_num(chain); ++i) { + boost::shared_ptr<X509> x509Cert(X509_dup(sk_X509_value(chain, i)), X509_free); + + Certificate::ref cert = boost::make_shared<OpenSSLCertificate>(x509Cert); + result.push_back(cert); } + return result; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h index d8d0d2f..d4327ca 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContext.h +++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h @@ -28,5 +28,5 @@ namespace Swift { void handleDataFromApplication(const SafeByteArray&); - Certificate::ref getPeerCertificate() const; + std::vector<Certificate::ref> getPeerCertificateChain() const; boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const; diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp index 6cd3c83..671cba7 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp @@ -19,8 +19,10 @@ TLSContext* OpenSSLContextFactory::createTLSContext() { } -void OpenSSLContextFactory::setCheckCertificateRevocation(bool) { +void OpenSSLContextFactory::setCheckCertificateRevocation(bool check) { + if (check) { assert(false); SWIFT_LOG(warning) << "CRL Checking not supported for OpenSSL" << std::endl; } +} diff --git a/Swiften/TLS/PKCS12Certificate.h b/Swiften/TLS/PKCS12Certificate.h index 2f70456..2d4c2e5 100644 --- a/Swiften/TLS/PKCS12Certificate.h +++ b/Swiften/TLS/PKCS12Certificate.h @@ -9,4 +9,5 @@ #include <Swiften/Base/SafeByteArray.h> #include <Swiften/TLS/CertificateWithKey.h> +#include <boost/filesystem/path.hpp> namespace Swift { @@ -15,5 +16,5 @@ namespace Swift { PKCS12Certificate() {} - PKCS12Certificate(const std::string& filename, const SafeByteArray& password) : password_(password) { + PKCS12Certificate(const boost::filesystem::path& filename, const SafeByteArray& password) : password_(password) { readByteArrayFromFile(data_, filename); } diff --git a/Swiften/TLS/PlatformTLSFactories.h b/Swiften/TLS/PlatformTLSFactories.h index 605db31..850d6f9 100644 --- a/Swiften/TLS/PlatformTLSFactories.h +++ b/Swiften/TLS/PlatformTLSFactories.h @@ -7,9 +7,11 @@ #pragma once +#include <Swiften/Base/API.h> + namespace Swift { class TLSContextFactory; class CertificateFactory; - class PlatformTLSFactories { + class SWIFTEN_API PlatformTLSFactories { public: PlatformTLSFactories(); diff --git a/Swiften/TLS/Schannel/SchannelCertificateFactory.h b/Swiften/TLS/Schannel/SchannelCertificateFactory.h index d09bb54..5a2b208 100644 --- a/Swiften/TLS/Schannel/SchannelCertificateFactory.h +++ b/Swiften/TLS/Schannel/SchannelCertificateFactory.h @@ -13,6 +13,6 @@ namespace Swift { class SchannelCertificateFactory : public CertificateFactory { public: - virtual Certificate::ref createCertificateFromDER(const ByteArray& der) { - return Certificate::ref(new SchannelCertificate(der)); + virtual Certificate* createCertificateFromDER(const ByteArray& der) { + return new SchannelCertificate(der); } }; diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp index 641568d..b4b2843 100644 --- a/Swiften/TLS/Schannel/SchannelContext.cpp +++ b/Swiften/TLS/Schannel/SchannelContext.cpp @@ -626,8 +626,29 @@ void SchannelContext::handleCertificateCardRemoved() { //------------------------------------------------------------------------ -Certificate::ref SchannelContext::getPeerCertificate() const { +std::vector<Certificate::ref> SchannelContext::getPeerCertificateChain() const { + std::vector<Certificate::ref> certificateChain; ScopedCertContext pServerCert; + ScopedCertContext pIssuerCert; + ScopedCertContext pCurrentCert; SECURITY_STATUS status = QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset()); - return status == SEC_E_OK ? boost::make_shared<SchannelCertificate>(pServerCert) : SchannelCertificate::ref(); + + if (status != SEC_E_OK) { + return certificateChain; + } + certificateChain.push_back(boost::make_shared<SchannelCertificate>(pServerCert)); + + pCurrentCert = pServerCert; + while(pCurrentCert.GetPointer()) { + DWORD dwVerificationFlags = 0; + pIssuerCert = CertGetIssuerCertificateFromStore(pServerCert->hCertStore, pCurrentCert, NULL, &dwVerificationFlags ); + if (!(*pIssuerCert.GetPointer())) { + break; + } + certificateChain.push_back(boost::make_shared<SchannelCertificate>(pIssuerCert)); + + pCurrentCert = pIssuerCert; + pIssuerCert = NULL; + } + return certificateChain; } diff --git a/Swiften/TLS/Schannel/SchannelContext.h b/Swiften/TLS/Schannel/SchannelContext.h index 587d0e7..8603498 100644 --- a/Swiften/TLS/Schannel/SchannelContext.h +++ b/Swiften/TLS/Schannel/SchannelContext.h @@ -51,5 +51,5 @@ namespace Swift virtual void handleDataFromApplication(const SafeByteArray& data); - virtual Certificate::ref getPeerCertificate() const; + virtual std::vector<Certificate::ref> getPeerCertificateChain() const; virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const; diff --git a/Swiften/TLS/ServerIdentityVerifier.cpp b/Swiften/TLS/ServerIdentityVerifier.cpp index a908ad0..0608a03 100644 --- a/Swiften/TLS/ServerIdentityVerifier.cpp +++ b/Swiften/TLS/ServerIdentityVerifier.cpp @@ -10,11 +10,15 @@ #include <Swiften/Base/foreach.h> -#include <Swiften/IDN/IDNA.h> +#include <Swiften/IDN/IDNConverter.h> namespace Swift { -ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid) { +ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter) : domainValid(false) { domain = jid.getDomain(); - encodedDomain = IDNA::getEncoded(domain); + boost::optional<std::string> domainResult = idnConverter->getIDNAEncoded(domain); + if (!!domainResult) { + encodedDomain = *domainResult; + domainValid = true; + } } @@ -22,4 +26,7 @@ bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) { bool hasSAN = false; + if (certificate == NULL) { + return false; + } // DNS names std::vector<std::string> dnsNames = certificate->getDNSNames(); @@ -65,9 +72,12 @@ bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) { bool ServerIdentityVerifier::matchesDomain(const std::string& s) const { + if (!domainValid) { + return false; + } if (boost::starts_with(s, "*.")) { std::string matchString(s.substr(2, s.npos)); std::string matchDomain = encodedDomain; - int dotIndex = matchDomain.find('.'); - if (dotIndex >= 0) { + size_t dotIndex = matchDomain.find('.'); + if (dotIndex != matchDomain.npos) { matchDomain = matchDomain.substr(dotIndex + 1, matchDomain.npos); } diff --git a/Swiften/TLS/ServerIdentityVerifier.h b/Swiften/TLS/ServerIdentityVerifier.h index b09abd9..ea08749 100644 --- a/Swiften/TLS/ServerIdentityVerifier.h +++ b/Swiften/TLS/ServerIdentityVerifier.h @@ -10,11 +10,14 @@ #include <string> +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <Swiften/TLS/Certificate.h> namespace Swift { - class ServerIdentityVerifier { + class IDNConverter; + + class SWIFTEN_API ServerIdentityVerifier { public: - ServerIdentityVerifier(const JID& jid); + ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter); bool certificateVerifies(Certificate::ref); @@ -27,4 +30,5 @@ namespace Swift { std::string domain; std::string encodedDomain; + bool domainValid; }; } diff --git a/Swiften/TLS/TLSContext.cpp b/Swiften/TLS/TLSContext.cpp index 026ae70..d461d91 100644 --- a/Swiften/TLS/TLSContext.cpp +++ b/Swiften/TLS/TLSContext.cpp @@ -12,3 +12,8 @@ TLSContext::~TLSContext() { } +Certificate::ref TLSContext::getPeerCertificate() const { + std::vector<Certificate::ref> chain = getPeerCertificateChain(); + return chain.empty() ? Certificate::ref() : chain[0]; +} + } diff --git a/Swiften/TLS/TLSContext.h b/Swiften/TLS/TLSContext.h index 5640fe1..5fee021 100644 --- a/Swiften/TLS/TLSContext.h +++ b/Swiften/TLS/TLSContext.h @@ -29,5 +29,6 @@ namespace Swift { virtual void handleDataFromApplication(const SafeByteArray&) = 0; - virtual Certificate::ref getPeerCertificate() const = 0; + Certificate::ref getPeerCertificate() const; + virtual std::vector<Certificate::ref> getPeerCertificateChain() const = 0; virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const = 0; diff --git a/Swiften/TLS/UnitTest/CertificateTest.cpp b/Swiften/TLS/UnitTest/CertificateTest.cpp index 5df5639..3352118 100644 --- a/Swiften/TLS/UnitTest/CertificateTest.cpp +++ b/Swiften/TLS/UnitTest/CertificateTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -13,4 +13,6 @@ #include <Swiften/TLS/Certificate.h> #include <Swiften/TLS/SimpleCertificate.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -26,5 +28,5 @@ class CertificateTest : public CppUnit::TestFixture { testling->setDER(createByteArray("abcdefg")); - CPPUNIT_ASSERT_EQUAL(std::string("2f:b5:e1:34:19:fc:89:24:68:65:e7:a3:24:f4:76:ec:62:4e:87:40"), testling->getSHA1Fingerprint()); + CPPUNIT_ASSERT_EQUAL(std::string("2f:b5:e1:34:19:fc:89:24:68:65:e7:a3:24:f4:76:ec:62:4e:87:40"), Certificate::getSHA1Fingerprint(testling, boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()).get())); } }; diff --git a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp index bd68c84..e974eb7 100644 --- a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp +++ b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp @@ -13,4 +13,6 @@ #include <Swiften/TLS/ServerIdentityVerifier.h> #include <Swiften/TLS/SimpleCertificate.h> +#include <Swiften/IDN/IDNConverter.h> +#include <Swiften/IDN/PlatformIDNConverter.h> using namespace Swift; @@ -37,6 +39,10 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { public: + void setUp() { + idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); + } + void testCertificateVerifies_WithoutMatchingDNSName() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addDNSName("foo.com"); @@ -46,5 +52,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingDNSName() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addDNSName("bar.com"); @@ -54,5 +60,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithSecondMatchingDNSName() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addDNSName("foo.com"); @@ -63,5 +69,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingInternationalDNSName() { - ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7on.com/baz")); + ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7on.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addDNSName("xn--tronon-zua.com"); @@ -71,5 +77,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingDNSNameWithWildcard() { - ServerIdentityVerifier testling(JID("foo@im.bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addDNSName("*.bar.com"); @@ -79,5 +85,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingDNSNameWithWildcardMatchingNoComponents() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addDNSName("*.bar.com"); @@ -87,5 +93,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithDNSNameWithWildcardMatchingTwoComponents() { - ServerIdentityVerifier testling(JID("foo@xmpp.im.bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@xmpp.im.bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addDNSName("*.bar.com"); @@ -95,5 +101,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingSRVNameWithoutService() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addSRVName("bar.com"); @@ -103,5 +109,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingSRVNameWithService() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addSRVName("_xmpp-client.bar.com"); @@ -111,5 +117,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingSRVNameWithServiceAndWildcard() { - ServerIdentityVerifier testling(JID("foo@im.bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addSRVName("_xmpp-client.*.bar.com"); @@ -119,5 +125,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingSRVNameWithDifferentService() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addSRVName("_xmpp-server.bar.com"); @@ -127,5 +133,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingXmppAddr() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addXMPPAddress("bar.com"); @@ -135,5 +141,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingXmppAddrWithWildcard() { - ServerIdentityVerifier testling(JID("foo@im.bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addXMPPAddress("*.bar.com"); @@ -143,5 +149,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingInternationalXmppAddr() { - ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7.com/baz")); + ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addXMPPAddress("tron\xc3\xa7.com"); @@ -151,5 +157,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingCNWithoutSAN() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addCommonName("bar.com"); @@ -159,5 +165,5 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { void testCertificateVerifies_WithMatchingCNWithSAN() { - ServerIdentityVerifier testling(JID("foo@bar.com/baz")); + ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get()); SimpleCertificate::ref certificate(new SimpleCertificate()); certificate->addSRVName("foo.com"); @@ -166,4 +172,6 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); } + + boost::shared_ptr<IDNConverter> idnConverter; }; diff --git a/Swiften/VCards/UnitTest/VCardManagerTest.cpp b/Swiften/VCards/UnitTest/VCardManagerTest.cpp index eecec7b..9f1c8bb 100644 --- a/Swiften/VCards/UnitTest/VCardManagerTest.cpp +++ b/Swiften/VCards/UnitTest/VCardManagerTest.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -17,4 +17,6 @@ #include <Swiften/Queries/IQRouter.h> #include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> using namespace Swift; @@ -37,7 +39,8 @@ class VCardManagerTest : public CppUnit::TestFixture { void setUp() { ownJID = JID("baz@fum.com/dum"); + crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); stanzaChannel = new DummyStanzaChannel(); iqRouter = new IQRouter(stanzaChannel); - vcardStorage = new VCardMemoryStorage(); + vcardStorage = new VCardMemoryStorage(crypto.get()); } @@ -202,4 +205,5 @@ class VCardManagerTest : public CppUnit::TestFixture { std::vector< std::pair<JID, VCard::ref> > changes; std::vector<VCard::ref> ownChanges; + boost::shared_ptr<CryptoProvider> crypto; }; diff --git a/Swiften/VCards/VCardManager.cpp b/Swiften/VCards/VCardManager.cpp index 52447a1..5a65dcd 100644 --- a/Swiften/VCards/VCardManager.cpp +++ b/Swiften/VCards/VCardManager.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,4 +9,5 @@ #include <boost/bind.hpp> +#include <Swiften/Base/Log.h> #include <Swiften/JID/JID.h> #include <Swiften/VCards/VCardStorage.h> @@ -26,7 +27,9 @@ VCard::ref VCardManager::getVCard(const JID& jid) const { } -VCard::ref VCardManager::getVCardAndRequestWhenNeeded(const JID& jid) { +VCard::ref VCardManager::getVCardAndRequestWhenNeeded(const JID& jid, const boost::posix_time::time_duration& allowedAge) { VCard::ref vcard = storage->getVCard(jid); - if (!vcard) { + boost::posix_time::ptime vcardFetchedTime = storage->getVCardWriteTime(jid); + bool vcardTooOld = vcard && (vcardFetchedTime.is_special() || ((boost::posix_time::second_clock::universal_time() - vcardFetchedTime) > allowedAge)); + if (!vcard || vcardTooOld) { requestVCard(jid); } diff --git a/Swiften/VCards/VCardManager.h b/Swiften/VCards/VCardManager.h index 29fe32c..78e0f3e 100644 --- a/Swiften/VCards/VCardManager.h +++ b/Swiften/VCards/VCardManager.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -9,4 +9,7 @@ #include <set> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <Swiften/Base/API.h> #include <Swiften/JID/JID.h> #include <Swiften/Elements/VCard.h> @@ -20,5 +23,5 @@ namespace Swift { class IQRouter; - class VCardManager : public boost::bsignals::trackable { + class SWIFTEN_API VCardManager : public boost::bsignals::trackable { public: VCardManager(const JID& ownJID, IQRouter* iqRouter, VCardStorage* vcardStorage); @@ -26,5 +29,5 @@ namespace Swift { VCard::ref getVCard(const JID& jid) const; - VCard::ref getVCardAndRequestWhenNeeded(const JID& jid); + VCard::ref getVCardAndRequestWhenNeeded(const JID& jid, const boost::posix_time::time_duration& allowedAge = boost::posix_time::time_duration(boost::date_time::pos_infin)); void requestVCard(const JID& jid); void requestOwnVCard(); diff --git a/Swiften/VCards/VCardMemoryStorage.h b/Swiften/VCards/VCardMemoryStorage.h index ade9c89..f538fc1 100644 --- a/Swiften/VCards/VCardMemoryStorage.h +++ b/Swiften/VCards/VCardMemoryStorage.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,4 +8,5 @@ #include <boost/shared_ptr.hpp> + #include <map> @@ -16,5 +17,5 @@ namespace Swift { class VCardMemoryStorage : public VCardStorage { public: - VCardMemoryStorage() {} + VCardMemoryStorage(CryptoProvider* crypto) : VCardStorage(crypto) {} virtual VCard::ref getVCard(const JID& jid) const { @@ -28,11 +29,23 @@ namespace Swift { } + virtual boost::posix_time::ptime getVCardWriteTime(const JID& jid) const { + if (vcardWriteTimes.find(jid) == vcardWriteTimes.end()) { + return boost::posix_time::ptime(); + } + else { + return vcardWriteTimes.at(jid); + } + } + virtual void setVCard(const JID& jid, VCard::ref v) { vcards[jid] = v; + vcardWriteTimes[jid] = boost::posix_time::second_clock::universal_time(); } private: typedef std::map<JID, VCard::ref> VCardMap; + typedef std::map<JID, boost::posix_time::ptime> VCardWriteTimeMap; VCardMap vcards; + VCardWriteTimeMap vcardWriteTimes; }; } diff --git a/Swiften/VCards/VCardStorage.cpp b/Swiften/VCards/VCardStorage.cpp index 900f1e5..fefea83 100644 --- a/Swiften/VCards/VCardStorage.cpp +++ b/Swiften/VCards/VCardStorage.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,8 +8,11 @@ #include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/Crypto/CryptoProvider.h> namespace Swift { +VCardStorage::VCardStorage(CryptoProvider* crypto) : crypto(crypto) { +} + VCardStorage::~VCardStorage() { } @@ -18,5 +21,5 @@ std::string VCardStorage::getPhotoHash(const JID& jid) const { VCard::ref vCard = getVCard(jid); if (vCard && !vCard->getPhoto().empty()) { - return Hexify::hexify(SHA1::getHash(vCard->getPhoto())); + return Hexify::hexify(crypto->getSHA1Hash(vCard->getPhoto())); } else { diff --git a/Swiften/VCards/VCardStorage.h b/Swiften/VCards/VCardStorage.h index 977a40c..e6c84f4 100644 --- a/Swiften/VCards/VCardStorage.h +++ b/Swiften/VCards/VCardStorage.h @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -8,19 +8,28 @@ #include <string> + #include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <Swiften/Base/API.h> #include <Swiften/Elements/VCard.h> namespace Swift { class JID; + class CryptoProvider; - class VCardStorage { + class SWIFTEN_API VCardStorage { public: + VCardStorage(CryptoProvider*); virtual ~VCardStorage(); virtual VCard::ref getVCard(const JID& jid) const = 0; + virtual boost::posix_time::ptime getVCardWriteTime(const JID& jid) const = 0; virtual void setVCard(const JID&, VCard::ref) = 0; virtual std::string getPhotoHash(const JID&) const; + + private: + CryptoProvider* crypto; }; } diff --git a/Swiften/Whiteboard/IncomingWhiteboardSession.cpp b/Swiften/Whiteboard/IncomingWhiteboardSession.cpp new file mode 100644 index 0000000..d64a0d2 --- /dev/null +++ b/Swiften/Whiteboard/IncomingWhiteboardSession.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Whiteboard/IncomingWhiteboardSession.h> +#include <Swiften/Elements/WhiteboardPayload.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h> + +namespace Swift { + IncomingWhiteboardSession::IncomingWhiteboardSession(const JID& jid, IQRouter* router) : WhiteboardSession(jid, router) { + } + + IncomingWhiteboardSession::~IncomingWhiteboardSession() { + } + + void IncomingWhiteboardSession::accept() { + boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(WhiteboardPayload::SessionAccept); + boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_); + request->send(); + onRequestAccepted(toJID_); + } + + void IncomingWhiteboardSession::handleIncomingOperation(WhiteboardOperation::ref operation) { + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(operation); + if (pairResult.client) { + if (pairResult.client->getPos() != -1) { + onOperationReceived(pairResult.client); + } + lastOpID = pairResult.client->getID(); + } + + if (pairResult.server) { + WhiteboardPayload::ref payload = boost::make_shared<WhiteboardPayload>(); + payload->setOperation(pairResult.server); + sendPayload(payload); + } + } + + void IncomingWhiteboardSession::sendOperation(WhiteboardOperation::ref operation) { + operation->setID(idGenerator.generateID()); + operation->setParentID(lastOpID); + lastOpID = operation->getID(); + + WhiteboardOperation::ref result = client.handleLocalOperationReceived(operation); + + if (result) { + WhiteboardPayload::ref payload = boost::make_shared<WhiteboardPayload>(); + payload->setOperation(result); + sendPayload(payload); + } + } +} diff --git a/Swiften/Whiteboard/IncomingWhiteboardSession.h b/Swiften/Whiteboard/IncomingWhiteboardSession.h new file mode 100644 index 0000000..54b5fb6 --- /dev/null +++ b/Swiften/Whiteboard/IncomingWhiteboardSession.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Whiteboard/WhiteboardSession.h> +#include <Swiften/Whiteboard/WhiteboardClient.h> +#include <boost/shared_ptr.hpp> + +namespace Swift { + class SWIFTEN_API IncomingWhiteboardSession : public WhiteboardSession { + public: + typedef boost::shared_ptr<IncomingWhiteboardSession> ref; + + public: + IncomingWhiteboardSession(const JID& jid, IQRouter* router); + ~IncomingWhiteboardSession(); + + void accept(); + + private: + void handleIncomingOperation(WhiteboardOperation::ref operation); + void sendOperation(WhiteboardOperation::ref operation); + + WhiteboardClient client; + }; +} diff --git a/Swiften/Whiteboard/OutgoingWhiteboardSession.cpp b/Swiften/Whiteboard/OutgoingWhiteboardSession.cpp new file mode 100644 index 0000000..ad81daa --- /dev/null +++ b/Swiften/Whiteboard/OutgoingWhiteboardSession.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Whiteboard/OutgoingWhiteboardSession.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> +#include <Swiften/Elements/WhiteboardPayload.h> + +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h> + +namespace Swift { + OutgoingWhiteboardSession::OutgoingWhiteboardSession(const JID& jid, IQRouter* router) : WhiteboardSession(jid, router) { + } + + OutgoingWhiteboardSession::~OutgoingWhiteboardSession() { + } + + void OutgoingWhiteboardSession::startSession() { + boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(WhiteboardPayload::SessionRequest); + boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_); + request->onResponse.connect(boost::bind(&OutgoingWhiteboardSession::handleRequestResponse, this, _1, _2)); + request->send(); + } + + void OutgoingWhiteboardSession::handleRequestResponse(boost::shared_ptr<WhiteboardPayload> /*payload*/, ErrorPayload::ref error) { + if (error) { + onRequestRejected(toJID_); + } + } + + void OutgoingWhiteboardSession::handleIncomingOperation(WhiteboardOperation::ref operation) { + WhiteboardOperation::ref op = server.handleClientOperationReceived(operation); + if (op->getPos() != -1) { + onOperationReceived(op); + } + lastOpID = op->getID(); + + WhiteboardPayload::ref payload = boost::make_shared<WhiteboardPayload>(); + payload->setOperation(op); + sendPayload(payload); + } + + void OutgoingWhiteboardSession::sendOperation(WhiteboardOperation::ref operation) { + operation->setID(idGenerator.generateID()); + operation->setParentID(lastOpID); + lastOpID = operation->getID(); + + server.handleLocalOperationReceived(operation); + WhiteboardPayload::ref payload = boost::make_shared<WhiteboardPayload>(); + payload->setOperation(operation); + sendPayload(payload); + } +} diff --git a/Swiften/Whiteboard/OutgoingWhiteboardSession.h b/Swiften/Whiteboard/OutgoingWhiteboardSession.h new file mode 100644 index 0000000..5db9c97 --- /dev/null +++ b/Swiften/Whiteboard/OutgoingWhiteboardSession.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Whiteboard/WhiteboardSession.h> +#include <Swiften/Whiteboard/WhiteboardServer.h> +#include <boost/shared_ptr.hpp> +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Base/API.h> + +namespace Swift { + class SWIFTEN_API OutgoingWhiteboardSession : public WhiteboardSession { + public: + typedef boost::shared_ptr<OutgoingWhiteboardSession> ref; + + public: + OutgoingWhiteboardSession(const JID& jid, IQRouter* router); + virtual ~OutgoingWhiteboardSession(); + void startSession(); + + private: + void handleRequestResponse(boost::shared_ptr<WhiteboardPayload> /*payload*/, ErrorPayload::ref error); + void handleIncomingOperation(WhiteboardOperation::ref operation); + void sendOperation(WhiteboardOperation::ref operation); + + WhiteboardServer server; + }; +} diff --git a/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp b/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp new file mode 100644 index 0000000..09c25bb --- /dev/null +++ b/Swiften/Whiteboard/UnitTest/WhiteboardClientTest.cpp @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Whiteboard/WhiteboardClient.h> +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardEllipseElement.h> + +using namespace Swift; + +class WhiteboardClientTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(WhiteboardClientTest); + CPPUNIT_TEST(testSynchronize_simplestSync); + CPPUNIT_TEST(testSynchronize_withoutTranslation); + CPPUNIT_TEST(testSynchronize_nonInterrupted); + CPPUNIT_TEST(testSynchronize_clientInterruption); + CPPUNIT_TEST(testSynchronize_serverInterruption); + CPPUNIT_TEST(testSynchronize_nonInterruptedMixOperations); + CPPUNIT_TEST(testSynchronize_nonInterruptedMixOperations2); + CPPUNIT_TEST_SUITE_END(); +public: + + /*! + * /\ + * \/ + * \ + */ + void testSynchronize_simplestSync() { + WhiteboardClient client; + WhiteboardInsertOperation::ref serverOp; + serverOp = createInsertOperation("0", "", 0); + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives first local operation, because it's parented off "0" which exists + //in server history and client doesn't wait for any operation ack from server, + //so this operation could be send + WhiteboardInsertOperation::ref clientOp; + clientOp = createInsertOperation("a", "0", 1); + WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(aElement); + WhiteboardInsertOperation::ref result; + checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement); + + //Client receives server operation parented off "0", which isn't last client operation + //so it have to be transformed against local operations and then transformed value can + //be returned to draw + serverOp = createInsertOperation("b", "0", 1); + WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(bElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "b", "a", 2, bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives confirmation from the server about processed "a" operation, it had to + //be transformed against "b" on the server side to receive operation parented off "b". + //There aren't any waiting operations to send to server, this operation should return + //nothing + serverOp = createInsertOperation("a", "b", 1); + pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives local operation, it doesn't have to be transformed against anything + //but operation returned to send to the server should be parented off last server + //operation, which is "b" + clientOp = createInsertOperation("c", "b", 3); + WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(cElement); + checkOperation(client.handleLocalOperationReceived(clientOp), "c", "a", 3, cElement); + + //Client receives confirmation from the server about processed "a" operation, it + //should be the same operation as it was sent because server didn't have to + //transform it + clientOp = createInsertOperation("c", "a", 3); + clientOp->setElement(cElement); + pairResult = client.handleServerOperationReceived(clientOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Results: + //Client operations: + //ID pos + //0 0 + //a 1 + //b 2 + //c 3 + // + //Server operations: + //ID pos + //0 0 + //b 1 + //a 1 + //c 3 + // + //what gives 0abc on both sides + } + + /*! + * / + * / + * \ + */ + void testSynchronize_withoutTranslation() { + WhiteboardClient client; + WhiteboardInsertOperation::ref serverOp; + serverOp = createInsertOperation("0", "", 0); + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives first local operation, because it's parented off "0" which exists + //in server history and client doesn't wait for any operation ack from server, + //so this operation could be send + WhiteboardInsertOperation::ref clientOp = createInsertOperation("c", "0", 1); + WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(cElement); + checkOperation(client.handleLocalOperationReceived(clientOp), "c", "0", 1, cElement); + + //Client receives second local operation, client didn't receive ack about previous + //operation from the server so it can't be send. + clientOp = createInsertOperation("d", "c", 2); + WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(dElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp)); + + //Client receives confirmation about processing "c" operation, it should be the + //same as sent operation because it wasn't transformed, client could send now + //operation "d" + clientOp = createInsertOperation("c", "0", 1); + clientOp->setElement(cElement); + pairResult = client.handleServerOperationReceived(clientOp); + checkOperation(pairResult.server, "d", "c", 2, dElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + + //Client receives confirmation about processing "d", it should be the same as + //sent operation. There aren't any operations in queue to send. + clientOp = createInsertOperation("d", "c", 2); + clientOp->setElement(dElement); + pairResult = client.handleServerOperationReceived(clientOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives new operation from server, it's parented off "d" which is at + //the end of local history so it doesn't have to be transformed, so operation + //to pass to window should be the same + serverOp = createInsertOperation("e", "d", 3); + WhiteboardEllipseElement::ref eElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(eElement); + pairResult = client.handleServerOperationReceived(serverOp); + WhiteboardInsertOperation::ref result = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + + //Client operations: + //ID pos + //0 0 + //c 1 + //d 2 + //e 3 + // + //Server operations: + //ID pos + //0 0 + //c 1 + //d 2 + //e 3 + } + + /*! + * /\ + * / \ + * \ / + * \/ + */ + void testSynchronize_nonInterrupted() { + WhiteboardClient client; + WhiteboardInsertOperation::ref serverOp; + serverOp = createInsertOperation("0", "", 0); + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives first local operation, because it's parented off "0" which exists + //in server history and client doesn't wait for any operation ack from server, + //so this operation could be send + WhiteboardInsertOperation::ref clientOp; + clientOp = createInsertOperation("a", "0", 1); + WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(aElement); + checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement); + + //Client receives second local operation, client didn't receive ack about previous + //operation from the server so it can't be send. + clientOp = createInsertOperation("b", "a", 2); + WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp)); + + //Client receives new operation from server, it should be transformed against + //"a" and "b" before adding to local operations history because it's parented off "0". + //Because client is waiting for ack of "a", there is no operation to send to server + serverOp = createInsertOperation("c", "0", 1); + WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(cElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "c", "b", 3, cElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives new operation from server, it should be transformed against + //results of previous transformations, returned operation should be parented off + //"c" existing in local history. + //Because client is waiting for ack of "a", there is no operation to send to server + serverOp = createInsertOperation("d", "c", 2); + WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(dElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "d", "c", 4, dElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives confirmation about processing "a", it should send next operation + //to server which is "b", but it should be version parented of transformed "a" + serverOp = createInsertOperation("a", "d", 1); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.server, "b", "a", 2, bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + + + //Client receives confirmation about processing "b", there aren't any operations + //waiting so it should return nothing. + serverOp = createInsertOperation("b", "a", 2); + pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client operations: + //ID pos + //0 0 + //a 1 + //b 2 + //c 3 + //d 4 + // + //Server operations: + //ID pos + //0 0 + //c 1 + //d 2 + //a 1 + //b 2 + // + //what gives 0abcd on both sides. + } + + /*! + * /\ + * / \ + * \ / + * / / + * \/ + */ + void testSynchronize_clientInterruption() { + WhiteboardClient client; + WhiteboardInsertOperation::ref serverOp; + serverOp = createInsertOperation("0", "", 0); + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives first local operation, because it's parented off "0" which exists + //in server history and client doesn't wait for any operation ack from server, + //so this operation could be send + WhiteboardInsertOperation::ref clientOp; + clientOp = createInsertOperation("a", "0", 1); + WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(aElement); + checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement); + + //Client receives second local operation, client didn't receive ack about previous + //operation from the server so it can't be send. + clientOp = createInsertOperation("b", "a", 2); + WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp)); + + //Client receives new operation from server, it should be transformed against + //"a" and "b" before adding to local operations history because it's parented off "0". + //Because client is waiting for ack of "a", there is no operation to send to server + serverOp = createInsertOperation("c", "0", 1); + WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(cElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "c", "b", 3, cElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives new local operation, client is still waiting for ack so, it + //should return nothing + clientOp = createInsertOperation("e", "a", 4); + WhiteboardEllipseElement::ref eElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(eElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp)); + + //Client receives new server operation, to add it to local history it should be transformed + //against result of previous transformations and operation "e", returned operation should + //be parented off "e", which was last local operation + serverOp = createInsertOperation("d", "c", 2); + WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(dElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "d", "e", 5, dElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives confirmation about processing "a", it had to be transformed against + //"c" and "d" and it is now parented off "d", returned value should be next operation + //which have to be send to server("b" parented off server version of "a"). + serverOp = createInsertOperation("a", "d", 1); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.server, "b", "a", 2, bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + + //Client receives confirmation about processing "b", it is the same operation as sent because + //it didn't have to be transformed, returned value should be next operation + //which have to be send to server("e" parented off server version of "b"). + serverOp = createInsertOperation("b", "a", 2); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.server, "e", "b", 4, eElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + + //Client receives confirmation about processing "b", it is the same operation as sent because + //it didn't have to be transformed, there aren't any operations to send so this function returns + //nothing + serverOp = createInsertOperation("e", "b", 4); + pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Result: + //Client operations: + //ID pos + //0 0 + //a 1 + //b 2 + //c 3 + //e 4 + //d 5 + // + //Server operations: + //0 0 + //c 1 + //d 2 + //a 1 + //b 2 + //e 4 + //what gives 0abced on both sides + } + + /*! + * /\ + * / / + * \ \ + * \/ + */ + void testSynchronize_serverInterruption() { + WhiteboardClient client; + WhiteboardInsertOperation::ref serverOp; + serverOp = createInsertOperation("0", "", 0); + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives first local operation, because it's parented off "0" which exists + //in server history and client doesn't wait for any operation ack from server, + //so this operation could be send + WhiteboardInsertOperation::ref clientOp; + clientOp = createInsertOperation("a", "0", 1); + WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(aElement); + checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement); + + //Client receives second local operation, client didn't receive ack about previous + //operation from the server so it can't be send. + clientOp = createInsertOperation("b", "a", 2); + WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientOp)); + + //Client receives new operation from server, it should be transformed against + //"a" and "b" before adding to local operations history because it's parented off "0". + //Because client is waiting for ack of "a", there is no operation to send to server + serverOp = createInsertOperation("c", "0", 1); + WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(cElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "c", "b", 3, cElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives confirmation about processing "a", it had to be transformed against + //"c" and it is now parented off "c", returned value should be next operation + //which have to be send to server("b" parented off server version of "a"). + serverOp = createInsertOperation("a", "c", 1); + serverOp->setElement(aElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.server, "b", "a", 2, bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + + //Client receives new server operation, to add it to local history it should be transformed + //against result of previous transformation(but only with transformation of "b"), returned + //operation should be parented off "c", which was last local operation + serverOp = createInsertOperation("d", "a", 3); + WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(dElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "d", "c", 4, dElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives confirmation about processing "b", it had to be transformed against + //"d" because both operations was parented off server version of "a". + //there aren't any operations to send so this function returns nothing. + serverOp = createInsertOperation("b", "d", 2); + serverOp->setElement(bElement); + pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client operations: + //ID pos + //0 0 + //a 1 + //b 2 + //c 3 + //d 4 + // + //Server operations: + //ID pos + //0 0 + //c 1 + //a 1 + //d 3 + //b 2 + // + //what gives 0abcd on both sides + + } + + /*! + * /\ + * / \ + * \ / + * \/ + */ + void testSynchronize_nonInterruptedMixOperations() { + WhiteboardClient client; + WhiteboardInsertOperation::ref serverOp; + serverOp = createInsertOperation("0", "", 0); + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives first local operation, because it's parented off "0" which exists + //in server history and client doesn't wait for any operation ack from server, + //so this operation could be send + WhiteboardInsertOperation::ref clientOp; + clientOp = createInsertOperation("a", "0", 1); + WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setElement(aElement); + checkOperation(client.handleLocalOperationReceived(clientOp), "a", "0", 1, aElement); + + //Client receives second local operation, client didn't receive ack about previous + //operation from the server so it can't be send. + WhiteboardUpdateOperation::ref clientUpdateOp = createUpdateOperation("b", "a", 0); + WhiteboardEllipseElement::ref bElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientUpdateOp->setElement(bElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientUpdateOp)); + + //Client receives new operation from server, it should be transformed against + //"a" and "b" before adding to local operations history because it's parented off "0". + //Because client is waiting for ack of "a", there is no operation to send to server + WhiteboardUpdateOperation::ref serverUpdateOp = createUpdateOperation("c", "0", 0); + WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverUpdateOp->setElement(cElement); + pairResult = client.handleServerOperationReceived(serverUpdateOp); + checkOperation(pairResult.client, "c", "b", 0, cElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives new operation from server, it should be transformed against + //results of previous transformations, returned operation should be parented off + //"c" existing in local history. + //Because client is waiting for ack of "a", there is no operation to send to server + serverOp = createInsertOperation("d", "c", 1); + WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(dElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "d", "c", 2, dElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives confirmation about processing "a", it should send next operation + //to server which is "b", but it should be version parented of transformed "a" + serverOp = createInsertOperation("a", "d", 1); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.server, "b", "a", 0, cElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + + + //Client receives confirmation about processing "b", there aren't any operations + //waiting so it should return nothing. + serverUpdateOp = createUpdateOperation("b", "a", 0); + pairResult = client.handleServerOperationReceived(serverUpdateOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client operations: + //ID pos + //0 0 + //a 1 + //b 2 + //c 3 + //d 4 + // + //Server operations: + //ID pos + //0 0 + //c 1 + //d 2 + //a 1 + //b 2 + // + //what gives 0abcd on both sides. + } + + /*! + * /\ + * / \ + * \ / + * \/ + */ + void testSynchronize_nonInterruptedMixOperations2() { + WhiteboardClient client; + WhiteboardInsertOperation::ref serverOp; + serverOp = createInsertOperation("0", "", 0); + WhiteboardClient::Result pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + serverOp = createInsertOperation("1", "0", 1); + pairResult = client.handleServerOperationReceived(serverOp); + CPPUNIT_ASSERT_EQUAL(serverOp, boost::dynamic_pointer_cast<WhiteboardInsertOperation>(pairResult.client)); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + //Client receives first local operation, because it's parented off "0" which exists + //in server history and client doesn't wait for any operation ack from server, + //so this operation could be send + WhiteboardInsertOperation::ref clientOp; + WhiteboardUpdateOperation::ref clientUpdateOp; + WhiteboardDeleteOperation::ref clientDeleteOp; + clientUpdateOp = createUpdateOperation("a", "1", 0); + WhiteboardEllipseElement::ref aElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientUpdateOp->setElement(aElement); + checkOperation(client.handleLocalOperationReceived(clientUpdateOp), "a", "1", 0, aElement); + + //Client receives second local operation, client didn't receive ack about previous + //operation from the server so it can't be send. + clientDeleteOp = createDeleteOperation("b", "a", 1); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), client.handleLocalOperationReceived(clientDeleteOp)); + + //Client receives new operation from server, it should be transformed against + //"a" and "b" before adding to local operations history because it's parented off "0". + //Because client is waiting for ack of "a", there is no operation to send to server + serverOp = createInsertOperation("c", "1", 2); + WhiteboardEllipseElement::ref cElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverOp->setElement(cElement); + pairResult = client.handleServerOperationReceived(serverOp); + checkOperation(pairResult.client, "c", "b", 1, cElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives new operation from server, it should be transformed against + //results of previous transformations, returned operation should be parented off + //"c" existing in local history. + //Because client is waiting for ack of "a", there is no operation to send to server + WhiteboardUpdateOperation::ref serverUpdateOp = createUpdateOperation("d", "c", 0); + WhiteboardEllipseElement::ref dElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + serverUpdateOp->setElement(dElement); + pairResult = client.handleServerOperationReceived(serverUpdateOp); + checkOperation(pairResult.client, "d", "c", 0, dElement); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client receives confirmation about processing "a", it should send next operation + //to server which is "b", but it should be version parented of transformed "a" + serverUpdateOp = createUpdateOperation("a", "d", 0); + pairResult = client.handleServerOperationReceived(serverUpdateOp); + checkOperation(pairResult.server, "b", "a", 1); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + + + //Client receives confirmation about processing "b", there aren't any operations + //waiting so it should return nothing. + WhiteboardDeleteOperation::ref serverDeleteOp = createDeleteOperation("b", "a", 0); + pairResult = client.handleServerOperationReceived(serverDeleteOp); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.client); + CPPUNIT_ASSERT_EQUAL(WhiteboardOperation::ref(), pairResult.server); + + //Client operations: + //ID pos + //0 0 + //a 1 + //b 2 + //c 3 + //d 4 + // + //Server operations: + //ID pos + //0 0 + //c 1 + //d 2 + //a 1 + //b 2 + // + //what gives 0abcd on both sides. + } + + + WhiteboardInsertOperation::ref createInsertOperation(std::string id, std::string parent, int pos) { + WhiteboardInsertOperation::ref operation = boost::make_shared<WhiteboardInsertOperation>(); + operation->setParentID(parent); + operation->setID(id); + operation->setPos(pos); + return operation; + } + + WhiteboardUpdateOperation::ref createUpdateOperation(std::string id, std::string parent, int pos) { + WhiteboardUpdateOperation::ref operation = boost::make_shared<WhiteboardUpdateOperation>(); + operation->setParentID(parent); + operation->setID(id); + operation->setPos(pos); + return operation; + } + + WhiteboardDeleteOperation::ref createDeleteOperation(std::string id, std::string parent, int pos) { + WhiteboardDeleteOperation::ref operation = boost::make_shared<WhiteboardDeleteOperation>(); + operation->setParentID(parent); + operation->setID(id); + operation->setPos(pos); + return operation; + } + + void checkOperation(WhiteboardOperation::ref operation, std::string id, std::string parent, int pos = -1, WhiteboardElement::ref element = WhiteboardElement::ref()) { + CPPUNIT_ASSERT_EQUAL(id, operation->getID()); + CPPUNIT_ASSERT_EQUAL(parent, operation->getParentID()); + if (pos != -1) { + CPPUNIT_ASSERT_EQUAL(pos, operation->getPos()); + } + + if (element) { + WhiteboardInsertOperation::ref insertOp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation); + if (insertOp) { + CPPUNIT_ASSERT_EQUAL(element, insertOp->getElement()); + } + + WhiteboardUpdateOperation::ref updateOp = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(operation); + if (updateOp) { + CPPUNIT_ASSERT_EQUAL(element, updateOp->getElement()); + } + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(WhiteboardClientTest); diff --git a/Swiften/Whiteboard/UnitTest/WhiteboardServerTest.cpp b/Swiften/Whiteboard/UnitTest/WhiteboardServerTest.cpp new file mode 100644 index 0000000..a7b9acc --- /dev/null +++ b/Swiften/Whiteboard/UnitTest/WhiteboardServerTest.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Whiteboard/WhiteboardServer.h> +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardEllipseElement.h> + +using namespace Swift; + +class WhiteboardServerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(WhiteboardServerTest); + CPPUNIT_TEST(testSimpleOp); + CPPUNIT_TEST(testSimpleOp1); + CPPUNIT_TEST(testSimpleOp2); + CPPUNIT_TEST(testFewSimpleOps); + CPPUNIT_TEST_SUITE_END(); +public: + void testSimpleOp() { + WhiteboardServer server; + WhiteboardInsertOperation::ref firstOp = boost::make_shared<WhiteboardInsertOperation>(); + firstOp->setID("0"); + server.handleLocalOperationReceived(firstOp); + WhiteboardInsertOperation::ref serverOp = boost::make_shared<WhiteboardInsertOperation>(); + serverOp->setID("b"); + serverOp->setParentID("0"); + serverOp->setPos(1); + server.handleLocalOperationReceived(serverOp); + WhiteboardInsertOperation::ref clientOp = boost::make_shared<WhiteboardInsertOperation>(); + WhiteboardEllipseElement::ref clientElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setID("a"); + clientOp->setParentID("0"); + clientOp->setPos(1); + clientOp->setElement(clientElement); + WhiteboardInsertOperation::ref op = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(server.handleClientOperationReceived(clientOp)); + CPPUNIT_ASSERT_EQUAL(std::string("b"), op->getParentID()); + CPPUNIT_ASSERT_EQUAL(std::string("a"), op->getID()); + CPPUNIT_ASSERT_EQUAL(1, op->getPos()); + CPPUNIT_ASSERT_EQUAL(clientElement, boost::dynamic_pointer_cast<WhiteboardEllipseElement>(op->getElement())); + } + + void testSimpleOp1() { + WhiteboardServer server; + WhiteboardInsertOperation::ref firstOp = boost::make_shared<WhiteboardInsertOperation>(); + firstOp->setID("0"); + server.handleLocalOperationReceived(firstOp); + WhiteboardDeleteOperation::ref serverOp = boost::make_shared<WhiteboardDeleteOperation>(); + serverOp->setID("b"); + serverOp->setParentID("0"); + serverOp->setPos(1); + server.handleLocalOperationReceived(serverOp); + WhiteboardUpdateOperation::ref clientOp = boost::make_shared<WhiteboardUpdateOperation>(); + WhiteboardEllipseElement::ref clientElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setID("a"); + clientOp->setParentID("0"); + clientOp->setPos(1); + clientOp->setElement(clientElement); + WhiteboardDeleteOperation::ref op = boost::dynamic_pointer_cast<WhiteboardDeleteOperation>(server.handleClientOperationReceived(clientOp)); + CPPUNIT_ASSERT_EQUAL(std::string("b"), op->getParentID()); + CPPUNIT_ASSERT_EQUAL(std::string("a"), op->getID()); + CPPUNIT_ASSERT_EQUAL(-1, op->getPos()); + } + + void testSimpleOp2() { + WhiteboardServer server; + WhiteboardInsertOperation::ref firstOp = boost::make_shared<WhiteboardInsertOperation>(); + firstOp->setID("0"); + server.handleLocalOperationReceived(firstOp); + WhiteboardUpdateOperation::ref serverOp = boost::make_shared<WhiteboardUpdateOperation>(); + serverOp->setID("b"); + serverOp->setParentID("0"); + serverOp->setPos(1); + server.handleLocalOperationReceived(serverOp); + WhiteboardDeleteOperation::ref clientOp = boost::make_shared<WhiteboardDeleteOperation>(); + clientOp->setID("a"); + clientOp->setParentID("0"); + clientOp->setPos(1); + WhiteboardDeleteOperation::ref op = boost::dynamic_pointer_cast<WhiteboardDeleteOperation>(server.handleClientOperationReceived(clientOp)); + CPPUNIT_ASSERT_EQUAL(std::string("b"), op->getParentID()); + CPPUNIT_ASSERT_EQUAL(std::string("a"), op->getID()); + CPPUNIT_ASSERT_EQUAL(1, op->getPos()); + } + + + void testFewSimpleOps() { + WhiteboardServer server; + WhiteboardInsertOperation::ref firstOp = boost::make_shared<WhiteboardInsertOperation>(); + firstOp->setID("0"); + server.handleLocalOperationReceived(firstOp); + WhiteboardInsertOperation::ref serverOp = boost::make_shared<WhiteboardInsertOperation>(); + serverOp->setID("a"); + serverOp->setParentID("0"); + serverOp->setPos(1); + server.handleLocalOperationReceived(serverOp); + serverOp = boost::make_shared<WhiteboardInsertOperation>(); + serverOp->setID("b"); + serverOp->setParentID("a"); + serverOp->setPos(2); + server.handleLocalOperationReceived(serverOp); + serverOp = boost::make_shared<WhiteboardInsertOperation>(); + serverOp->setID("c"); + serverOp->setParentID("b"); + serverOp->setPos(3); + server.handleLocalOperationReceived(serverOp); + WhiteboardInsertOperation::ref clientOp = boost::make_shared<WhiteboardInsertOperation>(); + WhiteboardEllipseElement::ref clientElement = boost::make_shared<WhiteboardEllipseElement>(0,0,0,0); + clientOp->setID("d"); + clientOp->setParentID("0"); + clientOp->setPos(1); + clientOp->setElement(clientElement); + WhiteboardInsertOperation::ref op = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(server.handleClientOperationReceived(clientOp)); + CPPUNIT_ASSERT_EQUAL(std::string("c"), op->getParentID()); + CPPUNIT_ASSERT_EQUAL(std::string("d"), op->getID()); + CPPUNIT_ASSERT_EQUAL(1, op->getPos()); + CPPUNIT_ASSERT_EQUAL(clientElement, boost::dynamic_pointer_cast<WhiteboardEllipseElement>(op->getElement())); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(WhiteboardServerTest); diff --git a/Swiften/Whiteboard/WhiteboardClient.cpp b/Swiften/Whiteboard/WhiteboardClient.cpp new file mode 100644 index 0000000..c17b9f9 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardClient.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Whiteboard/WhiteboardClient.h> +#include <Swiften/Whiteboard/WhiteboardTransformer.h> +#include <boost/smart_ptr/make_shared.hpp> +#include <iostream> + +namespace Swift { + WhiteboardOperation::ref WhiteboardClient::handleLocalOperationReceived(WhiteboardOperation::ref operation) { + localOperations_.push_back(operation); + + WhiteboardOperation::ref op; + WhiteboardInsertOperation::ref insertOp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation); + if (insertOp) { + op = boost::make_shared<WhiteboardInsertOperation>(*insertOp); + } + WhiteboardUpdateOperation::ref updateOp = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(operation); + if (updateOp) { + op = boost::make_shared<WhiteboardUpdateOperation>(*updateOp); + } + WhiteboardDeleteOperation::ref deleteOp = boost::dynamic_pointer_cast<WhiteboardDeleteOperation>(operation); + if (deleteOp) { + op = boost::make_shared<WhiteboardDeleteOperation>(*deleteOp); + } + + if (!bridge_.empty()) { + op->setParentID(bridge_.back()->getID()); + } + bridge_.push_back(op); + + if (lastSentOperationID_.empty()) + { + WhiteboardInsertOperation::ref insertOp = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(operation); + if (insertOp) { + op = boost::make_shared<WhiteboardInsertOperation>(*insertOp); + } + WhiteboardUpdateOperation::ref updateOp = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(operation); + if (updateOp) { + op = boost::make_shared<WhiteboardUpdateOperation>(*updateOp); + } + WhiteboardDeleteOperation::ref deleteOp = boost::dynamic_pointer_cast<WhiteboardDeleteOperation>(operation); + if (deleteOp) { + op = boost::make_shared<WhiteboardDeleteOperation>(*deleteOp); + } + + + if (!serverOperations_.empty()) { + op->setParentID(serverOperations_.back()->getID()); + } + lastSentOperationID_ = operation->getID(); + return op; + } else { + return WhiteboardOperation::ref(); + } + } + + WhiteboardClient::Result WhiteboardClient::handleServerOperationReceived(WhiteboardOperation::ref operation) { + serverOperations_.push_back(operation); + Result result; +// if (localOperations_.empty()) {// || localOperations_.back()->getID() == operation->getParentID()) { + //Situation where client and server are in sync + if (localOperations_.size() == serverOperations_.size()-1) { + localOperations_.push_back(operation); +// clientOp = operation; + result.client = operation; + } else if (lastSentOperationID_ == operation->getID()) { + //Client received confirmation about own operation and it sends next operation to server + if (!bridge_.empty() && lastSentOperationID_ == bridge_.front()->getID()) { + bridge_.erase(bridge_.begin()); + } + + if (!bridge_.empty() && (bridge_.front())->getParentID() == lastSentOperationID_) { + lastSentOperationID_ = (bridge_.front())->getID(); + result.server = bridge_.front(); + } + if (!result.server) { + lastSentOperationID_.clear(); + } + } else { + std::list<WhiteboardOperation::ref>::iterator it = bridge_.begin(); + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> opPair; + WhiteboardOperation::ref temp; + opPair = WhiteboardTransformer::transform(*it, operation); + temp = opPair.first; + + *it = opPair.second; + std::string previousID = (*it)->getID(); + ++it; + for (; it != bridge_.end(); ++it) { + opPair = WhiteboardTransformer::transform(*it, temp); + temp = opPair.first; + *it = opPair.second; + (*it)->setParentID(previousID); + previousID = (*it)->getID(); + } + + temp->setParentID(localOperations_.back()->getID()); + localOperations_.push_back(temp); + result.client = temp; + } + + return result; + } + + void WhiteboardClient::print() { + std::list<WhiteboardOperation::ref>::iterator it; + std::cout << "Client" << std::endl; + for(it = localOperations_.begin(); it != localOperations_.end(); ++it) { + std::cout << (*it)->getID() << " " << (*it)->getPos() << std::endl; + } + + std::cout << "Server" << std::endl; + for(it = serverOperations_.begin(); it != serverOperations_.end(); ++it) { + std::cout << (*it)->getID() << " " << (*it)->getPos() << std::endl; + } + } +} diff --git a/Swiften/Whiteboard/WhiteboardClient.h b/Swiften/Whiteboard/WhiteboardClient.h new file mode 100644 index 0000000..2cc46a6 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardClient.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Whiteboard/WhiteboardOperation.h> +#include <list> +#include <utility> + +namespace Swift { + class SWIFTEN_API WhiteboardClient { + public: + struct Result { + WhiteboardOperation::ref client; + WhiteboardOperation::ref server; + }; + /*! + * @return Operation to send + */ + WhiteboardOperation::ref handleLocalOperationReceived(WhiteboardOperation::ref operation); + /*! + * @return pair.first-element to handle locally, pair.second-element to send to server + */ + Result handleServerOperationReceived(WhiteboardOperation::ref operation); + void print(); + + private: + std::list<WhiteboardOperation::ref> localOperations_; + std::list<WhiteboardOperation::ref> serverOperations_; + std::list<WhiteboardOperation::ref> bridge_; + std::string lastSentOperationID_; + }; +} diff --git a/Swiften/Whiteboard/WhiteboardResponder.cpp b/Swiften/Whiteboard/WhiteboardResponder.cpp new file mode 100644 index 0000000..f72861f --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardResponder.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Whiteboard/WhiteboardResponder.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Whiteboard/WhiteboardSessionManager.h> +#include <Swiften/Whiteboard/IncomingWhiteboardSession.h> +#include <Swiften/Whiteboard/WhiteboardSession.h> +#include <Swiften/Queries/IQRouter.h> + +namespace Swift { + WhiteboardResponder::WhiteboardResponder(WhiteboardSessionManager* sessionManager, IQRouter* router) : SetResponder<WhiteboardPayload>(router), sessionManager_(sessionManager), router_(router) { + } + + bool WhiteboardResponder::handleSetRequest(const JID& from, const JID& /*to*/, const std::string& id, boost::shared_ptr<WhiteboardPayload> payload) { + if (payload->getType() == WhiteboardPayload::SessionRequest) { + if (sessionManager_->getSession(from)) { + sendError(from, id, ErrorPayload::Conflict, ErrorPayload::Cancel); + } else { + sendResponse(from, id, boost::shared_ptr<WhiteboardPayload>()); + IncomingWhiteboardSession::ref session = boost::make_shared<IncomingWhiteboardSession>(from, router_); + sessionManager_->handleIncomingSession(session); + } + } else { + sendResponse(from, id, boost::shared_ptr<WhiteboardPayload>()); + WhiteboardSession::ref session = sessionManager_->getSession(from); + if (session != NULL) { + session->handleIncomingAction(payload); + } + } + return true; + } +} diff --git a/Swiften/Whiteboard/WhiteboardResponder.h b/Swiften/Whiteboard/WhiteboardResponder.h new file mode 100644 index 0000000..c05be23 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardResponder.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Queries/SetResponder.h> +#include <Swiften/Elements/WhiteboardPayload.h> + +namespace Swift { + class IQRouter; + class WhiteboardSessionManager; + + class WhiteboardResponder : public SetResponder<WhiteboardPayload> { + public: + WhiteboardResponder(WhiteboardSessionManager* sessionManager, IQRouter* router); + bool handleSetRequest(const JID& from, const JID& /*to*/, const std::string& id, boost::shared_ptr<WhiteboardPayload> payload); + + private: + WhiteboardSessionManager* sessionManager_; + IQRouter* router_; + }; +} diff --git a/Swiften/Whiteboard/WhiteboardServer.cpp b/Swiften/Whiteboard/WhiteboardServer.cpp new file mode 100644 index 0000000..94f8cff --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardServer.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Whiteboard/WhiteboardServer.h> +#include <Swiften/Whiteboard/WhiteboardTransformer.h> +#include <iostream> + +namespace Swift { + void WhiteboardServer::handleLocalOperationReceived(WhiteboardOperation::ref operation) { + operations_.push_back(operation); + } + + WhiteboardOperation::ref WhiteboardServer::handleClientOperationReceived(WhiteboardOperation::ref newOperation) { + std::list<WhiteboardOperation::ref>::reverse_iterator it; + if (operations_.empty() || newOperation->getParentID() == operations_.back()->getID()) { + operations_.push_back(newOperation); + return newOperation; + } + for (it = operations_.rbegin(); it != operations_.rend(); ++it) { + WhiteboardOperation::ref operation = *it; + while (newOperation->getParentID() == operation->getParentID()) { + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> tResult = WhiteboardTransformer::transform(newOperation, operation); + + if (it == operations_.rbegin()) { + operations_.push_back(tResult.second); + return tResult.second; + } else { + newOperation = tResult.second; + --it; + operation = *it; + } + + } + } + return WhiteboardOperation::ref(); + } + + void WhiteboardServer::print() { + std::list<WhiteboardOperation::ref>::iterator it; + std::cout << "Server:" << std::endl; + for(it = operations_.begin(); it != operations_.end(); ++it) { + std::cout << (*it)->getID() << " " << (*it)->getPos() << std::endl; + } + } + +} diff --git a/Swiften/Whiteboard/WhiteboardServer.h b/Swiften/Whiteboard/WhiteboardServer.h new file mode 100644 index 0000000..73e8d33 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardServer.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> + +#include <list> + +namespace Swift { + class SWIFTEN_API WhiteboardServer { + public: + void handleLocalOperationReceived(WhiteboardOperation::ref operation); + WhiteboardOperation::ref handleClientOperationReceived(WhiteboardOperation::ref operation); + void print(); + + private: + std::list<WhiteboardOperation::ref> operations_; + }; +} diff --git a/Swiften/Whiteboard/WhiteboardSession.cpp b/Swiften/Whiteboard/WhiteboardSession.cpp new file mode 100644 index 0000000..cffcf07 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardSession.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Whiteboard/WhiteboardSession.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/WhiteboardPayload.h> +#include <Swiften/Elements/ErrorPayload.h> + +#include <iostream> + +namespace Swift { + WhiteboardSession::WhiteboardSession(const JID& jid, IQRouter* router) : toJID_(jid), router_(router) { + } + + WhiteboardSession::~WhiteboardSession() { + } + + void WhiteboardSession::handleIncomingAction(boost::shared_ptr<WhiteboardPayload> payload) { + switch (payload->getType()) { + case WhiteboardPayload::Data: + handleIncomingOperation(payload->getOperation()); + return; + case WhiteboardPayload::SessionAccept: + onRequestAccepted(toJID_); + return; + case WhiteboardPayload::SessionTerminate: + onSessionTerminated(toJID_); + return; + + //handled elsewhere + case WhiteboardPayload::SessionRequest: + + case WhiteboardPayload::UnknownType: + return; + } + } + + void WhiteboardSession::sendElement(const WhiteboardElement::ref element) { + boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(); + payload->setElement(element); + boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_); + request->send(); + } + + void WhiteboardSession::sendPayload(boost::shared_ptr<WhiteboardPayload> payload) { + boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_); + request->send(); + } + + void WhiteboardSession::cancel() { + if (router_->isAvailable()) { + boost::shared_ptr<WhiteboardPayload> payload = boost::make_shared<WhiteboardPayload>(WhiteboardPayload::SessionTerminate); + boost::shared_ptr<GenericRequest<WhiteboardPayload> > request = boost::make_shared<GenericRequest<WhiteboardPayload> >(IQ::Set, toJID_, payload, router_); + request->send(); + } + onSessionTerminated(toJID_); + } + + const JID& WhiteboardSession::getTo() const { + return toJID_; + } +} diff --git a/Swiften/Whiteboard/WhiteboardSession.h b/Swiften/Whiteboard/WhiteboardSession.h new file mode 100644 index 0000000..14fa632 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardSession.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/API.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/Whiteboard/WhiteboardElement.h> +#include <Swiften/Elements/Whiteboard/WhiteboardOperation.h> + +namespace Swift { + class IQRouter; + class ErrorPayload; + class WhiteboardPayload; + + class SWIFTEN_API WhiteboardSession { + public: + typedef boost::shared_ptr<WhiteboardSession> ref; + + public: + WhiteboardSession(const JID& jid, IQRouter* router); + virtual ~WhiteboardSession(); + void handleIncomingAction(boost::shared_ptr<WhiteboardPayload> payload); + void sendElement(const WhiteboardElement::ref element); + virtual void sendOperation(WhiteboardOperation::ref operation) = 0; + void cancel(); + const JID& getTo() const; + + public: + boost::signal< void(const WhiteboardElement::ref element)> onElementReceived; + boost::signal< void(const WhiteboardOperation::ref operation)> onOperationReceived; + boost::signal< void(const JID& contact)> onSessionTerminated; + boost::signal< void(const JID& contact)> onRequestAccepted; + boost::signal< void(const JID& contact)> onRequestRejected; + + private: + virtual void handleIncomingOperation(WhiteboardOperation::ref operation) = 0; + + protected: + void sendPayload(boost::shared_ptr<WhiteboardPayload> payload); + + JID toJID_; + IQRouter* router_; + std::string lastOpID; + IDGenerator idGenerator; + }; +} diff --git a/Swiften/Whiteboard/WhiteboardSessionManager.cpp b/Swiften/Whiteboard/WhiteboardSessionManager.cpp new file mode 100644 index 0000000..c8e9a6a --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardSessionManager.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#include <Swiften/Whiteboard/WhiteboardSessionManager.h> + +#include <Swiften/Base/foreach.h> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Whiteboard/WhiteboardResponder.h> +#include <Swiften/Presence/PresenceOracle.h> +#include "Swiften/Disco/EntityCapsProvider.h" + +namespace Swift { + WhiteboardSessionManager::WhiteboardSessionManager(IQRouter* router, StanzaChannel* stanzaChannel, PresenceOracle* presenceOracle, EntityCapsProvider* capsProvider) : router_(router), stanzaChannel_(stanzaChannel), presenceOracle_(presenceOracle), capsProvider_(capsProvider) { + responder = new WhiteboardResponder(this, router); + responder->start(); + stanzaChannel_->onPresenceReceived.connect(boost::bind(&WhiteboardSessionManager::handlePresenceReceived, this, _1)); + stanzaChannel_->onAvailableChanged.connect(boost::bind(&WhiteboardSessionManager::handleAvailableChanged, this, _1)); + } + + WhiteboardSessionManager::~WhiteboardSessionManager() { + responder->stop(); + delete responder; + } + + WhiteboardSession::ref WhiteboardSessionManager::getSession(const JID& to) { + if (sessions_.find(to) == sessions_.end()) { + return boost::shared_ptr<WhiteboardSession>(); + } + return sessions_[to]; + } + + OutgoingWhiteboardSession::ref WhiteboardSessionManager::createOutgoingSession(const JID& to) { + JID fullJID = to; + if (fullJID.isBare()) { + fullJID = getFullJID(fullJID); + } + OutgoingWhiteboardSession::ref session = boost::make_shared<OutgoingWhiteboardSession>(fullJID, router_); + sessions_[fullJID] = session; + session->onSessionTerminated.connect(boost::bind(&WhiteboardSessionManager::deleteSessionEntry, this, _1)); + session->onRequestRejected.connect(boost::bind(&WhiteboardSessionManager::deleteSessionEntry, this, _1)); + return session; + } + + WhiteboardSession::ref WhiteboardSessionManager::requestSession(const JID& to) { + WhiteboardSession::ref session = getSession(to); + if (!session) { + OutgoingWhiteboardSession::ref outgoingSession = createOutgoingSession(to); + outgoingSession->startSession(); + return outgoingSession; + } else { + return session; + } + } + + void WhiteboardSessionManager::handleIncomingSession(IncomingWhiteboardSession::ref session) { + sessions_[session->getTo()] = session; + session->onSessionTerminated.connect(boost::bind(&WhiteboardSessionManager::deleteSessionEntry, this, _1)); + onSessionRequest(session); + } + + JID WhiteboardSessionManager::getFullJID(const JID& bareJID) { + JID fullReceipientJID; + int priority = INT_MIN; + + //getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Remko Tronçon @ 11:11 + std::vector<Presence::ref> presences = presenceOracle_->getAllPresence(bareJID); + + //iterate over them + foreach(Presence::ref pres, presences) { + if (pres->getPriority() > priority) { + // look up caps from the jid + DiscoInfo::ref info = capsProvider_->getCaps(pres->getFrom()); + if (info && info->hasFeature(DiscoInfo::WhiteboardFeature)) { + priority = pres->getPriority(); + fullReceipientJID = pres->getFrom(); + } + } + } + + return fullReceipientJID; + } + + void WhiteboardSessionManager::deleteSessionEntry(const JID& contact) { + sessions_.erase(contact); + } + + void WhiteboardSessionManager::handlePresenceReceived(Presence::ref presence) { + if (!presence->isAvailable()) { + WhiteboardSession::ref session = getSession(presence->getFrom()); + if (session) { + session->cancel(); + } + } + } + + void WhiteboardSessionManager::handleAvailableChanged(bool available) { + if (!available) { + std::map<JID, WhiteboardSession::ref> sessionsCopy = sessions_; + std::map<JID, WhiteboardSession::ref>::iterator it; + for (it = sessionsCopy.begin(); it != sessionsCopy.end(); ++it) { + it->second->cancel(); + } + } + } +} diff --git a/Swiften/Whiteboard/WhiteboardSessionManager.h b/Swiften/Whiteboard/WhiteboardSessionManager.h new file mode 100644 index 0000000..d06b856 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardSessionManager.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <map> + +#include <Swiften/Base/API.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Whiteboard/WhiteboardSession.h> +#include <Swiften/Whiteboard/IncomingWhiteboardSession.h> +#include <Swiften/Whiteboard/OutgoingWhiteboardSession.h> + +namespace Swift { + class IQRouter; + class WhiteboardResponder; + class PresenceOracle; + class EntityCapsProvider; + + class SWIFTEN_API WhiteboardSessionManager { + friend class WhiteboardResponder; + public: + WhiteboardSessionManager(IQRouter* router, StanzaChannel* stanzaChannel, PresenceOracle* presenceOracle, EntityCapsProvider* capsProvider); + ~WhiteboardSessionManager(); + + WhiteboardSession::ref getSession(const JID& to); + WhiteboardSession::ref requestSession(const JID& to); + + public: + boost::signal< void (IncomingWhiteboardSession::ref)> onSessionRequest; + + private: + JID getFullJID(const JID& bareJID); + OutgoingWhiteboardSession::ref createOutgoingSession(const JID& to); + void handleIncomingSession(IncomingWhiteboardSession::ref session); + void handlePresenceReceived(Presence::ref presence); + void handleAvailableChanged(bool available); + void deleteSessionEntry(const JID& contact); + + private: + std::map<JID, boost::shared_ptr<WhiteboardSession> > sessions_; + IQRouter* router_; + StanzaChannel* stanzaChannel_; + PresenceOracle* presenceOracle_; + EntityCapsProvider* capsProvider_; + WhiteboardResponder* responder; + }; +} diff --git a/Swiften/Whiteboard/WhiteboardTransformer.cpp b/Swiften/Whiteboard/WhiteboardTransformer.cpp new file mode 100644 index 0000000..8b9c927 --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardTransformer.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Whiteboard/WhiteboardTransformer.h> +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardOperation::ref clientOp, WhiteboardOperation::ref serverOp) { + WhiteboardInsertOperation::ref clientInsert = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(clientOp); + WhiteboardInsertOperation::ref serverInsert = boost::dynamic_pointer_cast<WhiteboardInsertOperation>(serverOp); + WhiteboardUpdateOperation::ref clientUpdate = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(clientOp); + WhiteboardUpdateOperation::ref serverUpdate = boost::dynamic_pointer_cast<WhiteboardUpdateOperation>(serverOp); + WhiteboardDeleteOperation::ref clientDelete = boost::dynamic_pointer_cast<WhiteboardDeleteOperation>(clientOp); + WhiteboardDeleteOperation::ref serverDelete = boost::dynamic_pointer_cast<WhiteboardDeleteOperation>(serverOp); + if (clientInsert && serverInsert) { + return transform(clientInsert, serverInsert); + } else if (clientUpdate && serverUpdate) { + return transform(clientUpdate, serverUpdate); + } else if (clientInsert && serverUpdate) { + return transform(clientInsert, serverUpdate); + } else if (clientUpdate && serverInsert) { + return transform(clientUpdate, serverInsert); + } else if (clientDelete && serverDelete) { + return transform(clientDelete, serverDelete); + } else if (clientInsert && serverDelete) { + return transform(clientInsert, serverDelete); + } else if (clientDelete && serverInsert) { + return transform(clientDelete, serverInsert); + } else if (clientUpdate && serverDelete) { + return transform(clientUpdate, serverDelete); + } else if (clientDelete && serverUpdate) { + return transform(clientDelete, serverUpdate); + } else { + return std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref>(); + } + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardInsertOperation::ref clientOp, WhiteboardInsertOperation::ref serverOp) { + std::pair<WhiteboardInsertOperation::ref, WhiteboardInsertOperation::ref> result; + result.first = boost::make_shared<WhiteboardInsertOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + result.second = boost::make_shared<WhiteboardInsertOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + if (clientOp->getPos() <= serverOp->getPos()) { + result.first->setPos(result.first->getPos()+1); + } else { + result.second->setPos(result.second->getPos()+1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardUpdateOperation::ref clientOp, WhiteboardUpdateOperation::ref serverOp) { + std::pair<WhiteboardUpdateOperation::ref, WhiteboardUpdateOperation::ref> result; + result.first = boost::make_shared<WhiteboardUpdateOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + + if (clientOp->getPos() == serverOp->getPos()) { + result.second = boost::make_shared<WhiteboardUpdateOperation>(*serverOp); + result.second->setID(clientOp->getID()); + result.second->setParentID(serverOp->getID()); + } else { + result.second = boost::make_shared<WhiteboardUpdateOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + } + + if (clientOp->getPos() < serverOp->getPos() && clientOp->getNewPos() > serverOp->getPos()) { + result.first->setPos(result.first->getPos()-1); + if (clientOp->getNewPos() >= serverOp->getNewPos()) { + result.first->setNewPos(result.first->getNewPos()-1); + } + } else if (clientOp->getNewPos() >= serverOp->getNewPos()) { + result.first->setNewPos(result.first->getNewPos()-1); + } + + if (serverOp->getPos() < clientOp->getPos() && serverOp->getNewPos() > clientOp->getPos()) { + result.second->setPos(result.second->getPos()-1); + if (serverOp->getNewPos() >= clientOp->getNewPos()) { + result.second->setNewPos(result.second->getNewPos()-1); + } + } else if (serverOp->getNewPos() >= clientOp->getNewPos()) { + result.second->setNewPos(result.second->getNewPos()-1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardUpdateOperation::ref clientOp, WhiteboardInsertOperation::ref serverOp) { + std::pair<WhiteboardInsertOperation::ref, WhiteboardUpdateOperation::ref> result; + result.first = boost::make_shared<WhiteboardInsertOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + result.second = boost::make_shared<WhiteboardUpdateOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + if (serverOp->getPos() <= clientOp->getPos()) { + result.second->setPos(result.second->getPos()+1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardInsertOperation::ref clientOp, WhiteboardUpdateOperation::ref serverOp) { + std::pair<WhiteboardUpdateOperation::ref, WhiteboardInsertOperation::ref> result; + result.first = boost::make_shared<WhiteboardUpdateOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + result.second = boost::make_shared<WhiteboardInsertOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + if (serverOp->getPos() >= clientOp->getPos()) { + result.first->setPos(result.first->getPos()+1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardDeleteOperation::ref clientOp, WhiteboardDeleteOperation::ref serverOp) { + std::pair<WhiteboardDeleteOperation::ref, WhiteboardDeleteOperation::ref> result; + result.first = boost::make_shared<WhiteboardDeleteOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + result.second = boost::make_shared<WhiteboardDeleteOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + if (clientOp->getPos() == -1) { + result.second->setPos(-1); + } + if (serverOp->getPos() == -1) { + result.first->setPos(-1); + } + if (clientOp->getPos() < serverOp->getPos()) { + result.first->setPos(result.first->getPos()-1); + } else if (clientOp->getPos() > serverOp->getPos()) { + result.second->setPos(result.second->getPos()-1); + } else { + result.first->setPos(-1); + result.second->setPos(-1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardInsertOperation::ref clientOp, WhiteboardDeleteOperation::ref serverOp) { + std::pair<WhiteboardDeleteOperation::ref, WhiteboardInsertOperation::ref> result; + result.first = boost::make_shared<WhiteboardDeleteOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + result.second = boost::make_shared<WhiteboardInsertOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + if (clientOp->getPos() <= serverOp->getPos()) { + result.first->setPos(result.first->getPos()+1); + } else if (serverOp->getPos() != -1) { + result.second->setPos(result.second->getPos()-1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardDeleteOperation::ref clientOp, WhiteboardInsertOperation::ref serverOp) { + std::pair<WhiteboardInsertOperation::ref, WhiteboardDeleteOperation::ref> result; + result.first = boost::make_shared<WhiteboardInsertOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + result.second = boost::make_shared<WhiteboardDeleteOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + if (serverOp->getPos() <= clientOp->getPos()) { + result.second->setPos(result.second->getPos()+1); + } else if (clientOp->getPos() != -1) { + result.first->setPos(result.first->getPos()-1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardUpdateOperation::ref clientOp, WhiteboardDeleteOperation::ref serverOp) { + std::pair<WhiteboardDeleteOperation::ref, WhiteboardOperation::ref> result; + result.first = boost::make_shared<WhiteboardDeleteOperation>(*serverOp); + result.first->setParentID(clientOp->getID()); + WhiteboardUpdateOperation::ref updateOp = boost::make_shared<WhiteboardUpdateOperation>(*clientOp); + result.second = updateOp; + result.second->setParentID(serverOp->getID()); + if (clientOp->getPos() == serverOp->getPos()) { + WhiteboardDeleteOperation::ref deleteOp = boost::make_shared<WhiteboardDeleteOperation>(); + result.second = deleteOp; + result.second->setPos(-1); + result.second->setID(clientOp->getID()); + result.second->setParentID(serverOp->getID()); + deleteOp->setElementID(serverOp->getElementID()); + } else if (clientOp->getPos() > serverOp->getPos() && clientOp->getNewPos() <= serverOp->getPos()) { + result.second->setPos(result.second->getPos()-1); + } else if (clientOp->getPos() < serverOp->getPos() && clientOp->getNewPos() >= serverOp->getPos()) { + updateOp->setNewPos(updateOp->getNewPos()-1); + } else if (clientOp->getPos() > serverOp->getPos()) { + result.second->setPos(result.second->getPos()-1); + updateOp->setNewPos(updateOp->getNewPos()-1); + } + return result; + } + + std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> WhiteboardTransformer::transform(WhiteboardDeleteOperation::ref clientOp, WhiteboardUpdateOperation::ref serverOp) { + std::pair<WhiteboardOperation::ref, WhiteboardDeleteOperation::ref> result; + WhiteboardUpdateOperation::ref updateOp = boost::make_shared<WhiteboardUpdateOperation>(*serverOp); + result.first = updateOp; + result.first->setParentID(clientOp->getID()); + result.second = boost::make_shared<WhiteboardDeleteOperation>(*clientOp); + result.second->setParentID(serverOp->getID()); + if (clientOp->getPos() == serverOp->getPos()) { + WhiteboardDeleteOperation::ref deleteOp = boost::make_shared<WhiteboardDeleteOperation>(); + result.first = deleteOp; + result.first->setPos(-1); + result.first->setID(serverOp->getID()); + result.first->setParentID(clientOp->getID()); + deleteOp->setElementID(clientOp->getElementID()); + } else if (clientOp->getPos() < serverOp->getPos() && clientOp->getPos() >= serverOp->getNewPos()) { + result.first->setPos(result.first->getPos()-1); + } else if (clientOp->getPos() > serverOp->getPos() && clientOp->getPos() <= serverOp->getNewPos()) { + updateOp->setNewPos(updateOp->getNewPos()-1); + } else if (clientOp->getPos() < serverOp->getPos()) { + result.first->setPos(result.first->getPos()-1); + updateOp->setNewPos(updateOp->getNewPos()-1); + } + return result; + } +} diff --git a/Swiften/Whiteboard/WhiteboardTransformer.h b/Swiften/Whiteboard/WhiteboardTransformer.h new file mode 100644 index 0000000..5811f9f --- /dev/null +++ b/Swiften/Whiteboard/WhiteboardTransformer.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2012 Mateusz Piękos + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Whiteboard/WhiteboardInsertOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardUpdateOperation.h> +#include <Swiften/Elements/Whiteboard/WhiteboardDeleteOperation.h> +#include <utility> + +namespace Swift { + class WhiteboardTransformer { + public: + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardOperation::ref clientOp, WhiteboardOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardInsertOperation::ref clientOp, WhiteboardInsertOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardUpdateOperation::ref clientOp, WhiteboardUpdateOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardUpdateOperation::ref clientOp, WhiteboardInsertOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardInsertOperation::ref clientOp, WhiteboardUpdateOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardDeleteOperation::ref clientOp, WhiteboardDeleteOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardInsertOperation::ref clientOp, WhiteboardDeleteOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardDeleteOperation::ref clientOp, WhiteboardInsertOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardUpdateOperation::ref clientOp, WhiteboardDeleteOperation::ref serverOp); + static std::pair<WhiteboardOperation::ref, WhiteboardOperation::ref> transform(WhiteboardDeleteOperation::ref clientOp, WhiteboardUpdateOperation::ref serverOp); + }; +} |