diff options
Diffstat (limited to 'Swiften')
349 files changed, 6336 insertions, 1727 deletions
diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp new file mode 100644 index 0000000..da7f042 --- /dev/null +++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h> + +#include <boost/bind.hpp> + +#include <Swiften/Queries/GenericRequest.h> + +namespace Swift { +OutgoingAdHocCommandSession::OutgoingAdHocCommandSession(const DiscoItems::Item& command, AdHocCommandWindowFactory* /*factory*/, IQRouter* iqRouter) : command_(command), iqRouter_(iqRouter), isMultiStage_(false) { + +} + +void OutgoingAdHocCommandSession::handleResponse(boost::shared_ptr<Command> payload, ErrorPayload::ref error) { + if (error) { + onError(error); + } else { + const std::vector<Command::Action> actions = payload->getAvailableActions(); + actionStates_.clear(); + if (payload->getStatus() == Command::Executing ) { + actionStates_[Command::Cancel] = EnabledAndPresent; + actionStates_[Command::Complete] = Present; + if (std::find(actions.begin(), actions.end(), Command::Complete) != actions.end()) { + actionStates_[Command::Complete] = EnabledAndPresent; + } + + if (getIsMultiStage()) { + actionStates_[Command::Next] = Present; + actionStates_[Command::Prev] = Present; + } + + if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end()) { + actionStates_[Command::Next] = EnabledAndPresent; + } + if (std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) { + actionStates_[Command::Prev] = EnabledAndPresent; + } + } + + sessionID_ = payload->getSessionID(); + if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end() + || std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) { + isMultiStage_ = true; + } + onNextStageReceived(payload); + } +} + +bool OutgoingAdHocCommandSession::getIsMultiStage() { + return isMultiStage_; +} + +void OutgoingAdHocCommandSession::start() { + boost::shared_ptr<Payload> commandPayload(new Command(command_.getNode())); + boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_)); + commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2)); + commandRequest->send(); +} + +void OutgoingAdHocCommandSession::cancel() { + if (!sessionID_.empty()) { + boost::shared_ptr<Payload> commandPayload(new Command(command_.getNode(), sessionID_, Command::Cancel)); + boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_)); + commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2)); + commandRequest->send(); + } +} + +void OutgoingAdHocCommandSession::goBack() { + boost::shared_ptr<Payload> commandPayload(new Command(command_.getNode(), sessionID_, Command::Prev)); + boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_)); + commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2)); + commandRequest->send(); +} + +void OutgoingAdHocCommandSession::complete(Form::ref form) { + Command* command = new Command(command_.getNode(), sessionID_, Command::Complete); + boost::shared_ptr<Payload> commandPayload(command); + command->setForm(form); + boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_)); + commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2)); + commandRequest->send(); +} + +void OutgoingAdHocCommandSession::goNext(Form::ref form) { + Command* command = new Command(command_.getNode(), sessionID_, Command::Next); + boost::shared_ptr<Payload> commandPayload(command); + command->setForm(form); + boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_)); + commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2)); + commandRequest->send(); +} + +OutgoingAdHocCommandSession::ActionState OutgoingAdHocCommandSession::getActionState(Command::Action action) { + return actionStates_[action]; +} + +} diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.h b/Swiften/AdHoc/OutgoingAdHocCommandSession.h new file mode 100644 index 0000000..f4b5242 --- /dev/null +++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/boost_bsignals.h> +#include <boost/shared_ptr.hpp> +#include <Swiften/Elements/DiscoItems.h> +#include <Swiften/Elements/Command.h> +#include <Swiften/Elements/ErrorPayload.h> + +namespace Swift { + class IQRouter; + class MainWindow; + class UIEventStream; + class AdHocCommandWindowFactory; + class OutgoingAdHocCommandSession { + public: + + /** + * Availability of action. + */ + enum ActionState { + Absent /** Action isn't applicable to this command. */ = 0, + Present /** Action is applicable to this command */= 1, + Enabled /** Action is applicable and currently available */ = 2, + EnabledAndPresent = 3}; + + OutgoingAdHocCommandSession(const DiscoItems::Item& command, AdHocCommandWindowFactory* factory, IQRouter* iqRouter); + /** + * Send initial request to the target. + */ + void start(); + /** + * Cancel command session with the target. + */ + void cancel(); + /** + * Return to the previous stage. + */ + void goBack(); + /** + * Send the form to complete the command. + * \param form Form for submission - if missing the command will be submitted with no form. + */ + void complete(Form::ref form); + /** + * Send the form to advance to the next stage of the command. + * \param form Form for submission - if missing the command will be submitted with no form. + */ + void goNext(Form::ref form); + + /** + * Is the form multi-stage? + */ + bool getIsMultiStage(); + + /** + * Emitted when the form for the next stage is available. + */ + boost::signal<void (Command::ref)> onNextStageReceived; + + /** + * Emitted on error. + */ + boost::signal<void (ErrorPayload::ref)> onError; + + /** + * Get the state of a given action. + * This is useful for a UI to determine which buttons should be visible, + * and which enabled. + * Use for Next, Prev, Cancel and Complete only. + * If no actions are available, the command has completed. + */ + ActionState getActionState(Command::Action action); + private: + void handleResponse(boost::shared_ptr<Command> payload, ErrorPayload::ref error); + private: + DiscoItems::Item command_; + IQRouter* iqRouter_; + bool isMultiStage_; + std::string sessionID_; + std::map<Command::Action, ActionState> actionStates_; + }; +} diff --git a/Swiften/AdHoc/SConscript b/Swiften/AdHoc/SConscript new file mode 100644 index 0000000..69c9083 --- /dev/null +++ b/Swiften/AdHoc/SConscript @@ -0,0 +1,6 @@ +Import("swiften_env") + +objects = swiften_env.SwiftenObject([ + "OutgoingAdHocCommandSession.cpp", + ]) +swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Avatars/AvatarFileStorage.cpp b/Swiften/Avatars/AvatarFileStorage.cpp deleted file mode 100644 index 4f76c80..0000000 --- a/Swiften/Avatars/AvatarFileStorage.cpp +++ /dev/null @@ -1,104 +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/Avatars/AvatarFileStorage.h> - -#include <iostream> -#include <boost/filesystem/fstream.hpp> - -#include <Swiften/Base/foreach.h> -#include <Swiften/Base/String.h> -#include <Swiften/StringCodecs/SHA1.h> -#include <Swiften/StringCodecs/Hexify.h> - -namespace Swift { - -AvatarFileStorage::AvatarFileStorage(const boost::filesystem::path& avatarsDir, const boost::filesystem::path& avatarsFile) : avatarsDir(avatarsDir), avatarsFile(avatarsFile) { - if (boost::filesystem::exists(avatarsFile)) { - try { - boost::filesystem::ifstream file(avatarsFile); - std::string line; - if (file.is_open()) { - while (!file.eof()) { - getline(file, line); - std::pair<std::string, std::string> r = String::getSplittedAtFirst(line, ' '); - JID jid(r.second); - if (jid.isValid()) { - jidAvatars.insert(std::make_pair(jid, r.first)); - } - else if (!r.first.empty() || !r.second.empty()) { - std::cerr << "Invalid entry in avatars file: " << r.second << std::endl; - } - } - } - } - catch (...) { - std::cerr << "Error reading avatars file" << std::endl; - } - } -} - -bool AvatarFileStorage::hasAvatar(const std::string& hash) const { - return boost::filesystem::exists(getAvatarPath(hash)); -} - -void AvatarFileStorage::addAvatar(const std::string& hash, const ByteArray& avatar) { - assert(Hexify::hexify(SHA1::getHash(avatar)) == hash); - - boost::filesystem::path avatarPath = getAvatarPath(hash); - if (!boost::filesystem::exists(avatarPath.parent_path())) { - try { - boost::filesystem::create_directories(avatarPath.parent_path()); - } - catch (const boost::filesystem::filesystem_error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - } - } - boost::filesystem::ofstream file(avatarPath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out); - file.write(reinterpret_cast<const char*>(avatar.getData()), avatar.getSize()); - file.close(); -} - -boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash) const { - return avatarsDir / hash; -} - -ByteArray AvatarFileStorage::getAvatar(const std::string& hash) const { - ByteArray data; - data.readFromFile(getAvatarPath(hash).string()); - return data; -} - -void AvatarFileStorage::setAvatarForJID(const JID& jid, const std::string& hash) { - std::pair<JIDAvatarMap::iterator, bool> r = jidAvatars.insert(std::make_pair(jid, hash)); - if (r.second) { - saveJIDAvatars(); - } - else if (r.first->second != hash) { - r.first->second = hash; - saveJIDAvatars(); - } -} - -std::string AvatarFileStorage::getAvatarForJID(const JID& jid) const { - JIDAvatarMap::const_iterator i = jidAvatars.find(jid); - return i == jidAvatars.end() ? "" : i->second; -} - -void AvatarFileStorage::saveJIDAvatars() { - try { - boost::filesystem::ofstream file(avatarsFile); - for (JIDAvatarMap::const_iterator i = jidAvatars.begin(); i != jidAvatars.end(); ++i) { - file << i->second << " " << i->first.toString() << std::endl; - } - file.close(); - } - catch (...) { - std::cerr << "Error writing avatars file" << std::endl; - } -} - -} diff --git a/Swiften/Avatars/AvatarFileStorage.h b/Swiften/Avatars/AvatarFileStorage.h deleted file mode 100644 index e736230..0000000 --- a/Swiften/Avatars/AvatarFileStorage.h +++ /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. - */ - -#pragma once - -#include <map> -#include <string> -#include <boost/filesystem.hpp> - -#include <Swiften/JID/JID.h> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Avatars/AvatarStorage.h" - -namespace Swift { - class AvatarFileStorage : public AvatarStorage { - public: - AvatarFileStorage(const boost::filesystem::path& avatarsDir, const boost::filesystem::path& avatarsFile); - - virtual bool hasAvatar(const std::string& hash) const; - virtual void addAvatar(const std::string& hash, const ByteArray& avatar); - virtual ByteArray getAvatar(const std::string& hash) const; - - virtual boost::filesystem::path getAvatarPath(const std::string& hash) const; - - virtual void setAvatarForJID(const JID& jid, const std::string& hash); - virtual std::string getAvatarForJID(const JID& jid) const; - - private: - void saveJIDAvatars(); - - private: - boost::filesystem::path avatarsDir; - boost::filesystem::path avatarsFile; - typedef std::map<JID, std::string> JIDAvatarMap; - JIDAvatarMap jidAvatars; - }; - -} diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h index e1af451..3461973 100644 --- a/Swiften/Avatars/AvatarManager.h +++ b/Swiften/Avatars/AvatarManager.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/ByteArray.h> diff --git a/Swiften/Avatars/AvatarProvider.h b/Swiften/Avatars/AvatarProvider.h index 0f66904..d2d408e 100644 --- a/Swiften/Avatars/AvatarProvider.h +++ b/Swiften/Avatars/AvatarProvider.h @@ -6,9 +6,10 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" #include <string> +#include <Swiften/Base/boost_bsignals.h> + namespace Swift { class JID; diff --git a/Swiften/Avatars/AvatarStorage.h b/Swiften/Avatars/AvatarStorage.h index 48fc885..d1aff39 100644 --- a/Swiften/Avatars/AvatarStorage.h +++ b/Swiften/Avatars/AvatarStorage.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <string> namespace Swift { diff --git a/Swiften/Avatars/SConscript b/Swiften/Avatars/SConscript index 46ae897..9c219a4 100644 --- a/Swiften/Avatars/SConscript +++ b/Swiften/Avatars/SConscript @@ -1,7 +1,6 @@ Import("swiften_env") objects = swiften_env.SwiftenObject([ - "AvatarFileStorage.cpp", "VCardUpdateAvatarManager.cpp", "VCardAvatarManager.cpp", "OfflineAvatarManager.cpp", diff --git a/Swiften/Avatars/VCardAvatarManager.h b/Swiften/Avatars/VCardAvatarManager.h index 3f99dad..6c02ace 100644 --- a/Swiften/Avatars/VCardAvatarManager.h +++ b/Swiften/Avatars/VCardAvatarManager.h @@ -6,11 +6,8 @@ #pragma once -#include <map> - #include "Swiften/Avatars/AvatarProvider.h" #include "Swiften/JID/JID.h" -#include "Swiften/Elements/VCard.h" namespace Swift { class MUCRegistry; diff --git a/Swiften/Base/ByteArray.cpp b/Swiften/Base/ByteArray.cpp index 928e145..323c866 100644 --- a/Swiften/Base/ByteArray.cpp +++ b/Swiften/Base/ByteArray.cpp @@ -9,6 +9,10 @@ #include <fstream> std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s) { + return operator<<(os, s.getDataVector()); +} + +std::ostream& operator<<(std::ostream& os, const std::vector<unsigned char>& s) { std::ios::fmtflags oldFlags = os.flags(); os << std::hex; for (Swift::ByteArray::const_iterator i = s.begin(); i != s.end(); ++i) { @@ -37,4 +41,45 @@ void ByteArray::readFromFile(const std::string& file) { input.close(); } +std::vector<unsigned char> ByteArray::create(const std::string& s) { + return std::vector<unsigned char>(s.begin(), s.end()); +} + +std::vector<unsigned char> ByteArray::create(const char* c) { + std::vector<unsigned char> data; + while (*c) { + data.push_back(static_cast<unsigned char>(*c)); + ++c; + } + return data; +} + +std::vector<unsigned char> ByteArray::create(const char* c, size_t n) { + std::vector<unsigned char> data; + if (n > 0) { + data.resize(n); + memcpy(&data[0], c, n); + } + return data; +} + +std::vector<unsigned char> ByteArray::create(const unsigned char* c, size_t n) { + std::vector<unsigned char> data; + if (n > 0) { + data.resize(n); + memcpy(&data[0], c, n); + } + return data; +} + +std::string ByteArray::toString() const { + size_t i; + for (i = data_.size(); i > 0; --i) { + if (data_[i - 1] != 0) { + break; + } + } + return i > 0 ? std::string(reinterpret_cast<const char*>(getData()), i) : ""; +} + } diff --git a/Swiften/Base/ByteArray.h b/Swiften/Base/ByteArray.h index ad2c1e5..ebc22d8 100644 --- a/Swiften/Base/ByteArray.h +++ b/Swiften/Base/ByteArray.h @@ -6,11 +6,9 @@ #pragma once -#include <cstring> #include <vector> -#include <iostream> - #include <string> +#include <cstring> // for memcpy namespace Swift { class ByteArray @@ -24,7 +22,7 @@ namespace Swift { ByteArray(const char* c) { while (*c) { - data_.push_back(*c); + data_.push_back(static_cast<unsigned char>(*c)); ++c; } } @@ -75,7 +73,7 @@ namespace Swift { } void resize(size_t size, char c) { - return data_.resize(size, c); + return data_.resize(size, static_cast<unsigned char>(c)); } friend ByteArray operator+(const ByteArray& a, const ByteArray&b) { @@ -87,7 +85,7 @@ namespace Swift { friend ByteArray operator+(const ByteArray& a, char b) { ByteArray x; x.resize(1); - x[0] = b; + x[0] = static_cast<unsigned char>(b); return a + x; } @@ -97,7 +95,7 @@ namespace Swift { } ByteArray& operator+=(char c) { - data_.push_back(c); + data_.push_back(static_cast<unsigned char>(c)); return *this; } @@ -122,9 +120,7 @@ namespace Swift { return data_.end(); } - std::string toString() const { - return std::string(reinterpret_cast<const char*>(getData()), getSize()); - } + std::string toString() const; void readFromFile(const std::string& file); @@ -132,9 +128,27 @@ namespace Swift { data_.clear(); } + const std::vector<unsigned char>& getDataVector() const { + return data_; + } + + static std::vector<unsigned char> create(const std::string& s); + static std::vector<unsigned char> create(const char* c); + static std::vector<unsigned char> create(const unsigned char* c, size_t n); + static std::vector<unsigned char> create(const char* c, size_t n); + + static const unsigned char* data(const std::vector<unsigned char>& v) { + return v.empty() ? NULL : &v[0]; + } + + static const char* charData(const std::vector<unsigned char>& v) { + return v.empty() ? NULL : reinterpret_cast<const char*>(&v[0]); + } + private: std::vector<unsigned char> data_; }; } std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s); +std::ostream& operator<<(std::ostream& os, const std::vector<unsigned char>& s); diff --git a/Swiften/Base/IDGenerator.h b/Swiften/Base/IDGenerator.h index 4b6289b..d536dcc 100644 --- a/Swiften/Base/IDGenerator.h +++ b/Swiften/Base/IDGenerator.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IDGenerator_H -#define SWIFTEN_IDGenerator_H +#pragma once #include <string> @@ -20,5 +19,3 @@ namespace Swift { std::string currentID_; }; } - -#endif diff --git a/Swiften/Base/Paths.cpp b/Swiften/Base/Paths.cpp index 43eee57..d901ff9 100644 --- a/Swiften/Base/Paths.cpp +++ b/Swiften/Base/Paths.cpp @@ -25,7 +25,7 @@ boost::filesystem::path Paths::getExecutablePath() { uint32_t size = 4096; path.resize(size); if (_NSGetExecutablePath(reinterpret_cast<char*>(path.getData()), &size) == 0) { - return boost::filesystem::path(path.toString().c_str()).parent_path(); + return boost::filesystem::path(std::string(reinterpret_cast<const char*>(path.getData()), path.getSize()).c_str()).parent_path(); } #elif defined(SWIFTEN_PLATFORM_LINUX) ByteArray path; @@ -33,13 +33,13 @@ boost::filesystem::path Paths::getExecutablePath() { size_t size = readlink("/proc/self/exe", reinterpret_cast<char*>(path.getData()), path.getSize()); if (size > 0) { path.resize(size); - return boost::filesystem::path(path.toString().c_str()).parent_path(); + return boost::filesystem::path(std::string(reinterpret_cast<const char*>(path.getData()), path.getSize()).c_str()).parent_path(); } #elif defined(SWIFTEN_PLATFORM_WINDOWS) ByteArray data; data.resize(2048); GetModuleFileName(NULL, reinterpret_cast<char*>(data.getData()), data.getSize()); - return boost::filesystem::path(data.toString().c_str()).parent_path(); + return boost::filesystem::path(std::string(reinterpret_cast<const char*>(data.getData()), data.getSize()).c_str()).parent_path(); #endif return boost::filesystem::path(); } diff --git a/Swiften/Base/Paths.h b/Swiften/Base/Paths.h index 06c6aeb..8ac4640 100644 --- a/Swiften/Base/Paths.h +++ b/Swiften/Base/Paths.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> namespace Swift { class Paths { diff --git a/Swiften/Base/Platform.h b/Swiften/Base/Platform.h index 32e2671..395747c 100644 --- a/Swiften/Base/Platform.h +++ b/Swiften/Base/Platform.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_Platform_H -#define SWIFTEN_Platform_H +#pragma once // Base platforms #if defined(linux) || defined(__linux) || defined(__linux__) @@ -26,6 +25,10 @@ #define SWIFTEN_PLATFORM_BEOS #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #define SWIFTEN_PLATFORM_MACOSX +#include <TargetConditionals.h> +# if defined(TARGET_OS_IPHONE) +# define SWIFTEN_PLATFORM_IPHONE +# endif #elif defined(__IBMCPP__) || defined(_AIX) #define SWIFTEN_PLATFORM_AIX #elif defined(__amigaos__) @@ -46,5 +49,3 @@ #elif defined(BOOST_BIG_ENDIAN) #define SWIFTEN_BIG_ENDIAN #endif - -#endif diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h index 192d53b..0de6cac 100644 --- a/Swiften/Base/String.h +++ b/Swiften/Base/String.h @@ -6,7 +6,6 @@ #pragma once -#include <map> #include <string> #include <vector> diff --git a/Swiften/Base/UnitTest/ByteArrayTest.cpp b/Swiften/Base/UnitTest/ByteArrayTest.cpp index cb10dd4..069e68e 100644 --- a/Swiften/Base/UnitTest/ByteArrayTest.cpp +++ b/Swiften/Base/UnitTest/ByteArrayTest.cpp @@ -8,12 +8,17 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include "Swiften/Base/ByteArray.h" +#include <boost/lexical_cast.hpp> using namespace Swift; class ByteArrayTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ByteArrayTest); CPPUNIT_TEST(testGetData_NoData); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST(testToString_NullTerminated); + CPPUNIT_TEST(testToString_TwoNullTerminated); + CPPUNIT_TEST(testToString_AllNull); CPPUNIT_TEST_SUITE_END(); public: @@ -22,6 +27,30 @@ class ByteArrayTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(reinterpret_cast<const char*>(NULL), reinterpret_cast<const char*>(testling.getData())); } + + void testToString() { + ByteArray testling(ByteArray::create("abcde")); + + CPPUNIT_ASSERT_EQUAL(std::string("abcde"), testling.toString()); + } + + void testToString_NullTerminated() { + ByteArray testling(ByteArray::create("abcde\0", 6)); + + CPPUNIT_ASSERT_EQUAL(std::string("abcde"), testling.toString()); + } + + void testToString_TwoNullTerminated() { + ByteArray testling(ByteArray::create("abcde\0\0", 7)); + + CPPUNIT_ASSERT_EQUAL(std::string("abcde"), testling.toString()); + } + + void testToString_AllNull() { + ByteArray testling(ByteArray::create("\0\0", 2)); + + CPPUNIT_ASSERT_EQUAL(std::string(""), testling.toString()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(ByteArrayTest); diff --git a/Swiften/Base/foreach.h b/Swiften/Base/foreach.h index 05366d6..87f6147 100644 --- a/Swiften/Base/foreach.h +++ b/Swiften/Base/foreach.h @@ -4,12 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_FOREACH_H -#define SWIFTEN_FOREACH_H +#pragma once #include <boost/foreach.hpp> #undef foreach #define foreach BOOST_FOREACH - -#endif diff --git a/Swiften/Base/format.h b/Swiften/Base/format.h index 4591827..0e49eaa 100644 --- a/Swiften/Base/format.h +++ b/Swiften/Base/format.h @@ -7,6 +7,7 @@ #pragma once #include <boost/format.hpp> +#include <iostream> namespace Swift { inline boost::format format(const std::string& s) { diff --git a/Swiften/Base/sleep.h b/Swiften/Base/sleep.h index c2bc601..a95e907 100644 --- a/Swiften/Base/sleep.h +++ b/Swiften/Base/sleep.h @@ -4,11 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_sleep_H -#define SWIFTEN_sleep_H +#pragma once namespace Swift { void sleep(unsigned int msecs); } - -#endif diff --git a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp index 5d7961b..aa16892 100644 --- a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp +++ b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp @@ -8,6 +8,7 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> +#include <Swiften/Base/foreach.h> #include "Swiften/Chat/ChatStateNotifier.h" #include "Swiften/Client/DummyStanzaChannel.h" #include "Swiften/Disco/DummyEntityCapsProvider.h" diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 7918c46..5a3450c 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -25,6 +25,7 @@ #include "Swiften/Presence/SubscriptionManager.h" #include "Swiften/TLS/BlindCertificateTrustChecker.h" #include <Swiften/Client/NickManagerImpl.h> +#include <Swiften/Client/ClientSession.h> namespace Swift { @@ -35,7 +36,7 @@ Client::Client(const JID& jid, const std::string& password, NetworkFactories* ne softwareVersionResponder->start(); roster = new XMPPRosterImpl(); - rosterController = new XMPPRosterController(getIQRouter(), roster); + rosterController = new XMPPRosterController(getIQRouter(), roster, getStorages()->getRosterStorage()); subscriptionManager = new SubscriptionManager(getStanzaChannel()); @@ -98,6 +99,11 @@ void Client::setSoftwareVersion(const std::string& name, const std::string& vers } void Client::requestRoster() { + // FIXME: We should set this once when the session is finished, but there + // is currently no callback for this + if (getSession()) { + rosterController->setUseVersioning(getSession()->getRosterVersioningSupported()); + } rosterController->requestRoster(); } diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index 083b8a0..05c1e6e 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Client/CoreClient.h" +#include <Swiften/Client/CoreClient.h> namespace Swift { class SoftwareVersionResponder; @@ -85,12 +85,12 @@ namespace Swift { /** * Returns the last received presence for the given (full) JID. */ - Presence::ref getLastPresence(const JID& jid) const; + boost::shared_ptr<Presence> getLastPresence(const JID& jid) const; /** * Returns the presence with the highest priority received for the given JID. */ - Presence::ref getHighestPriorityPresence(const JID& bareJID) const; + boost::shared_ptr<Presence> getHighestPriorityPresence(const JID& bareJID) const; PresenceOracle* getPresenceOracle() const { return presenceOracle; @@ -142,7 +142,7 @@ namespace Swift { /** * This signal is emitted when a JID changes presence. */ - boost::signal<void (Presence::ref)> onPresenceChange; + boost::signal<void (boost::shared_ptr<Presence>)> onPresenceChange; private: Storages* getStorages() const; diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h new file mode 100644 index 0000000..1155b46 --- /dev/null +++ b/Swiften/Client/ClientOptions.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +struct ClientOptions { + enum UseTLS { + NeverUseTLS, + UseTLSWhenAvailable + }; + + ClientOptions() : useStreamCompression(true), useTLS(UseTLSWhenAvailable), useStreamResumption(false) { + } + + /** + * Whether ZLib stream compression should be used when available. + * + * Default: true + */ + bool useStreamCompression; + + /** + * Sets whether TLS encryption should be used. + * + * Default: UseTLSWhenAvailable + */ + UseTLS useTLS; + + /** + * Use XEP-196 stream resumption when available. + * + * Default: false + */ + bool useStreamResumption; +}; + diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index e1c1d8e..cadc9a4 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -54,6 +54,7 @@ ClientSession::ClientSession( needSessionStart(false), needResourceBind(false), needAcking(false), + rosterVersioningSupported(false), authenticator(NULL), certificateTrustChecker(NULL) { } @@ -223,6 +224,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else { // Start the session + rosterVersioningSupported = streamFeatures->hasRosterVersioning(); stream->setWhitespacePingEnabled(true); needSessionStart = streamFeatures->hasSession(); needResourceBind = streamFeatures->hasResourceBind(); diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index 25ee694..4447f57 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -89,6 +89,10 @@ namespace Swift { return stanzaAckRequester_; } + bool getRosterVersioningSupported() const { + return rosterVersioningSupported; + } + const JID& getLocalJID() const { return localJID; } @@ -153,6 +157,7 @@ namespace Swift { bool needSessionStart; bool needResourceBind; bool needAcking; + bool rosterVersioningSupported; ClientAuthenticator* authenticator; boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_; boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_; diff --git a/Swiften/Client/ClientSessionStanzaChannel.cpp b/Swiften/Client/ClientSessionStanzaChannel.cpp index 6b32b3d..85d9dec 100644 --- a/Swiften/Client/ClientSessionStanzaChannel.cpp +++ b/Swiften/Client/ClientSessionStanzaChannel.cpp @@ -7,6 +7,7 @@ #include "Swiften/Client/ClientSessionStanzaChannel.h" #include <boost/bind.hpp> +#include <iostream> namespace Swift { diff --git a/Swiften/Client/ClientXMLTracer.cpp b/Swiften/Client/ClientXMLTracer.cpp new file mode 100644 index 0000000..a26ce66 --- /dev/null +++ b/Swiften/Client/ClientXMLTracer.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Client/ClientXMLTracer.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +ClientXMLTracer::ClientXMLTracer(CoreClient* client) { + client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, '<', _1)); + client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, '>', _1)); +} + +void ClientXMLTracer::printData(char direction, const std::string& data) { + printLine(direction); + std::cerr << data << std::endl; +} + +void ClientXMLTracer::printLine(char c) { + for (unsigned int i = 0; i < 80; ++i) { + std::cerr << c; + } + std::cerr << std::endl; +} + +} diff --git a/Swiften/Client/ClientXMLTracer.h b/Swiften/Client/ClientXMLTracer.h index bca2a54..617c53f 100644 --- a/Swiften/Client/ClientXMLTracer.h +++ b/Swiften/Client/ClientXMLTracer.h @@ -6,29 +6,15 @@ #pragma once -#include <boost/bind.hpp> - #include <Swiften/Client/CoreClient.h> namespace Swift { class ClientXMLTracer { public: - ClientXMLTracer(CoreClient* client) { - client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, '<', _1)); - client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, '>', _1)); - } + ClientXMLTracer(CoreClient* client); private: - static void printData(char direction, const std::string& data) { - printLine(direction); - std::cerr << data << std::endl; - } - - static void printLine(char c) { - for (unsigned int i = 0; i < 80; ++i) { - std::cerr << c; - } - std::cerr << std::endl; - } + static void printData(char direction, const std::string& data); + static void printLine(char c); }; } diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index f0c5333..de40517 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -7,11 +7,12 @@ #include "Swiften/Client/CoreClient.h" #include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> #include "Swiften/Client/ClientSession.h" #include "Swiften/TLS/PlatformTLSFactories.h" #include "Swiften/TLS/CertificateVerificationError.h" -#include "Swiften/Network/Connector.h" +#include <Swiften/Network/ChainedConnector.h> #include "Swiften/Network/NetworkFactories.h" #include "Swiften/TLS/PKCS12Certificate.h" #include "Swiften/Session/BasicSessionStream.h" @@ -19,10 +20,14 @@ #include "Swiften/Base/IDGenerator.h" #include "Swiften/Client/ClientSessionStanzaChannel.h" #include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include "Swiften/Network/PlatformProxyProvider.h" +#include "Swiften/Network/SOCKS5ProxiedConnectionFactory.h" +#include "Swiften/Network/HTTPConnectProxiedConnectionFactory.h" namespace Swift { -CoreClient::CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), useStreamCompression(true), useTLS(UseTLSWhenAvailable), disconnectRequested_(false), certificateTrustChecker(NULL) { +CoreClient::CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), disconnectRequested_(false), certificateTrustChecker(NULL) { stanzaChannel_ = new ClientSessionStanzaChannel(); stanzaChannel_->onMessageReceived.connect(boost::bind(&CoreClient::handleMessageReceived, this, _1)); stanzaChannel_->onPresenceReceived.connect(boost::bind(&CoreClient::handlePresenceReceived, this, _1)); @@ -47,8 +52,9 @@ CoreClient::~CoreClient() { delete stanzaChannel_; } -void CoreClient::connect() { +void CoreClient::connect(const ClientOptions& o) { SWIFT_LOG(debug) << "Connecting" << std::endl; + options = o; connect(jid_.getDomain()); } @@ -56,7 +62,19 @@ void CoreClient::connect(const std::string& host) { SWIFT_LOG(debug) << "Connecting to host " << host << std::endl; disconnectRequested_ = false; assert(!connector_); - connector_ = Connector::create(host, networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory()); + + assert(proxyConnectionFactories.empty()); + PlatformProxyProvider proxyProvider; + if(proxyProvider.getSOCKS5Proxy().isValid()) { + proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getConnectionFactory(), proxyProvider.getSOCKS5Proxy())); + } + if(proxyProvider.getHTTPConnectProxy().isValid()) { + proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getConnectionFactory(), proxyProvider.getHTTPConnectProxy())); + } + std::vector<ConnectionFactory*> connectionFactories(proxyConnectionFactories); + connectionFactories.push_back(networkFactories->getConnectionFactory()); + + connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); connector_->setTimeoutMilliseconds(60*1000); connector_->start(); @@ -65,6 +83,10 @@ void CoreClient::connect(const std::string& host) { void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection) { connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); connector_.reset(); + foreach(ConnectionFactory* f, proxyConnectionFactories) { + delete f; + } + if (!connection) { onDisconnected(disconnectRequested_ ? boost::optional<ClientError>() : boost::optional<ClientError>(ClientError::ConnectionError)); } @@ -82,12 +104,12 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio session_ = ClientSession::create(jid_, sessionStream_); session_->setCertificateTrustChecker(certificateTrustChecker); - session_->setUseStreamCompression(useStreamCompression); - switch(useTLS) { - case UseTLSWhenAvailable: + session_->setUseStreamCompression(options.useStreamCompression); + switch(options.useTLS) { + case ClientOptions::UseTLSWhenAvailable: session_->setUseTLS(ClientSession::UseTLSWhenAvailable); break; - case NeverUseTLS: + case ClientOptions::NeverUseTLS: session_->setUseTLS(ClientSession::NeverUseTLS); break; } @@ -275,13 +297,25 @@ void CoreClient::handleStanzaAcked(Stanza::ref stanza) { onStanzaAcked(stanza); } -void CoreClient::setUseStreamCompression(bool b) { - useStreamCompression = b; +bool CoreClient::isAvailable() const { + return stanzaChannel_->isAvailable(); } -void CoreClient::setUseTLS(UseTLS b) { - useTLS = b; +bool CoreClient::getStreamManagementEnabled() const { + return stanzaChannel_->getStreamManagementEnabled(); } +StanzaChannel* CoreClient::getStanzaChannel() const { + return stanzaChannel_; +} + +const JID& CoreClient::getJID() const { + if (session_) { + return session_->getLocalJID(); + } + else { + return jid_; + } +} } diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index eb9c42c..7c46fe7 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -6,35 +6,33 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <string> #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Network/PlatformDomainNameResolver.h" -#include "Swiften/Network/Connector.h" -#include "Swiften/Base/Error.h" -#include "Swiften/Client/ClientSession.h" -#include "Swiften/Client/ClientError.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/JID/JID.h" -#include <string> -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" #include <Swiften/Entity/Entity.h> - -#include "Swiften/Client/ClientSessionStanzaChannel.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Client/ClientError.h> +#include <Swiften/Client/ClientOptions.h> namespace Swift { + class ChainedConnector; + class Message; + class Presence; + class Error; class IQRouter; class TLSContextFactory; class ConnectionFactory; + class Connection; class TimerFactory; class ClientSession; + class StanzaChannel; + class Stanza; class BasicSessionStream; class PlatformTLSFactories; class CertificateTrustChecker; class NetworkFactories; + class ClientSessionStanzaChannel; /** * The central class for communicating with an XMPP server. @@ -48,11 +46,6 @@ namespace Swift { */ class CoreClient : public Entity { public: - enum UseTLS { - NeverUseTLS, - UseTLSWhenAvailable - }; - /** * Constructs a client for the given JID with the given password. * The given eventLoop will be used to post events to. @@ -68,7 +61,7 @@ namespace Swift { * After the connection is established, the client will set * initialize the stream and authenticate. */ - void connect(); + void connect(const ClientOptions& = ClientOptions()); /** * Disconnects the client from the server. @@ -80,12 +73,12 @@ namespace Swift { /** * Sends a message. */ - void sendMessage(Message::ref); + void sendMessage(boost::shared_ptr<Message>); /** * Sends a presence stanza. */ - void sendPresence(Presence::ref); + void sendPresence(boost::shared_ptr<Presence>); /** * Sends raw, unchecked data. @@ -103,9 +96,7 @@ namespace Swift { * Checks whether the client is connected to the server, * and stanzas can be sent. */ - bool isAvailable() const { - return stanzaChannel_->isAvailable(); - } + bool isAvailable() const; /** * Checks whether the client is active. @@ -118,14 +109,7 @@ namespace Swift { * Returns the JID of the client. * After the session was initialized, this returns the bound JID. */ - const JID& getJID() const { - if (session_) { - return session_->getLocalJID(); - } - else { - return jid_; - } - } + const JID& getJID() const; /** * Checks whether stream management is enabled. @@ -135,13 +119,9 @@ namespace Swift { * * \see onStanzaAcked */ - bool getStreamManagementEnabled() const { - return stanzaChannel_->getStreamManagementEnabled(); - } + bool getStreamManagementEnabled() const; - StanzaChannel* getStanzaChannel() const { - return stanzaChannel_; - } + StanzaChannel* getStanzaChannel() const; /** * Sets the certificate trust checker. @@ -153,16 +133,6 @@ namespace Swift { */ void setCertificateTrustChecker(CertificateTrustChecker*); - /** - * Sets whether ZLib stream compression should be used when available. - */ - void setUseStreamCompression(bool b); - - /** - * Sets whether TLS encryption should be used. - */ - void setUseTLS(UseTLS useTLS); - public: /** * Emitted when the client was disconnected from the network. @@ -197,12 +167,12 @@ namespace Swift { /** * Emitted when a message is received. */ - boost::signal<void (Message::ref)> onMessageReceived; + boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived; /** * Emitted when a presence stanza is received. */ - boost::signal<void (Presence::ref) > onPresenceReceived; + boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived; /** * Emitted when the server acknowledges receipt of a @@ -210,7 +180,12 @@ namespace Swift { * * \see getStreamManagementEnabled() */ - boost::signal<void (Stanza::ref)> onStanzaAcked; + boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked; + + protected: + boost::shared_ptr<ClientSession> getSession() const { + return session_; + } private: void handleConnectorFinished(boost::shared_ptr<Connection>); @@ -219,19 +194,19 @@ namespace Swift { void handleNeedCredentials(); void handleDataRead(const std::string&); void handleDataWritten(const std::string&); - void handlePresenceReceived(Presence::ref); - void handleMessageReceived(Message::ref); - void handleStanzaAcked(Stanza::ref); + void handlePresenceReceived(boost::shared_ptr<Presence>); + void handleMessageReceived(boost::shared_ptr<Message>); + void handleStanzaAcked(boost::shared_ptr<Stanza>); private: JID jid_; std::string password_; NetworkFactories* networkFactories; - bool useStreamCompression; - UseTLS useTLS; ClientSessionStanzaChannel* stanzaChannel_; IQRouter* iqRouter_; - Connector::ref connector_; + ClientOptions options; + boost::shared_ptr<ChainedConnector> connector_; + std::vector<ConnectionFactory*> proxyConnectionFactories; PlatformTLSFactories* tlsFactories; boost::shared_ptr<Connection> connection_; boost::shared_ptr<BasicSessionStream> sessionStream_; diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index b9f05c3..306e2b4 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -56,6 +56,22 @@ namespace Swift { return iqStanza && iqStanza->getType() == type && iqStanza->getTo() == jid && iqStanza->getPayload<T>(); } + bool isResultAtIndex(size_t index, const std::string& id) { + if (index >= sentStanzas.size()) { + return false; + } + boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]); + return iqStanza && iqStanza->getType() == IQ::Result && iqStanza->getID() == id; + } + + bool isErrorAtIndex(size_t index, const std::string& id) { + if (index >= sentStanzas.size()) { + return false; + } + boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]); + return iqStanza && iqStanza->getType() == IQ::Error && iqStanza->getID() == id; + } + template<typename T> boost::shared_ptr<T> getStanzaAtIndex(size_t index) { if (sentStanzas.size() <= index) { return boost::shared_ptr<T>(); diff --git a/Swiften/Client/FileStorages.cpp b/Swiften/Client/FileStorages.cpp deleted file mode 100644 index 3c76c46..0000000 --- a/Swiften/Client/FileStorages.cpp +++ /dev/null @@ -1,39 +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/Client/FileStorages.h" -#include "Swiften/VCards/VCardFileStorage.h" -#include "Swiften/Avatars/AvatarFileStorage.h" -#include "Swiften/Disco/CapsFileStorage.h" - -namespace Swift { - -FileStorages::FileStorages(const boost::filesystem::path& baseDir, const JID& jid) { - std::string profile = jid.toBare(); - vcardStorage = new VCardFileStorage(baseDir / profile / "vcards"); - capsStorage = new CapsFileStorage(baseDir / "caps"); - avatarStorage = new AvatarFileStorage(baseDir / "avatars", baseDir / profile / "avatars"); -} - -FileStorages::~FileStorages() { - delete avatarStorage; - delete capsStorage; - delete vcardStorage; -} - -VCardStorage* FileStorages::getVCardStorage() const { - return vcardStorage; -} - -CapsStorage* FileStorages::getCapsStorage() const { - return capsStorage; -} - -AvatarStorage* FileStorages::getAvatarStorage() const { - return avatarStorage; -} - -} diff --git a/Swiften/Client/FileStorages.h b/Swiften/Client/FileStorages.h deleted file mode 100644 index 451105f..0000000 --- a/Swiften/Client/FileStorages.h +++ /dev/null @@ -1,50 +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/filesystem.hpp> - -#include "Swiften/Client/Storages.h" - -namespace Swift { - class VCardFileStorage; - class AvatarFileStorage; - class CapsFileStorage; - class JID; - - /** - * A storages implementation that stores all controller data on disk. - */ - class FileStorages : public Storages { - public: - /** - * Creates the storages interface. - * - * All data will be stored relative to a base directory, and - * for some controllers, in a subdirectory for the given profile. - * The data is stored in the following places: - * - Avatars: <basedir>/avatars - * - VCards: <basedir>/<profile>/vcards - * - Entity capabilities: <basedir>/caps - * - * \param baseDir the base dir to store data relative to - * \param jid the subdir in which profile-specific data will be stored. - * The bare JID will be used as the subdir name. - */ - FileStorages(const boost::filesystem::path& baseDir, const JID& jid); - ~FileStorages(); - - virtual VCardStorage* getVCardStorage() const; - virtual AvatarStorage* getAvatarStorage() const; - virtual CapsStorage* getCapsStorage() const; - - private: - VCardFileStorage* vcardStorage; - AvatarFileStorage* avatarStorage; - CapsFileStorage* capsStorage; - }; -} diff --git a/Swiften/Client/MemoryStorages.cpp b/Swiften/Client/MemoryStorages.cpp index 5f6371b..6941add 100644 --- a/Swiften/Client/MemoryStorages.cpp +++ b/Swiften/Client/MemoryStorages.cpp @@ -8,6 +8,7 @@ #include "Swiften/VCards/VCardMemoryStorage.h" #include "Swiften/Avatars/AvatarMemoryStorage.h" #include "Swiften/Disco/CapsMemoryStorage.h" +#include "Swiften/Roster/RosterMemoryStorage.h" namespace Swift { @@ -15,9 +16,11 @@ MemoryStorages::MemoryStorages() { vcardStorage = new VCardMemoryStorage(); capsStorage = new CapsMemoryStorage(); avatarStorage = new AvatarMemoryStorage(); + rosterStorage = new RosterMemoryStorage(); } MemoryStorages::~MemoryStorages() { + delete rosterStorage; delete avatarStorage; delete capsStorage; delete vcardStorage; @@ -35,4 +38,9 @@ AvatarStorage* MemoryStorages::getAvatarStorage() const { return avatarStorage; } +RosterStorage* MemoryStorages::getRosterStorage() const { + return rosterStorage; +} + + } diff --git a/Swiften/Client/MemoryStorages.h b/Swiften/Client/MemoryStorages.h index 67025cd..1e1a596 100644 --- a/Swiften/Client/MemoryStorages.h +++ b/Swiften/Client/MemoryStorages.h @@ -23,10 +23,12 @@ namespace Swift { virtual VCardStorage* getVCardStorage() const; virtual AvatarStorage* getAvatarStorage() const; virtual CapsStorage* getCapsStorage() const; + virtual RosterStorage* getRosterStorage() const; private: VCardMemoryStorage* vcardStorage; AvatarStorage* avatarStorage; CapsStorage* capsStorage; + RosterStorage* rosterStorage; }; } diff --git a/Swiften/Client/NickResolver.h b/Swiften/Client/NickResolver.h index 881362a..bf373fa 100644 --- a/Swiften/Client/NickResolver.h +++ b/Swiften/Client/NickResolver.h @@ -5,9 +5,9 @@ */ #include <map> -#include <boost/signals.hpp> #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> #include <string> #include "Swiften/JID/JID.h" #include "Swiften/Elements/VCard.h" diff --git a/Swiften/Client/Storages.cpp b/Swiften/Client/Storages.cpp new file mode 100644 index 0000000..3c2dbc5 --- /dev/null +++ b/Swiften/Client/Storages.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Client/Storages.h> + +using namespace Swift; + +Storages::~Storages() { +} diff --git a/Swiften/Client/Storages.h b/Swiften/Client/Storages.h index e62f0a9..1c5bbe9 100644 --- a/Swiften/Client/Storages.h +++ b/Swiften/Client/Storages.h @@ -10,6 +10,7 @@ namespace Swift { class VCardStorage; class AvatarStorage; class CapsStorage; + class RosterStorage; /** * An interface to hold storage classes for different @@ -17,10 +18,11 @@ namespace Swift { */ class Storages { public: - virtual ~Storages() {} + virtual ~Storages(); virtual VCardStorage* getVCardStorage() const = 0; virtual AvatarStorage* getAvatarStorage() const = 0; virtual CapsStorage* getCapsStorage() const = 0; + virtual RosterStorage* getRosterStorage() const = 0; }; } diff --git a/Swiften/Component/ComponentSessionStanzaChannel.cpp b/Swiften/Component/ComponentSessionStanzaChannel.cpp index b9fecb2..b342714 100644 --- a/Swiften/Component/ComponentSessionStanzaChannel.cpp +++ b/Swiften/Component/ComponentSessionStanzaChannel.cpp @@ -7,6 +7,7 @@ #include "Swiften/Component/ComponentSessionStanzaChannel.h" #include <boost/bind.hpp> +#include <iostream> namespace Swift { diff --git a/Swiften/Component/ComponentXMLTracer.cpp b/Swiften/Component/ComponentXMLTracer.cpp new file mode 100644 index 0000000..b952c29 --- /dev/null +++ b/Swiften/Component/ComponentXMLTracer.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Component/ComponentXMLTracer.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +ComponentXMLTracer::ComponentXMLTracer(CoreComponent* client) { + client->onDataRead.connect(boost::bind(&ComponentXMLTracer::printData, '<', _1)); + client->onDataWritten.connect(boost::bind(&ComponentXMLTracer::printData, '>', _1)); +} + +void ComponentXMLTracer::printData(char direction, const std::string& data) { + printLine(direction); + std::cerr << data << std::endl; +} + +void ComponentXMLTracer::printLine(char c) { + for (unsigned int i = 0; i < 80; ++i) { + std::cerr << c; + } + std::cerr << std::endl; +} + +} diff --git a/Swiften/Component/ComponentXMLTracer.h b/Swiften/Component/ComponentXMLTracer.h index 70a617b..d7e2b46 100644 --- a/Swiften/Component/ComponentXMLTracer.h +++ b/Swiften/Component/ComponentXMLTracer.h @@ -6,29 +6,15 @@ #pragma once -#include <boost/bind.hpp> - #include "Swiften/Component/Component.h" namespace Swift { class ComponentXMLTracer { public: - ComponentXMLTracer(Component* component) { - component->onDataRead.connect(boost::bind(&ComponentXMLTracer::printData, '<', _1)); - component->onDataWritten.connect(boost::bind(&ComponentXMLTracer::printData, '>', _1)); - } + ComponentXMLTracer(CoreComponent* component); private: - static void printData(char direction, const std::string& data) { - printLine(direction); - std::cerr << data << std::endl; - } - - static void printLine(char c) { - for (unsigned int i = 0; i < 80; ++i) { - std::cerr << c; - } - std::cerr << std::endl; - } + static void printData(char direction, const std::string& data); + static void printLine(char c); }; } diff --git a/Swiften/Component/CoreComponent.cpp b/Swiften/Component/CoreComponent.cpp index e79d735..f995ab0 100644 --- a/Swiften/Component/CoreComponent.cpp +++ b/Swiften/Component/CoreComponent.cpp @@ -7,6 +7,7 @@ #include "Swiften/Component/CoreComponent.h" #include <boost/bind.hpp> +#include <iostream> #include "Swiften/Component/ComponentSession.h" #include "Swiften/Network/Connector.h" diff --git a/Swiften/Component/SConscript b/Swiften/Component/SConscript index 0a9f250..ef5700c 100644 --- a/Swiften/Component/SConscript +++ b/Swiften/Component/SConscript @@ -7,6 +7,7 @@ sources = [ "ComponentSessionStanzaChannel.cpp", "CoreComponent.cpp", "Component.cpp", + "ComponentXMLTracer.cpp", ] swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources)) diff --git a/Swiften/Compress/ZLibCompressor.cpp b/Swiften/Compress/ZLibCompressor.cpp index 7e3116e..b740c68 100644 --- a/Swiften/Compress/ZLibCompressor.cpp +++ b/Swiften/Compress/ZLibCompressor.cpp @@ -6,6 +6,8 @@ #include "Swiften/Compress/ZLibCompressor.h" +#include <cassert> + #pragma GCC diagnostic ignored "-Wold-style-cast" namespace Swift { diff --git a/Swiften/Compress/ZLibCompressor.h b/Swiften/Compress/ZLibCompressor.h index 7fe5387..e0b4759 100644 --- a/Swiften/Compress/ZLibCompressor.h +++ b/Swiften/Compress/ZLibCompressor.h @@ -6,8 +6,6 @@ #pragma once -#include <cassert> - #include "Swiften/Compress/ZLibCodecompressor.h" #include "Swiften/Base/ByteArray.h" diff --git a/Swiften/Compress/ZLibDecompressor.cpp b/Swiften/Compress/ZLibDecompressor.cpp index af7349b..78e9846 100644 --- a/Swiften/Compress/ZLibDecompressor.cpp +++ b/Swiften/Compress/ZLibDecompressor.cpp @@ -6,6 +6,8 @@ #include "Swiften/Compress/ZLibDecompressor.h" +#include <cassert> + #pragma GCC diagnostic ignored "-Wold-style-cast" namespace Swift { diff --git a/Swiften/Compress/ZLibDecompressor.h b/Swiften/Compress/ZLibDecompressor.h index ec08a4f..917e1b7 100644 --- a/Swiften/Compress/ZLibDecompressor.h +++ b/Swiften/Compress/ZLibDecompressor.h @@ -6,8 +6,6 @@ #pragma once -#include <cassert> - #include "Swiften/Compress/ZLibCodecompressor.h" #include "Swiften/Base/ByteArray.h" diff --git a/Swiften/Config/swiften-config.cpp b/Swiften/Config/swiften-config.cpp index b3875cb..0c46cf0 100644 --- a/Swiften/Config/swiften-config.cpp +++ b/Swiften/Config/swiften-config.cpp @@ -11,6 +11,7 @@ #include <boost/program_options/variables_map.hpp> #include <boost/program_options.hpp> #include <boost/version.hpp> +#include <boost/filesystem.hpp> #include <string> #include <Swiften/Base/Platform.h> diff --git a/Swiften/Disco/CapsFileStorage.cpp b/Swiften/Disco/CapsFileStorage.cpp deleted file mode 100644 index 1e53854..0000000 --- a/Swiften/Disco/CapsFileStorage.cpp +++ /dev/null @@ -1,61 +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/Disco/CapsFileStorage.h" - -#include <iostream> -#include <boost/filesystem/fstream.hpp> - -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h" -#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h" -#include "Swiften/StringCodecs/Hexify.h" -#include "Swiften/StringCodecs/Base64.h" - -namespace Swift { - -CapsFileStorage::CapsFileStorage(const boost::filesystem::path& path) : path(path) { -} - -DiscoInfo::ref CapsFileStorage::getDiscoInfo(const std::string& hash) const { - boost::filesystem::path capsPath(getCapsPath(hash)); - if (boost::filesystem::exists(capsPath)) { - ByteArray data; - data.readFromFile(capsPath.string()); - - DiscoInfoParser parser; - PayloadParserTester tester(&parser); - tester.parse(data.toString()); - return boost::dynamic_pointer_cast<DiscoInfo>(parser.getPayload()); - } - else { - return DiscoInfo::ref(); - } -} - -void CapsFileStorage::setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo) { - boost::filesystem::path capsPath(getCapsPath(hash)); - if (!boost::filesystem::exists(capsPath.parent_path())) { - try { - boost::filesystem::create_directories(capsPath.parent_path()); - } - catch (const boost::filesystem::filesystem_error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - } - } - DiscoInfo::ref bareDiscoInfo(new DiscoInfo(*discoInfo.get())); - bareDiscoInfo->setNode(""); - boost::filesystem::ofstream file(capsPath); - file << DiscoInfoSerializer().serializePayload(bareDiscoInfo); - file.close(); -} - -boost::filesystem::path CapsFileStorage::getCapsPath(const std::string& hash) const { - return path / (Hexify::hexify(Base64::decode(hash)) + ".xml"); -} - -} diff --git a/Swiften/Disco/CapsFileStorage.h b/Swiften/Disco/CapsFileStorage.h deleted file mode 100644 index 5faf08b..0000000 --- a/Swiften/Disco/CapsFileStorage.h +++ /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. - */ - -#pragma once - -#include <boost/filesystem.hpp> - -#include "Swiften/Disco/CapsStorage.h" -#include <string> - -namespace Swift { - class CapsFileStorage : public CapsStorage { - public: - CapsFileStorage(const boost::filesystem::path& path); - - virtual DiscoInfo::ref getDiscoInfo(const std::string& hash) const; - virtual void setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo); - - private: - boost::filesystem::path getCapsPath(const std::string& hash) const; - - private: - boost::filesystem::path path; - }; -} diff --git a/Swiften/Disco/CapsManager.cpp b/Swiften/Disco/CapsManager.cpp index 63166e6..6eb7c17 100644 --- a/Swiften/Disco/CapsManager.cpp +++ b/Swiften/Disco/CapsManager.cpp @@ -7,6 +7,7 @@ #include "Swiften/Disco/CapsManager.h" #include <boost/bind.hpp> +#include <iostream> #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Disco/CapsStorage.h" diff --git a/Swiften/Disco/DummyEntityCapsProvider.cpp b/Swiften/Disco/DummyEntityCapsProvider.cpp new file mode 100644 index 0000000..a906652 --- /dev/null +++ b/Swiften/Disco/DummyEntityCapsProvider.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Disco/DummyEntityCapsProvider.h> + +#include <iostream> + +namespace Swift { + +DiscoInfo::ref DummyEntityCapsProvider::getCaps(const JID& jid) const { + std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid); + if (i != caps.end()) { + return i->second; + } + return DiscoInfo::ref(); +} + +} diff --git a/Swiften/Disco/DummyEntityCapsProvider.h b/Swiften/Disco/DummyEntityCapsProvider.h index 68cef2f..1bd4bb9 100644 --- a/Swiften/Disco/DummyEntityCapsProvider.h +++ b/Swiften/Disco/DummyEntityCapsProvider.h @@ -7,7 +7,7 @@ #pragma once #include <map> -#include <iostream> + #include "Swiften/Disco/EntityCapsProvider.h" namespace Swift { @@ -16,13 +16,7 @@ namespace Swift { DummyEntityCapsProvider() { } - DiscoInfo::ref getCaps(const JID& jid) const { - std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid); - if (i != caps.end()) { - return i->second; - } - return DiscoInfo::ref(); - } + DiscoInfo::ref getCaps(const JID& jid) const; std::map<JID, DiscoInfo::ref> caps; }; diff --git a/Swiften/Disco/GetDiscoItemsRequest.h b/Swiften/Disco/GetDiscoItemsRequest.h index 0a94402..46735ef 100644 --- a/Swiften/Disco/GetDiscoItemsRequest.h +++ b/Swiften/Disco/GetDiscoItemsRequest.h @@ -18,9 +18,18 @@ namespace Swift { return ref(new GetDiscoItemsRequest(jid, router)); } + static ref create(const JID& jid, const std::string& node, IQRouter* router) { + return ref(new GetDiscoItemsRequest(jid, node, router)); + } + private: GetDiscoItemsRequest(const JID& jid, IQRouter* router) : GenericRequest<DiscoItems>(IQ::Get, jid, boost::shared_ptr<DiscoItems>(new DiscoItems()), router) { } + + GetDiscoItemsRequest(const JID& jid, const std::string& node, IQRouter* router) : + GenericRequest<DiscoItems>(IQ::Get, jid, boost::shared_ptr<DiscoItems>(new DiscoItems()), router) { + getPayloadGeneric()->setNode(node); + } }; } diff --git a/Swiften/Disco/SConscript b/Swiften/Disco/SConscript index 9982192..434018a 100644 --- a/Swiften/Disco/SConscript +++ b/Swiften/Disco/SConscript @@ -5,8 +5,8 @@ objects = swiften_env.SwiftenObject([ "CapsManager.cpp", "EntityCapsManager.cpp", "EntityCapsProvider.cpp", + "DummyEntityCapsProvider.cpp", "CapsStorage.cpp", - "CapsFileStorage.cpp", "ClientDiscoManager.cpp", "DiscoInfoResponder.cpp", "JIDDiscoInfoResponder.cpp", diff --git a/Swiften/Elements/Body.h b/Swiften/Elements/Body.h index 2887390..a2497f7 100644 --- a/Swiften/Elements/Body.h +++ b/Swiften/Elements/Body.h @@ -6,14 +6,13 @@ #pragma once -#include "Swiften/Elements/Payload.h" #include <string> +#include <Swiften/Elements/Payload.h> + namespace Swift { class Body : public Payload { public: - typedef boost::shared_ptr<Body> ref; - Body(const std::string& text = "") : text_(text) { } diff --git a/Swiften/Elements/Bytestreams.h b/Swiften/Elements/Bytestreams.h index b493375..211396b 100644 --- a/Swiften/Elements/Bytestreams.h +++ b/Swiften/Elements/Bytestreams.h @@ -9,9 +9,9 @@ #include <vector> #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> +#include <string> #include "Swiften/JID/JID.h" -#include <string> #include "Swiften/Elements/Payload.h" namespace Swift { diff --git a/Swiften/Elements/CapsInfo.h b/Swiften/Elements/CapsInfo.h index ccad278..f1e2c37 100644 --- a/Swiften/Elements/CapsInfo.h +++ b/Swiften/Elements/CapsInfo.h @@ -7,8 +7,8 @@ #pragma once #include <boost/shared_ptr.hpp> - #include <string> + #include "Swiften/Elements/Payload.h" namespace Swift { diff --git a/Swiften/Elements/ChatState.h b/Swiften/Elements/ChatState.h index 2896877..ddeed79 100644 --- a/Swiften/Elements/ChatState.h +++ b/Swiften/Elements/ChatState.h @@ -7,6 +7,7 @@ #pragma once #include <string> + #include "Swiften/Elements/Payload.h" namespace Swift { diff --git a/Swiften/Elements/Command.h b/Swiften/Elements/Command.h index f4059a8..4a9c2a3 100644 --- a/Swiften/Elements/Command.h +++ b/Swiften/Elements/Command.h @@ -7,8 +7,8 @@ #pragma once #include <boost/shared_ptr.hpp> - #include <string> + #include "Swiften/Elements/Payload.h" #include "Swiften/Elements/Form.h" diff --git a/Swiften/Elements/ComponentHandshake.h b/Swiften/Elements/ComponentHandshake.h index 6047eab..3fe0457 100644 --- a/Swiften/Elements/ComponentHandshake.h +++ b/Swiften/Elements/ComponentHandshake.h @@ -7,9 +7,9 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <string> #include "Swiften/Elements/Element.h" -#include <string> namespace Swift { class ComponentHandshake : public Element { diff --git a/Swiften/Elements/Delay.h b/Swiften/Elements/Delay.h index 3213037..85d167b 100644 --- a/Swiften/Elements/Delay.h +++ b/Swiften/Elements/Delay.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> #include <boost/optional.hpp> #include "Swiften/Elements/Payload.h" diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp index f0e728e..5b2bb04 100644 --- a/Swiften/Elements/DiscoInfo.cpp +++ b/Swiften/Elements/DiscoInfo.cpp @@ -6,12 +6,15 @@ #include "Swiften/Elements/DiscoInfo.h" +#include <algorithm> + namespace Swift { const std::string DiscoInfo::ChatStatesFeature = std::string("http://jabber.org/protocol/chatstates"); const std::string DiscoInfo::SecurityLabelsFeature = std::string("urn:xmpp:sec-label:0"); const std::string DiscoInfo::SecurityLabelsCatalogFeature = std::string("urn:xmpp:sec-label:catalog:2"); const std::string DiscoInfo::JabberSearchFeature = std::string("jabber:iq:search"); +const std::string DiscoInfo::CommandsFeature = std::string("http://jabber.org/protocol/commands"); bool DiscoInfo::Identity::operator<(const Identity& other) const { @@ -33,4 +36,8 @@ bool DiscoInfo::Identity::operator<(const Identity& other) const { } } +bool DiscoInfo::hasFeature(const std::string& feature) const { + return std::find(features_.begin(), features_.end(), feature) != features_.end(); +} + } diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h index d5bf64a..cd650b9 100644 --- a/Swiften/Elements/DiscoInfo.h +++ b/Swiften/Elements/DiscoInfo.h @@ -7,11 +7,9 @@ #pragma once #include <vector> -#include <algorithm> - -#include "Swiften/Elements/Payload.h" #include <string> +#include "Swiften/Elements/Payload.h" #include "Swiften/Elements/Form.h" namespace Swift { @@ -23,6 +21,7 @@ namespace Swift { static const std::string SecurityLabelsFeature; static const std::string SecurityLabelsCatalogFeature; static const std::string JabberSearchFeature; + static const std::string CommandsFeature; class Identity { public: @@ -82,9 +81,7 @@ namespace Swift { features_.push_back(feature); } - bool hasFeature(const std::string& feature) const { - return std::find(features_.begin(), features_.end(), feature) != features_.end(); - } + bool hasFeature(const std::string& feature) const; void addExtension(Form::ref form) { extensions_.push_back(form); diff --git a/Swiften/Elements/DiscoItems.h b/Swiften/Elements/DiscoItems.h index cc5a583..1b7063b 100644 --- a/Swiften/Elements/DiscoItems.h +++ b/Swiften/Elements/DiscoItems.h @@ -7,10 +7,9 @@ #pragma once #include <vector> -#include <algorithm> +#include <string> #include "Swiften/Elements/Payload.h" -#include <string> #include "Swiften/JID/JID.h" namespace Swift { diff --git a/Swiften/Elements/Element.h b/Swiften/Elements/Element.h index aded528..1e6a9d0 100644 --- a/Swiften/Elements/Element.h +++ b/Swiften/Elements/Element.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ELEMENT_H -#define SWIFTEN_ELEMENT_H +#pragma once namespace Swift { class Element { @@ -13,5 +12,3 @@ namespace Swift { virtual ~Element(); }; } - -#endif diff --git a/Swiften/Elements/ErrorPayload.h b/Swiften/Elements/ErrorPayload.h index 12ad574..cece81f 100644 --- a/Swiften/Elements/ErrorPayload.h +++ b/Swiften/Elements/ErrorPayload.h @@ -7,9 +7,9 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <string> #include "Swiften/Elements/Payload.h" -#include <string> namespace Swift { class ErrorPayload : public Payload { diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h index 1c50f0c..4e6e9f1 100644 --- a/Swiften/Elements/Form.h +++ b/Swiften/Elements/Form.h @@ -7,11 +7,10 @@ #pragma once #include <vector> +#include <string> #include "Swiften/Elements/Payload.h" #include "Swiften/Elements/FormField.h" -#include <string> - #include "Swiften/JID/JID.h" namespace Swift { diff --git a/Swiften/Elements/FormField.h b/Swiften/Elements/FormField.h index f455303..2438bb3 100644 --- a/Swiften/Elements/FormField.h +++ b/Swiften/Elements/FormField.h @@ -11,8 +11,8 @@ #include <vector> #include <boost/shared_ptr.hpp> - #include <string> + #include "Swiften/JID/JID.h" namespace Swift { @@ -111,5 +111,4 @@ namespace Swift { SWIFTEN_DECLARE_FORM_FIELD(JIDSingle, JID); SWIFTEN_DECLARE_FORM_FIELD(JIDMulti, std::vector<JID>); SWIFTEN_DECLARE_FORM_FIELD(ListMulti, std::vector<std::string>); - SWIFTEN_DECLARE_FORM_FIELD(Untyped, std::vector<std::string>); } diff --git a/Swiften/Elements/IBB.h b/Swiften/Elements/IBB.h index 55f2c4f..8138e83 100644 --- a/Swiften/Elements/IBB.h +++ b/Swiften/Elements/IBB.h @@ -6,11 +6,11 @@ #pragma once +#include <string> +#include <vector> #include <boost/shared_ptr.hpp> -#include <string> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class IBB : public Payload { @@ -36,7 +36,7 @@ namespace Swift { return result; } - static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const ByteArray& data) { + static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const std::vector<unsigned char>& data) { IBB::ref result(new IBB(Data, streamID)); result->setSequenceNumber(sequenceNumber); result->setData(data); @@ -71,11 +71,11 @@ namespace Swift { return streamID; } - const ByteArray& getData() const { + const std::vector<unsigned char>& getData() const { return data; } - void setData(const ByteArray& data) { + void setData(const std::vector<unsigned char>& data) { this->data = data; } @@ -98,7 +98,7 @@ namespace Swift { private: Action action; std::string streamID; - ByteArray data; + std::vector<unsigned char> data; StanzaType stanzaType; int blockSize; int sequenceNumber; diff --git a/Swiften/Elements/InBandRegistrationPayload.h b/Swiften/Elements/InBandRegistrationPayload.h index e4e1e6f..6e0f741 100644 --- a/Swiften/Elements/InBandRegistrationPayload.h +++ b/Swiften/Elements/InBandRegistrationPayload.h @@ -8,10 +8,10 @@ #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> +#include <string> #include "Swiften/Elements/Payload.h" #include "Swiften/Elements/Form.h" -#include <string> namespace Swift { class InBandRegistrationPayload : public Payload { diff --git a/Swiften/Elements/JingleContent.h b/Swiften/Elements/JingleContentPayload.h index 4ae908b..c44a806 100644 --- a/Swiften/Elements/JingleContent.h +++ b/Swiften/Elements/JingleContentPayload.h @@ -8,18 +8,17 @@ #include <vector> #include <boost/optional.hpp> - #include <string> + #include <Swiften/JID/JID.h> #include <Swiften/Elements/Payload.h> #include <Swiften/Elements/JingleDescription.h> -#include <Swiften/Elements/JingleTransport.h> -#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/JingleTransportPayload.h> namespace Swift { - class JingleContent : public Payload { + class JingleContentPayload : public Payload { public: - typedef boost::shared_ptr<JingleContent> ref; + typedef boost::shared_ptr<JingleContentPayload> ref; enum Creator { InitiatorCreator, @@ -33,10 +32,18 @@ namespace Swift { BothSenders, };*/ + Creator getCreator() const { + return creator; + } + void setCreator(Creator creator) { this->creator = creator; } + const std::string& getName() const { + return name; + } + void setName(const std::string& name) { this->name = name; } @@ -49,18 +56,18 @@ namespace Swift { descriptions.push_back(description); } - const std::vector<JingleTransport::ref>& getTransports() const { + const std::vector<boost::shared_ptr<JingleTransportPayload> >& getTransports() const { return transports; } - void addTransport(JingleTransport::ref transport) { + void addTransport(boost::shared_ptr<JingleTransportPayload> transport) { transports.push_back(transport); } template<typename T> boost::shared_ptr<T> getDescription() const { - foreach (JingleDescription::ref i, descriptions) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < descriptions.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(descriptions[i])); if (result) { return result; } @@ -70,8 +77,8 @@ namespace Swift { template<typename T> boost::shared_ptr<T> getTransport() const { - foreach (JingleTransport::ref i, transports) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < transports.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(transports[i])); if (result) { return result; } @@ -84,6 +91,6 @@ namespace Swift { std::string name; //Senders senders; std::vector<JingleDescription::ref> descriptions; - std::vector<JingleTransport::ref> transports; + std::vector<boost::shared_ptr<JingleTransportPayload> > transports; }; } diff --git a/Swiften/Elements/JingleIBBTransport.h b/Swiften/Elements/JingleIBBTransportPayload.h index faa5af3..67aab09 100644 --- a/Swiften/Elements/JingleIBBTransport.h +++ b/Swiften/Elements/JingleIBBTransportPayload.h @@ -6,12 +6,16 @@ #pragma once +#include <boost/shared_ptr.hpp> #include <string> -#include <Swiften/Elements/JingleTransport.h> + +#include <Swiften/Elements/JingleTransportPayload.h> namespace Swift { - class JingleIBBTransport : public JingleTransport { + class JingleIBBTransportPayload : public JingleTransportPayload { public: + typedef boost::shared_ptr<JingleIBBTransportPayload> ref; + enum StanzaType { IQStanza, MessageStanza, diff --git a/Swiften/Elements/JinglePayload.h b/Swiften/Elements/JinglePayload.h index 59d3c99..be02543 100644 --- a/Swiften/Elements/JinglePayload.h +++ b/Swiften/Elements/JinglePayload.h @@ -12,7 +12,7 @@ #include <string> #include <Swiften/JID/JID.h> #include <Swiften/Elements/Payload.h> -#include <Swiften/Elements/JingleContent.h> +#include <Swiften/Elements/JingleContentPayload.h> namespace Swift { @@ -98,11 +98,11 @@ namespace Swift { return sessionID; } - void addContent(JingleContent::ref content) { + void addContent(JingleContentPayload::ref content) { this->contents.push_back(content); } - const std::vector<JingleContent::ref> getContents() const { + const std::vector<JingleContentPayload::ref> getContents() const { return contents; } @@ -119,7 +119,7 @@ namespace Swift { JID initiator; JID responder; std::string sessionID; - std::vector<JingleContent::ref> contents; + std::vector<JingleContentPayload::ref> contents; boost::optional<Reason> reason; }; } diff --git a/Swiften/Elements/JingleS5BTransport.h b/Swiften/Elements/JingleS5BTransportPayload.h index 4522417..7b3089f 100644 --- a/Swiften/Elements/JingleS5BTransport.h +++ b/Swiften/Elements/JingleS5BTransportPayload.h @@ -6,11 +6,13 @@ #pragma once -#include <Swiften/Elements/JingleTransport.h> +#include <Swiften/Elements/JingleTransportPayload.h> #include <Swiften/Elements/Bytestreams.h> +// FIXME: Remove Bytestreams, and replace by our own candidate + namespace Swift { - class JingleS5BTransport : public JingleTransport { + class JingleS5BTransportPayload : public JingleTransportPayload { public: const Bytestreams& getInfo() const { return info; diff --git a/Swiften/Elements/JingleTransportPayload.h b/Swiften/Elements/JingleTransportPayload.h new file mode 100644 index 0000000..7a9ea29 --- /dev/null +++ b/Swiften/Elements/JingleTransportPayload.h @@ -0,0 +1,18 @@ +/* + * 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/Elements/Payload.h> + +namespace Swift { + class JingleTransportPayload : public Payload { + public: + typedef boost::shared_ptr<JingleTransportPayload> ref; + }; +} diff --git a/Swiften/Elements/MUCPayload.h b/Swiften/Elements/MUCPayload.h index c372360..eb3baeb 100644 --- a/Swiften/Elements/MUCPayload.h +++ b/Swiften/Elements/MUCPayload.h @@ -7,7 +7,7 @@ #pragma once #include <boost/optional.hpp> -#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> #include "Swiften/JID/JID.h" #include <string> diff --git a/Swiften/Elements/Message.h b/Swiften/Elements/Message.h index a553eb3..3623e73 100644 --- a/Swiften/Elements/Message.h +++ b/Swiften/Elements/Message.h @@ -14,6 +14,7 @@ #include "Swiften/Elements/Subject.h" #include "Swiften/Elements/ErrorPayload.h" #include "Swiften/Elements/Stanza.h" +#include "Swiften/Elements/Replace.h" namespace Swift { class Message : public Stanza { diff --git a/Swiften/Elements/Payload.h b/Swiften/Elements/Payload.h index c87b899..8b6d44a 100644 --- a/Swiften/Elements/Payload.h +++ b/Swiften/Elements/Payload.h @@ -6,13 +6,9 @@ #pragma once -#include <boost/shared_ptr.hpp> - namespace Swift { class Payload { public: - typedef boost::shared_ptr<Payload> ref; - virtual ~Payload(); }; } diff --git a/Swiften/Elements/Presence.cpp b/Swiften/Elements/Presence.cpp new file mode 100644 index 0000000..6cde567 --- /dev/null +++ b/Swiften/Elements/Presence.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/Presence.h> + +#include <Swiften/Elements/Priority.h> +#include <Swiften/Elements/Status.h> + +namespace Swift { + +Presence::Presence() : type_(Available) /*, showType_(Online)*/ { +} + +Presence::Presence(const std::string& status) : type_(Available) { + setStatus(status); +} + +Presence::~Presence() { +} + +int Presence::getPriority() const { + boost::shared_ptr<Priority> priority(getPayload<Priority>()); + return (priority ? priority->getPriority() : 0); +} + +void Presence::setPriority(int priority) { + updatePayload(boost::shared_ptr<Priority>(new Priority(priority))); +} + +std::string Presence::getStatus() const { + boost::shared_ptr<Status> status(getPayload<Status>()); + if (status) { + return status->getText(); + } + return ""; +} + +void Presence::setStatus(const std::string& status) { + updatePayload(boost::shared_ptr<Status>(new Status(status))); +} + + +} diff --git a/Swiften/Elements/Presence.h b/Swiften/Elements/Presence.h index 7f957ba..5ae482b 100644 --- a/Swiften/Elements/Presence.h +++ b/Swiften/Elements/Presence.h @@ -6,11 +6,8 @@ #pragma once - -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Elements/Status.h" -#include "Swiften/Elements/StatusShow.h" -#include "Swiften/Elements/Priority.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Elements/StatusShow.h> namespace Swift { class Presence : public Stanza { @@ -19,10 +16,9 @@ namespace Swift { enum Type { Available, Error, Probe, Subscribe, Subscribed, Unavailable, Unsubscribe, Unsubscribed }; - Presence() : type_(Available) /*, showType_(Online)*/ {} - Presence(const std::string& status) : type_(Available) { - setStatus(status); - } + Presence(); + Presence(const std::string& status); + virtual ~Presence(); static ref create() { return ref(new Presence()); @@ -51,26 +47,11 @@ namespace Swift { updatePayload(boost::shared_ptr<StatusShow>(new StatusShow(show))); } - std::string getStatus() const { - boost::shared_ptr<Status> status(getPayload<Status>()); - if (status) { - return status->getText(); - } - return ""; - } + std::string getStatus() const; + void setStatus(const std::string& status); - void setStatus(const std::string& status) { - updatePayload(boost::shared_ptr<Status>(new Status(status))); - } - - int getPriority() const { - boost::shared_ptr<Priority> priority(getPayload<Priority>()); - return (priority ? priority->getPriority() : 0); - } - - void setPriority(int priority) { - updatePayload(boost::shared_ptr<Priority>(new Priority(priority))); - } + int getPriority() const; + void setPriority(int priority); boost::shared_ptr<Presence> clone() const { return boost::shared_ptr<Presence>(new Presence(*this)); diff --git a/Swiften/Elements/Priority.h b/Swiften/Elements/Priority.h index 12181d4..2c0cb9b 100644 --- a/Swiften/Elements/Priority.h +++ b/Swiften/Elements/Priority.h @@ -6,13 +6,11 @@ #pragma once -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class Priority : public Payload { public: - typedef boost::shared_ptr<Priority> ref; - Priority(int priority = 0) : priority_(priority) { } diff --git a/Swiften/Elements/Replace.h b/Swiften/Elements/Replace.h new file mode 100644 index 0000000..dc8ff59 --- /dev/null +++ b/Swiften/Elements/Replace.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * 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/Payload.h" + +namespace Swift { + class Replace : public Payload { + public: + typedef boost::shared_ptr<Replace> ref; + Replace(std::string id = "") : replaceID_(id) {}; + std::string getId() { + return replaceID_; + } + void setId(std::string id) { + replaceID_ = id; + } + private: + std::string replaceID_; + }; +} diff --git a/Swiften/Elements/RosterItemExchangePayload.cpp b/Swiften/Elements/RosterItemExchangePayload.cpp new file mode 100644 index 0000000..f4f3a57 --- /dev/null +++ b/Swiften/Elements/RosterItemExchangePayload.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Elements/RosterItemExchangePayload.h" +#include "Swiften/Base/foreach.h" + +namespace Swift { + +RosterItemExchangePayload::Item::Item() { +} + +RosterItemExchangePayload::RosterItemExchangePayload() { +} + +} diff --git a/Swiften/Elements/RosterItemExchangePayload.h b/Swiften/Elements/RosterItemExchangePayload.h new file mode 100644 index 0000000..d9e2912 --- /dev/null +++ b/Swiften/Elements/RosterItemExchangePayload.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> +#include <string> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Elements/Payload.h" +#include "Swiften/JID/JID.h" + + +namespace Swift { + class RosterItemExchangePayload : public Payload { + public: + typedef boost::shared_ptr<RosterItemExchangePayload> ref; + + class Item { + public: + enum Action { Add, Modify, Delete }; + + Item(); + + Action getAction() const { + return action; + } + + void setAction(Action action) { + this->action = action; + } + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& jid) { + this->jid = jid; + } + + const std::string& getName() const { + return name; + } + + void setName(const std::string& name) { + this->name = name; + } + + const std::vector<std::string>& getGroups() const { + return groups; + } + + void addGroup(const std::string& group) { + groups.push_back(group); + } + + private: + Action action; + JID jid; + std::string name; + std::vector<std::string> groups; + }; + + typedef std::vector<RosterItemExchangePayload::Item> RosterItemExchangePayloadItems; + + public: + RosterItemExchangePayload(); + + void addItem(const RosterItemExchangePayload::Item& item) { + items_.push_back(item); + } + + const RosterItemExchangePayloadItems& getItems() const { + return items_; + } + + private: + RosterItemExchangePayloadItems items_; + }; +} diff --git a/Swiften/Elements/RosterItemPayload.h b/Swiften/Elements/RosterItemPayload.h index b8a1b10..915ae31 100644 --- a/Swiften/Elements/RosterItemPayload.h +++ b/Swiften/Elements/RosterItemPayload.h @@ -4,22 +4,20 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterItemPayloadPayload_H -#define SWIFTEN_RosterItemPayloadPayload_H +#pragma once #include <vector> - -#include "Swiften/JID/JID.h" #include <string> +#include <Swiften/JID/JID.h> + namespace Swift { - class RosterItemPayload - { + class RosterItemPayload { public: enum Subscription { None, To, From, Both, Remove }; RosterItemPayload() : subscription_(None), ask_(false) {} - RosterItemPayload(const JID& jid, const std::string& name, Subscription subscription) : jid_(jid), name_(name), subscription_(subscription), ask_(false) { } + RosterItemPayload(const JID& jid, const std::string& name, Subscription subscription, const std::vector<std::string>& groups = std::vector<std::string>()) : jid_(jid), name_(name), subscription_(subscription), groups_(groups), ask_(false) { } void setJID(const JID& jid) { jid_ = jid; } const JID& getJID() const { return jid_; } @@ -51,5 +49,3 @@ namespace Swift { std::string unknownContent_; }; } - -#endif diff --git a/Swiften/Elements/RosterPayload.h b/Swiften/Elements/RosterPayload.h index b46b384..3102f0e 100644 --- a/Swiften/Elements/RosterPayload.h +++ b/Swiften/Elements/RosterPayload.h @@ -33,7 +33,16 @@ namespace Swift { return items_; } + const boost::optional<std::string>& getVersion() const { + return version_; + } + + void setVersion(const std::string& version) { + version_ = version; + } + private: RosterItemPayloads items_; + boost::optional<std::string> version_; }; } diff --git a/Swiften/Elements/SecurityLabelsCatalog.h b/Swiften/Elements/SecurityLabelsCatalog.h index 10ef459..cd84b0b 100644 --- a/Swiften/Elements/SecurityLabelsCatalog.h +++ b/Swiften/Elements/SecurityLabelsCatalog.h @@ -4,13 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelsCatalog_H -#define SWIFTEN_SecurityLabelsCatalog_H +#pragma once #include <vector> +#include <string> +#include <boost/shared_ptr.hpp> #include "Swiften/JID/JID.h" -#include <string> #include "Swiften/Elements/Payload.h" #include "Swiften/Elements/SecurityLabel.h" @@ -85,5 +85,3 @@ namespace Swift { std::vector<Item> items_; }; } - -#endif diff --git a/Swiften/Elements/SoftwareVersion.h b/Swiften/Elements/SoftwareVersion.h index 5863b38..887c6e9 100644 --- a/Swiften/Elements/SoftwareVersion.h +++ b/Swiften/Elements/SoftwareVersion.h @@ -6,8 +6,10 @@ #pragma once -#include "Swiften/Elements/Payload.h" #include <string> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Elements/Payload.h" namespace Swift { class SoftwareVersion : public Payload { diff --git a/Swiften/Elements/Stanza.cpp b/Swiften/Elements/Stanza.cpp index d15d778..607dfd1 100644 --- a/Swiften/Elements/Stanza.cpp +++ b/Swiften/Elements/Stanza.cpp @@ -9,8 +9,13 @@ #include <typeinfo> +#include <Swiften/Base/foreach.h> + namespace Swift { +Stanza::Stanza() { +} + Stanza::~Stanza() { payloads_.clear(); } diff --git a/Swiften/Elements/Stanza.h b/Swiften/Elements/Stanza.h index 9b934e4..9e082cc 100644 --- a/Swiften/Elements/Stanza.h +++ b/Swiften/Elements/Stanza.h @@ -7,27 +7,28 @@ #pragma once #include <vector> +#include <string> #include <boost/shared_ptr.hpp> -#include <boost/optional.hpp> -#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/optional/optional_fwd.hpp> +#include <boost/date_time/posix_time/ptime.hpp> -#include "Swiften/Elements/Element.h" -#include "Swiften/Elements/Payload.h" -#include <string> -#include "Swiften/Base/foreach.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/JID/JID.h> namespace Swift { + class Payload; + class Stanza : public Element { public: typedef boost::shared_ptr<Stanza> ref; + Stanza(); virtual ~Stanza(); template<typename T> boost::shared_ptr<T> getPayload() const { - foreach (const boost::shared_ptr<Payload>& i, payloads_) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < payloads_.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(payloads_[i])); if (result) { return result; } @@ -38,8 +39,8 @@ namespace Swift { template<typename T> std::vector< boost::shared_ptr<T> > getPayloads() const { std::vector< boost::shared_ptr<T> > results; - foreach (const boost::shared_ptr<Payload>& i, payloads_) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < payloads_.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(payloads_[i])); if (result) { results.push_back(result); } @@ -78,8 +79,6 @@ namespace Swift { std::string id_; JID from_; JID to_; - - typedef std::vector< boost::shared_ptr<Payload> > Payloads; - Payloads payloads_; + std::vector< boost::shared_ptr<Payload> > payloads_; }; } diff --git a/Swiften/Elements/Status.h b/Swiften/Elements/Status.h index 3ef6401..bb9b6e9 100644 --- a/Swiften/Elements/Status.h +++ b/Swiften/Elements/Status.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_Status_H -#define SWIFTEN_Status_H +#pragma once #include "Swiften/Elements/Payload.h" #include <string> @@ -28,5 +27,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Elements/StatusShow.cpp b/Swiften/Elements/StatusShow.cpp new file mode 100644 index 0000000..656e5c4 --- /dev/null +++ b/Swiften/Elements/StatusShow.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StatusShow.h> + +using namespace Swift; + +StatusShow::StatusShow(const Type& type) : type_(type) { +} diff --git a/Swiften/Elements/StatusShow.h b/Swiften/Elements/StatusShow.h index a158239..cd3477e 100644 --- a/Swiften/Elements/StatusShow.h +++ b/Swiften/Elements/StatusShow.h @@ -4,19 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StatusShow_H -#define SWIFTEN_StatusShow_H +#pragma once -#include "Swiften/Elements/Payload.h" -#include <string> +#include <Swiften/Elements/Payload.h> namespace Swift { class StatusShow : public Payload { public: enum Type { Online, Away, FFC, XA, DND, None }; - StatusShow(const Type& type = Online) : type_(type) { - } + StatusShow(const Type& type = Online); void setType(const Type& type) { type_ = type; @@ -32,19 +29,17 @@ namespace Swift { */ static int typeToAvailabilityOrdering(Type type) { switch (type) { - case Online: return 4; - case FFC: return 5; - case Away: return 2; - case XA: return 1; - case DND: return 3; - case None: return 0; + case Online: return 4; + case FFC: return 5; + case Away: return 2; + case XA: return 1; + case DND: return 3; + case None: return 0; } - return -1; + return 0; } private: Type type_; }; } - -#endif diff --git a/Swiften/Elements/StreamFeatures.cpp b/Swiften/Elements/StreamFeatures.cpp new file mode 100644 index 0000000..c6f6c04 --- /dev/null +++ b/Swiften/Elements/StreamFeatures.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamFeatures.h> + +#include <algorithm> + +namespace Swift { + +bool StreamFeatures::hasCompressionMethod(const std::string& mechanism) const { + return std::find(compressionMethods_.begin(), compressionMethods_.end(), mechanism) != compressionMethods_.end(); +} + +bool StreamFeatures::hasAuthenticationMechanism(const std::string& mechanism) const { + return std::find(authenticationMechanisms_.begin(), authenticationMechanisms_.end(), mechanism) != authenticationMechanisms_.end(); +} + +} diff --git a/Swiften/Elements/StreamFeatures.h b/Swiften/Elements/StreamFeatures.h index fbc0bb8..5dc5a26 100644 --- a/Swiften/Elements/StreamFeatures.h +++ b/Swiften/Elements/StreamFeatures.h @@ -7,9 +7,9 @@ #pragma once #include <vector> -#include <algorithm> - #include <string> +#include <boost/shared_ptr.hpp> + #include "Swiften/Elements/Element.h" namespace Swift { @@ -17,7 +17,7 @@ namespace Swift { public: typedef boost::shared_ptr<StreamFeatures> ref; - StreamFeatures() : hasStartTLS_(false), hasResourceBind_(false), hasSession_(false), hasStreamManagement_(false) {} + StreamFeatures() : hasStartTLS_(false), hasResourceBind_(false), hasSession_(false), hasStreamManagement_(false), hasRosterVersioning_(false) {} void setHasStartTLS() { hasStartTLS_ = true; @@ -51,9 +51,7 @@ namespace Swift { compressionMethods_.push_back(mechanism); } - bool hasCompressionMethod(const std::string& mechanism) const { - return std::find(compressionMethods_.begin(), compressionMethods_.end(), mechanism) != compressionMethods_.end(); - } + bool hasCompressionMethod(const std::string& mechanism) const; const std::vector<std::string>& getAuthenticationMechanisms() const { return authenticationMechanisms_; @@ -63,9 +61,7 @@ namespace Swift { authenticationMechanisms_.push_back(mechanism); } - bool hasAuthenticationMechanism(const std::string& mechanism) const { - return std::find(authenticationMechanisms_.begin(), authenticationMechanisms_.end(), mechanism) != authenticationMechanisms_.end(); - } + bool hasAuthenticationMechanism(const std::string& mechanism) const; bool hasAuthenticationMechanisms() const { return !authenticationMechanisms_.empty(); @@ -79,6 +75,14 @@ namespace Swift { hasStreamManagement_ = true; } + bool hasRosterVersioning() const { + return hasRosterVersioning_; + } + + void setHasRosterVersioning() { + hasRosterVersioning_ = true; + } + private: bool hasStartTLS_; std::vector<std::string> compressionMethods_; @@ -86,5 +90,6 @@ namespace Swift { bool hasResourceBind_; bool hasSession_; bool hasStreamManagement_; + bool hasRosterVersioning_; }; } diff --git a/Swiften/Elements/StreamManagementEnabled.cpp b/Swiften/Elements/StreamManagementEnabled.cpp new file mode 100644 index 0000000..bab7516 --- /dev/null +++ b/Swiften/Elements/StreamManagementEnabled.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamManagementEnabled.h> + +using namespace Swift; + +StreamManagementEnabled::StreamManagementEnabled() { +} + +StreamManagementEnabled::~StreamManagementEnabled() { +} diff --git a/Swiften/Elements/StreamManagementEnabled.h b/Swiften/Elements/StreamManagementEnabled.h index 0c72b84..02e77f3 100644 --- a/Swiften/Elements/StreamManagementEnabled.h +++ b/Swiften/Elements/StreamManagementEnabled.h @@ -1,17 +1,39 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include "Swiften/Elements/Element.h" +#include <string> +#include <Swiften/Elements/Element.h> namespace Swift { class StreamManagementEnabled : public Element { public: - StreamManagementEnabled() {} + StreamManagementEnabled(); + ~StreamManagementEnabled(); + + void setResumeSupported() { + resumeSupported = true; + } + + bool getResumeSupported() const { + return resumeSupported; + } + + void setResumeID(const std::string& id) { + resumeID = id; + } + + const std::string& getResumeID() const { + return resumeID; + } + + private: + bool resumeSupported; + std::string resumeID; }; } diff --git a/Swiften/Elements/StreamResume.cpp b/Swiften/Elements/StreamResume.cpp new file mode 100644 index 0000000..d55ef78 --- /dev/null +++ b/Swiften/Elements/StreamResume.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamResume.h> + +using namespace Swift; + +StreamResume::StreamResume() { +} + +StreamResume::~StreamResume() { +} diff --git a/Swiften/Elements/StreamResume.h b/Swiften/Elements/StreamResume.h new file mode 100644 index 0000000..652182a --- /dev/null +++ b/Swiften/Elements/StreamResume.h @@ -0,0 +1,40 @@ +/* + * 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 <string> +#include <boost/optional.hpp> + +#include <Swiften/Elements/Element.h> + +namespace Swift { + class StreamResume : public Element { + public: + StreamResume(); + ~StreamResume(); + + void setResumeID(const std::string& id) { + resumeID = id; + } + + const std::string& getResumeID() const { + return resumeID; + } + + const boost::optional<int> getHandledStanzasCount() const { + return handledStanzasCount; + } + + void setHandledStanzasCount(int i) { + handledStanzasCount = i; + } + + private: + std::string resumeID; + boost::optional<int> handledStanzasCount; + }; +} diff --git a/Swiften/Elements/StreamResumed.cpp b/Swiften/Elements/StreamResumed.cpp new file mode 100644 index 0000000..552e654 --- /dev/null +++ b/Swiften/Elements/StreamResumed.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamResumed.h> + +using namespace Swift; + +StreamResumed::StreamResumed() { +} + +StreamResumed::~StreamResumed() { +} diff --git a/Swiften/Elements/StreamResumed.h b/Swiften/Elements/StreamResumed.h new file mode 100644 index 0000000..cc42895 --- /dev/null +++ b/Swiften/Elements/StreamResumed.h @@ -0,0 +1,40 @@ +/* + * 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 <string> +#include <boost/optional.hpp> + +#include <Swiften/Elements/Element.h> + +namespace Swift { + class StreamResumed : public Element { + public: + StreamResumed(); + ~StreamResumed(); + + void setResumeID(const std::string& id) { + resumeID = id; + } + + const std::string& getResumeID() const { + return resumeID; + } + + const boost::optional<int> getHandledStanzasCount() const { + return handledStanzasCount; + } + + void setHandledStanzasCount(int i) { + handledStanzasCount = i; + } + + private: + std::string resumeID; + boost::optional<int> handledStanzasCount; + }; +} diff --git a/Swiften/Elements/UnitTest/StanzaTest.cpp b/Swiften/Elements/UnitTest/StanzaTest.cpp index 4020f8b..4669f16 100644 --- a/Swiften/Elements/UnitTest/StanzaTest.cpp +++ b/Swiften/Elements/UnitTest/StanzaTest.cpp @@ -7,6 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> #include "Swiften/Elements/Stanza.h" #include "Swiften/Elements/Payload.h" diff --git a/Swiften/Entity/Entity.cpp b/Swiften/Entity/Entity.cpp index da2ecaf..dea47b0 100644 --- a/Swiften/Entity/Entity.cpp +++ b/Swiften/Entity/Entity.cpp @@ -6,26 +6,45 @@ #include "Swiften/Entity/Entity.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" + + namespace Swift { +Entity::Entity() { + payloadParserFactories = new FullPayloadParserFactoryCollection(); + payloadSerializers = new FullPayloadSerializerCollection(); +} + Entity::~Entity() { + delete payloadSerializers; + delete payloadParserFactories; } void Entity::addPayloadParserFactory(PayloadParserFactory* payloadParserFactory) { - payloadParserFactories.addFactory(payloadParserFactory); + payloadParserFactories->addFactory(payloadParserFactory); } void Entity::removePayloadParserFactory(PayloadParserFactory* payloadParserFactory) { - payloadParserFactories.removeFactory(payloadParserFactory); + payloadParserFactories->removeFactory(payloadParserFactory); } void Entity::addPayloadSerializer(PayloadSerializer* payloadSerializer) { - payloadSerializers.addSerializer(payloadSerializer); + payloadSerializers->addSerializer(payloadSerializer); } void Entity::removePayloadSerializer(PayloadSerializer* payloadSerializer) { - payloadSerializers.removeSerializer(payloadSerializer); + payloadSerializers->removeSerializer(payloadSerializer); +} + +PayloadParserFactoryCollection* Entity::getPayloadParserFactories() { + return payloadParserFactories; +} + +PayloadSerializerCollection* Entity::getPayloadSerializers() { + return payloadSerializers; } } diff --git a/Swiften/Entity/Entity.h b/Swiften/Entity/Entity.h index 20d02ba..65480d0 100644 --- a/Swiften/Entity/Entity.h +++ b/Swiften/Entity/Entity.h @@ -6,21 +6,20 @@ #pragma once -#include <Swiften/Base/boost_bsignals.h> -#include <boost/shared_ptr.hpp> - -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" - namespace Swift { class PayloadParserFactory; class PayloadSerializer; + class FullPayloadParserFactoryCollection; + class FullPayloadSerializerCollection; + class PayloadParserFactoryCollection; + class PayloadSerializerCollection; /** * The base class for XMPP entities (Clients, Components). */ class Entity { public: + Entity(); virtual ~Entity(); void addPayloadParserFactory(PayloadParserFactory* payloadParserFactory); @@ -30,16 +29,11 @@ namespace Swift { void removePayloadSerializer(PayloadSerializer* payloadSerializer); protected: - PayloadParserFactoryCollection* getPayloadParserFactories() { - return &payloadParserFactories; - } - - PayloadSerializerCollection* getPayloadSerializers() { - return &payloadSerializers; - } + PayloadParserFactoryCollection* getPayloadParserFactories(); + PayloadSerializerCollection* getPayloadSerializers(); private: - FullPayloadParserFactoryCollection payloadParserFactories; - FullPayloadSerializerCollection payloadSerializers; + FullPayloadParserFactoryCollection* payloadParserFactories; + FullPayloadSerializerCollection* payloadSerializers; }; } diff --git a/Swiften/Entity/GenericPayloadPersister.h b/Swiften/Entity/GenericPayloadPersister.h new file mode 100644 index 0000000..63553de --- /dev/null +++ b/Swiften/Entity/GenericPayloadPersister.h @@ -0,0 +1,36 @@ +/* + * 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/Entity/PayloadPersister.h> +#include <Swiften/Parser/GenericPayloadParserFactory.h> + +namespace Swift { + template<typename PAYLOAD, typename PARSER, typename SERIALIZER> + class GenericPayloadPersister : public PayloadPersister { + public: + GenericPayloadPersister() { + } + + public: + boost::shared_ptr<PAYLOAD> loadPayloadGeneric(const boost::filesystem::path& path) { + return boost::dynamic_pointer_cast<PAYLOAD>(loadPayload(path)); + } + + protected: + virtual const PayloadSerializer* getSerializer() const { + return &serializer; + } + + virtual PayloadParser* createParser() const { + return new PARSER(); + } + + private: + SERIALIZER serializer; + }; +} diff --git a/Swiften/Entity/PayloadPersister.cpp b/Swiften/Entity/PayloadPersister.cpp new file mode 100644 index 0000000..f7278cc --- /dev/null +++ b/Swiften/Entity/PayloadPersister.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Entity/PayloadPersister.h> + +#include <boost/filesystem/fstream.hpp> +#include <boost/filesystem.hpp> +#include <iostream> + +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Parser/PayloadParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Serializer/PayloadSerializer.h> + +using namespace Swift; + +PayloadPersister::PayloadPersister() { +} + +PayloadPersister::~PayloadPersister() { +} + +void PayloadPersister::savePayload(boost::shared_ptr<Payload> payload, const boost::filesystem::path& path) { + if (!boost::filesystem::exists(path.parent_path())) { + try { + boost::filesystem::create_directories(path.parent_path()); + } + catch (const boost::filesystem::filesystem_error& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + } + } + boost::filesystem::ofstream file(path); + file << getSerializer()->serialize(payload); + file.close(); +} + +boost::shared_ptr<Payload> PayloadPersister::loadPayload(const boost::filesystem::path& path) { + if (boost::filesystem::exists(path)) { + ByteArray data; + data.readFromFile(path.string()); + std::auto_ptr<PayloadParser> parser(createParser()); + PayloadParserTester tester(parser.get()); + tester.parse(data.toString()); + return parser->getPayload(); + } + else { + return boost::shared_ptr<Payload>(); + } +} diff --git a/Swiften/Entity/PayloadPersister.h b/Swiften/Entity/PayloadPersister.h new file mode 100644 index 0000000..ea7c74c --- /dev/null +++ b/Swiften/Entity/PayloadPersister.h @@ -0,0 +1,30 @@ +/* + * 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 <boost/filesystem/path.hpp> + +namespace Swift { + class Payload; + class PayloadSerializer; + class PayloadParser; + + class PayloadPersister { + public: + PayloadPersister(); + virtual ~PayloadPersister(); + + void savePayload(boost::shared_ptr<Payload>, const boost::filesystem::path&); + boost::shared_ptr<Payload> loadPayload(const boost::filesystem::path&); + + protected: + + virtual const PayloadSerializer* getSerializer() const = 0; + virtual PayloadParser* createParser() const = 0; + }; +} diff --git a/Swiften/EventLoop/DummyEventLoop.cpp b/Swiften/EventLoop/DummyEventLoop.cpp new file mode 100644 index 0000000..3741eec --- /dev/null +++ b/Swiften/EventLoop/DummyEventLoop.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/EventLoop/DummyEventLoop.h> + +#include <iostream> + +namespace Swift { + +DummyEventLoop::DummyEventLoop() { +} + +DummyEventLoop::~DummyEventLoop() { + if (!events_.empty()) { + std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl; + } + events_.clear(); +} + + +} diff --git a/Swiften/EventLoop/DummyEventLoop.h b/Swiften/EventLoop/DummyEventLoop.h index b7ef516..68f9b85 100644 --- a/Swiften/EventLoop/DummyEventLoop.h +++ b/Swiften/EventLoop/DummyEventLoop.h @@ -7,24 +7,14 @@ #pragma once #include <deque> -#include <iostream> -#include <boost/function.hpp> #include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Base/foreach.h" namespace Swift { class DummyEventLoop : public EventLoop { public: - DummyEventLoop() { - } - - ~DummyEventLoop() { - if (!events_.empty()) { - std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl; - } - events_.clear(); - } + DummyEventLoop(); + ~DummyEventLoop(); void processEvents() { while (!events_.empty()) { diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp index 56bb6ac..510ed63 100644 --- a/Swiften/EventLoop/EventLoop.cpp +++ b/Swiften/EventLoop/EventLoop.cpp @@ -9,6 +9,7 @@ #include <algorithm> #include <boost/bind.hpp> #include <iostream> +#include <cassert> #include <Swiften/Base/Log.h> @@ -17,6 +18,7 @@ namespace Swift { inline void invokeCallback(const Event& event) { try { + assert(!event.callback.empty()); event.callback(); } catch (const std::exception& e) { diff --git a/Swiften/EventLoop/SConscript b/Swiften/EventLoop/SConscript index 21ae8b9..e448f43 100644 --- a/Swiften/EventLoop/SConscript +++ b/Swiften/EventLoop/SConscript @@ -5,6 +5,7 @@ sources = [ "EventOwner.cpp", "Event.cpp", "SimpleEventLoop.cpp", + "DummyEventLoop.cpp", ] objects = swiften_env.SwiftenObject(sources) diff --git a/Swiften/Examples/BenchTool/BenchTool.cpp b/Swiften/Examples/BenchTool/BenchTool.cpp index 9e54ed9..1fb6601 100644 --- a/Swiften/Examples/BenchTool/BenchTool.cpp +++ b/Swiften/Examples/BenchTool/BenchTool.cpp @@ -6,6 +6,7 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <iostream> #include "Swiften/Client/Client.h" #include "Swiften/Network/TimerFactory.h" diff --git a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp index fda203a..3b66d96 100644 --- a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp +++ b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp @@ -6,6 +6,7 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <iostream> #include "Swiften/Client/Client.h" #include "Swiften/Network/Timer.h" diff --git a/Swiften/Examples/SendFile/ReceiveFile.cpp b/Swiften/Examples/SendFile/ReceiveFile.cpp index b46d790..effa1b7 100644 --- a/Swiften/Examples/SendFile/ReceiveFile.cpp +++ b/Swiften/Examples/SendFile/ReceiveFile.cpp @@ -7,7 +7,10 @@ #include <boost/bind.hpp> #include <boost/filesystem.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <iostream> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Base/foreach.h> #include <Swiften/Client/Client.h> #include <Swiften/Network/BoostNetworkFactories.h> #include <Swiften/EventLoop/SimpleEventLoop.h> diff --git a/Swiften/Examples/SendFile/SendFile.cpp b/Swiften/Examples/SendFile/SendFile.cpp index 5ec00a9..d8300be 100644 --- a/Swiften/Examples/SendFile/SendFile.cpp +++ b/Swiften/Examples/SendFile/SendFile.cpp @@ -6,15 +6,17 @@ #include <boost/bind.hpp> #include <boost/filesystem.hpp> +#include <iostream> #include "Swiften/Client/Client.h" +#include <Swiften/Elements/Presence.h> #include "Swiften/Network/BoostTimer.h" #include "Swiften/Network/TimerFactory.h" #include "Swiften/Network/BoostNetworkFactories.h" #include "Swiften/EventLoop/EventLoop.h" #include "Swiften/Client/ClientXMLTracer.h" #include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/FileTransfer/OutgoingFileTransfer.h" +#include "Swiften/FileTransfer/OutgoingSIFileTransfer.h" #include "Swiften/FileTransfer/FileReadBytestream.h" #include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" #include "Swiften/Network/BoostConnectionServer.h" @@ -64,7 +66,7 @@ class FileSender { private: void handleConnected() { client->sendPresence(Presence::create()); - transfer = new OutgoingFileTransfer("myid", client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer); + transfer = new OutgoingSIFileTransfer("myid", client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer); transfer->onFinished.connect(boost::bind(&FileSender::handleFileTransferFinished, this, _1)); transfer->start(); } @@ -99,7 +101,7 @@ class FileSender { boost::filesystem::path file; Client* client; ClientXMLTracer* tracer; - OutgoingFileTransfer* transfer; + OutgoingSIFileTransfer* transfer; }; diff --git a/Swiften/Examples/SendMessage/SendMessage.cpp b/Swiften/Examples/SendMessage/SendMessage.cpp index d7f7333..ad75318 100644 --- a/Swiften/Examples/SendMessage/SendMessage.cpp +++ b/Swiften/Examples/SendMessage/SendMessage.cpp @@ -6,8 +6,10 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <iostream> #include "Swiften/Client/Client.h" +#include "Swiften/Elements/Message.h" #include "Swiften/Network/BoostNetworkFactories.h" #include "Swiften/Network/TimerFactory.h" #include "Swiften/EventLoop/EventLoop.h" diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.h b/Swiften/FileTransfer/ByteArrayReadBytestream.h index d459658..4704db6 100644 --- a/Swiften/FileTransfer/ByteArrayReadBytestream.h +++ b/Swiften/FileTransfer/ByteArrayReadBytestream.h @@ -6,31 +6,32 @@ #pragma once -#include "Swiften/FileTransfer/ReadBytestream.h" -#include "Swiften/Base/ByteArray.h" +#include <vector> + +#include <Swiften/FileTransfer/ReadBytestream.h> namespace Swift { class ByteArrayReadBytestream : public ReadBytestream { public: - ByteArrayReadBytestream(const ByteArray& data) : data(data), position(0) { + ByteArrayReadBytestream(const std::vector<unsigned char>& data) : data(data), position(0) { } - virtual ByteArray read(size_t size) { + virtual std::vector<unsigned char> read(size_t size) { size_t readSize = size; - if (position + readSize > data.getSize()) { - readSize = data.getSize() - position; + if (position + readSize > data.size()) { + readSize = data.size() - position; } - ByteArray result(data.getData() + position, readSize); + std::vector<unsigned char> result(data.begin() + position, data.begin() + position + readSize); position += readSize; return result; } virtual bool isFinished() const { - return position >= data.getSize(); + return position >= data.size(); } private: - ByteArray data; + std::vector<unsigned char> data; size_t position; }; } diff --git a/Swiften/FileTransfer/ByteArrayWriteBytestream.h b/Swiften/FileTransfer/ByteArrayWriteBytestream.h new file mode 100644 index 0000000..6c360e6 --- /dev/null +++ b/Swiften/FileTransfer/ByteArrayWriteBytestream.h @@ -0,0 +1,28 @@ +/* + * 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/FileTransfer/WriteBytestream.h> + +namespace Swift { + class ByteArrayWriteBytestream : public WriteBytestream { + public: + ByteArrayWriteBytestream() { + } + + virtual void write(const std::vector<unsigned char>& bytes) { + data.insert(data.end(), bytes.begin(), bytes.end()); + } + + const std::vector<unsigned char>& getData() const { + return data; + } + + private: + std::vector<unsigned char> data; + }; +} diff --git a/Swiften/FileTransfer/FileReadBytestream.cpp b/Swiften/FileTransfer/FileReadBytestream.cpp index c08747b..e997366 100644 --- a/Swiften/FileTransfer/FileReadBytestream.cpp +++ b/Swiften/FileTransfer/FileReadBytestream.cpp @@ -21,14 +21,14 @@ FileReadBytestream::~FileReadBytestream() { } } -ByteArray FileReadBytestream::read(size_t size) { +std::vector<unsigned char> FileReadBytestream::read(size_t size) { if (!stream) { stream = new boost::filesystem::ifstream(file, std::ios_base::in|std::ios_base::binary); } - ByteArray result; + std::vector<unsigned char> result; result.resize(size); assert(stream->good()); - stream->read(reinterpret_cast<char*>(result.getData()), size); + stream->read(reinterpret_cast<char*>(&result[0]), size); result.resize(stream->gcount()); return result; } diff --git a/Swiften/FileTransfer/FileReadBytestream.h b/Swiften/FileTransfer/FileReadBytestream.h index 055e194..f136a68 100644 --- a/Swiften/FileTransfer/FileReadBytestream.h +++ b/Swiften/FileTransfer/FileReadBytestream.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/filesystem/fstream.hpp> #include "Swiften/FileTransfer/ReadBytestream.h" @@ -17,7 +17,7 @@ namespace Swift { FileReadBytestream(const boost::filesystem::path& file); ~FileReadBytestream(); - virtual ByteArray read(size_t size) ; + virtual std::vector<unsigned char> read(size_t size); virtual bool isFinished() const; private: diff --git a/Swiften/FileTransfer/FileWriteBytestream.cpp b/Swiften/FileTransfer/FileWriteBytestream.cpp index 4d29bd1..803a10b 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.cpp +++ b/Swiften/FileTransfer/FileWriteBytestream.cpp @@ -21,12 +21,12 @@ FileWriteBytestream::~FileWriteBytestream() { } } -void FileWriteBytestream::write(const ByteArray& data) { +void FileWriteBytestream::write(const std::vector<unsigned char>& data) { 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.getData()), data.getSize()); + stream->write(reinterpret_cast<const char*>(&data[0]), data.size()); } } diff --git a/Swiften/FileTransfer/FileWriteBytestream.h b/Swiften/FileTransfer/FileWriteBytestream.h index c6f7b39..8cfa718 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.h +++ b/Swiften/FileTransfer/FileWriteBytestream.h @@ -6,10 +6,10 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/filesystem/fstream.hpp> -#include "Swiften/FileTransfer/WriteBytestream.h" +#include <Swiften/FileTransfer/WriteBytestream.h> namespace Swift { class FileWriteBytestream : public WriteBytestream { @@ -17,7 +17,7 @@ namespace Swift { FileWriteBytestream(const boost::filesystem::path& file); ~FileWriteBytestream(); - virtual void write(const ByteArray&); + virtual void write(const std::vector<unsigned char>&); private: boost::filesystem::path file; diff --git a/Swiften/FileTransfer/IBBReceiveSession.cpp b/Swiften/FileTransfer/IBBReceiveSession.cpp index 5c90757..566dcca 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.cpp +++ b/Swiften/FileTransfer/IBBReceiveSession.cpp @@ -4,31 +4,96 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/IBBReceiveSession.h" +#include <Swiften/FileTransfer/IBBReceiveSession.h> #include <boost/bind.hpp> -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/FileTransfer/IBBRequest.h" -#include "Swiften/FileTransfer/BytestreamException.h" +#include <Swiften/Base/Log.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/FileTransfer/IBBRequest.h> +#include <Swiften/FileTransfer/BytestreamException.h> +#include <Swiften/Queries/SetResponder.h> namespace Swift { -IBBReceiveSession::IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router) : SetResponder<IBB>(router), id(id), from(from), size(size), bytestream(bytestream), router(router), sequenceNumber(0), active(false), receivedSize(0) { +class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { + public: + IBBResponder(IBBReceiveSession* session, IQRouter* router) : SetResponder<IBB>(router), session(session), sequenceNumber(0), receivedSize(0) { + } + + virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) { + if (from == session->from && ibb->getStreamID() == session->id) { + if (ibb->getAction() == IBB::Data) { + if (sequenceNumber == ibb->getSequenceNumber()) { + session->onDataReceived(ibb->getData()); + receivedSize += ibb->getData().size(); + sequenceNumber++; + sendResponse(from, id, IBB::ref()); + if (receivedSize >= session->size) { + if (receivedSize > session->size) { + std::cerr << "Warning: Received more data than expected" << std::endl; + } + session->finish(boost::optional<FileTransferError>()); + } + } + else { + SWIFT_LOG(warning) << "Received data out of order" << std::endl; + sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel); + session->finish(FileTransferError(FileTransferError::ClosedError)); + } + } + else if (ibb->getAction() == IBB::Open) { + sendResponse(from, id, IBB::ref()); + } + else if (ibb->getAction() == IBB::Close) { + sendResponse(from, id, IBB::ref()); + session->finish(FileTransferError(FileTransferError::ClosedError)); + } + return true; + } + return false; + } + + private: + IBBReceiveSession* session; + int sequenceNumber; + size_t receivedSize; +}; + + +IBBReceiveSession::IBBReceiveSession( + const std::string& id, + const JID& from, + size_t size, + IQRouter* router) : + id(id), + from(from), + size(size), + router(router), + active(false) { + responder = new IBBResponder(this, router); } IBBReceiveSession::~IBBReceiveSession() { + if (active) { + SWIFT_LOG(warning) << "Session still active" << std::endl; + } + delete responder; } void IBBReceiveSession::start() { active = true; + responder->start(); } void IBBReceiveSession::stop() { - if (active && router->isAvailable()) { - IBBRequest::create(from, IBB::createIBBClose(id), router)->send(); + responder->stop(); + if (active) { + if (router->isAvailable()) { + IBBRequest::create(from, IBB::createIBBClose(id), router)->send(); + } + finish(boost::optional<FileTransferError>()); } - finish(boost::optional<FileTransferError>()); } void IBBReceiveSession::finish(boost::optional<FileTransferError> error) { @@ -36,34 +101,4 @@ void IBBReceiveSession::finish(boost::optional<FileTransferError> error) { onFinished(error); } -bool IBBReceiveSession::handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) { - if (from == this->from && ibb->getStreamID() == id) { - if (ibb->getAction() == IBB::Data) { - if (sequenceNumber == ibb->getSequenceNumber()) { - bytestream->write(ibb->getData()); - receivedSize += ibb->getData().getSize(); - if (receivedSize >= size) { - if (receivedSize > size) { - std::cerr << "Warning: Received more data than expected" << std::endl; - } - finish(boost::optional<FileTransferError>()); - } - } - else { - sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel); - finish(FileTransferError(FileTransferError::ClosedError)); - } - } - else if (ibb->getAction() == IBB::Open) { - sendResponse(from, id, IBB::ref()); - } - else if (ibb->getAction() == IBB::Close) { - sendResponse(from, id, IBB::ref()); - finish(FileTransferError(FileTransferError::ClosedError)); - } - return true; - } - return false; -} - } diff --git a/Swiften/FileTransfer/IBBReceiveSession.h b/Swiften/FileTransfer/IBBReceiveSession.h index 6d936de..d512025 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.h +++ b/Swiften/FileTransfer/IBBReceiveSession.h @@ -7,27 +7,30 @@ #pragma once #include <boost/shared_ptr.hpp> -#include <boost/optional.hpp> +#include <boost/optional/optional_fwd.hpp> #include "Swiften/Base/boost_bsignals.h" #include "Swiften/FileTransfer/WriteBytestream.h" #include "Swiften/JID/JID.h" #include "Swiften/Elements/IBB.h" -#include "Swiften/Elements/ErrorPayload.h" #include "Swiften/FileTransfer/FileTransferError.h" -#include "Swiften/Queries/SetResponder.h" namespace Swift { class IQRouter; - class IBBReceiveSession : public SetResponder<IBB> { + class IBBReceiveSession { public: - IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router); + IBBReceiveSession( + const std::string& id, + const JID& from, + size_t size, + IQRouter* router); ~IBBReceiveSession(); void start(); void stop(); + boost::signal<void (const std::vector<unsigned char>&)> onDataReceived; boost::signal<void (boost::optional<FileTransferError>)> onFinished; private: @@ -35,13 +38,14 @@ namespace Swift { void finish(boost::optional<FileTransferError>); private: + class IBBResponder; + friend class IBBResponder; + std::string id; JID from; size_t size; - WriteBytestream::ref bytestream; IQRouter* router; - int sequenceNumber; + IBBResponder* responder; bool active; - size_t receivedSize; }; } diff --git a/Swiften/FileTransfer/IBBSendSession.cpp b/Swiften/FileTransfer/IBBSendSession.cpp index 0fb47d3..c31fe4a 100644 --- a/Swiften/FileTransfer/IBBSendSession.cpp +++ b/Swiften/FileTransfer/IBBSendSession.cpp @@ -38,13 +38,13 @@ void IBBSendSession::handleIBBResponse(IBB::ref, ErrorPayload::ref error) { if (!error) { if (!bytestream->isFinished()) { try { - ByteArray data = bytestream->read(blockSize); + std::vector<unsigned char> data = bytestream->read(blockSize); IBBRequest::ref request = IBBRequest::create(to, IBB::createIBBData(id, sequenceNumber, data), router); sequenceNumber++; request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); request->send(); } - catch (const BytestreamException& e) { + catch (const BytestreamException&) { finish(FileTransferError(FileTransferError::ReadError)); } } diff --git a/Swiften/FileTransfer/IncomingFileTransfer.cpp b/Swiften/FileTransfer/IncomingFileTransfer.cpp index 238ccce..7c97e4d 100644 --- a/Swiften/FileTransfer/IncomingFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingFileTransfer.cpp @@ -4,20 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/IncomingFileTransfer.h" +#include <Swiften/FileTransfer/IncomingFileTransfer.h> namespace Swift { IncomingFileTransfer::~IncomingFileTransfer() { - -} - -/*void IncomingFileTransfer::accept(WriteBytestream::ref) { - } -void IncomingFileTransfer::stop() { - -}*/ - } diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp index 5535840..79d2391 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp +++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp @@ -10,8 +10,10 @@ #include <Swiften/Elements/JingleDescription.h> #include <Swiften/Elements/JingleFileTransferDescription.h> -#include <Swiften/Elements/JingleIBBTransport.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> #include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/Jingle/Jingle.h> #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> namespace Swift { @@ -24,12 +26,12 @@ IncomingFileTransferManager::~IncomingFileTransferManager() { jingleSessionManager->removeIncomingSessionHandler(this); } -bool IncomingFileTransferManager::handleIncomingJingleSession(IncomingJingleSession::ref session) { - JingleContent::ref content = session->getContentWithDescription<JingleFileTransferDescription>(); - if (content) { - // Check for supported transports - if (content->getTransport<JingleIBBTransport>()) { - IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(session); +bool IncomingFileTransferManager::handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents) { + if (JingleContentPayload::ref content = Jingle::getContentWithDescription<JingleFileTransferDescription>(contents)) { + if (content->getTransport<JingleIBBTransportPayload>() || content->getTransport<JingleS5BTransportPayload>()) { + RemoteJingleTransportCandidateSelectorFactory* a; + LocalJingleTransportCandidateGeneratorFactory* b; + IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(session, content, a, b, router); onIncomingFileTransfer(transfer); } else { diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.h b/Swiften/FileTransfer/IncomingFileTransferManager.h index a54b5cd..428a838 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.h +++ b/Swiften/FileTransfer/IncomingFileTransferManager.h @@ -15,6 +15,8 @@ namespace Swift { class IQRouter; class JingleSessionManager; + class RemoteJingleTransportCandidateSelectorFactory; + class LocalJingleTransportCandidateGeneratorFactory; class IncomingFileTransferManager : public IncomingJingleSessionHandler { public: @@ -24,7 +26,7 @@ namespace Swift { boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer; private: - bool handleIncomingJingleSession(IncomingJingleSession::ref session); + bool handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents); private: JingleSessionManager* jingleSessionManager; diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp index cb2f65c..904b53e 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp @@ -6,14 +6,164 @@ #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> + namespace Swift { -IncomingJingleFileTransfer::IncomingJingleFileTransfer(IncomingJingleSession::ref session) : session(session) { +IncomingJingleFileTransfer::IncomingJingleFileTransfer( + JingleSession::ref session, + JingleContentPayload::ref content, + RemoteJingleTransportCandidateSelectorFactory* candidateSelectorFactory, + LocalJingleTransportCandidateGeneratorFactory* candidateGeneratorFactory, + IQRouter* router) : + session(session), + router(router), + initialContent(content), + contentID(content->getName(), content->getCreator()), + state(Initial), + remoteTransportCandidateSelectFinished(false), + localTransportCandidateSelectFinished(false) { + + 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)); + + description = initialContent->getDescription<JingleFileTransferDescription>(); + assert(description); +} + +IncomingJingleFileTransfer::~IncomingJingleFileTransfer() { + session->onSessionTerminateReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this)); + 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) { + assert(!stream); this->stream = stream; + + if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) { + setActiveTransport(createIBBTransport(ibbTransport)); + session->accept(); + } + else if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) { + state = CreatingInitialTransports; + candidateSelector->addRemoteTransportCandidates(s5bTransport); + candidateGenerator->generateLocalTransportCandidates(); + } + else { + assert(false); + } +} + + +void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates) { + if (state == CreatingInitialTransports) { + if (!candidates) { + localTransportCandidateSelectFinished = true; + } + session->accept(candidates); + state = NegotiatingTransport; + candidateSelector->selectCandidate(); + } +} + + +void IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref transport) { + remoteTransportCandidateSelectFinished = true; + selectedRemoteTransportCandidate = transport; + session->sendTransportInfo(contentID, transport); + checkCandidateSelected(); +} + +void IncomingJingleFileTransfer::checkCandidateSelected() { + 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; + } + } +} + +void IncomingJingleFileTransfer::setActiveTransport(JingleTransport::ref transport) { + state = Transferring; + activeTransport = transport; + activeTransport->onDataReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1)); + activeTransport->start(); +} + +void IncomingJingleFileTransfer::handleSessionTerminateReceived() { + // TODO + state = Terminated; +} + +void IncomingJingleFileTransfer::handleTransportDataReceived(const std::vector<unsigned char>& data) { + stream->write(data); +} + + +void IncomingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref transport) { + localTransportCandidateSelectFinished = true; + selectedLocalTransportCandidate = transport; + if (candidateGenerator->isActualCandidate(transport)) { + candidateSelector->setMinimumPriority(candidateGenerator->getPriority(transport)); + } + checkCandidateSelected(); +} + +void IncomingJingleFileTransfer::handleTransportReplaceReceived(const JingleContentID& content, JingleTransportPayload::ref transport) { + if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { + setActiveTransport(createIBBTransport(ibbTransport)); + session->acceptTransport(content, transport); + } + else { + session->rejectTransport(content, transport); + } +} + +void IncomingJingleFileTransfer::stopActiveTransport() { + if (activeTransport) { + activeTransport->stop(); + activeTransport->onDataReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1)); + } +} + +JingleIncomingIBBTransport::ref IncomingJingleFileTransfer::createIBBTransport(JingleIBBTransportPayload::ref ibbTransport) { + return boost::make_shared<JingleIncomingIBBTransport>(session->getInitiator(), ibbTransport->getSessionID(), description->getOffer()->size, router); } } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h index d69449e..164d868 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h @@ -8,20 +8,71 @@ #include <boost/shared_ptr.hpp> -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/Jingle/JingleContentID.h> #include <Swiften/FileTransfer/IncomingFileTransfer.h> +#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> namespace Swift { + class IQRouter; + class RemoteJingleTransportCandidateSelectorFactory; + class LocalJingleTransportCandidateGeneratorFactory; + class RemoteJingleTransportCandidateSelector; + class LocalJingleTransportCandidateGenerator; + class IncomingJingleFileTransfer : public IncomingFileTransfer { public: typedef boost::shared_ptr<IncomingJingleFileTransfer> ref; + enum State { + Initial, + CreatingInitialTransports, + NegotiatingTransport, + Transferring, + WaitingForFallbackOrTerminate, + Terminated + }; - IncomingJingleFileTransfer(IncomingJingleSession::ref session); + IncomingJingleFileTransfer( + JingleSession::ref, + JingleContentPayload::ref content, + RemoteJingleTransportCandidateSelectorFactory*, + LocalJingleTransportCandidateGeneratorFactory*, + IQRouter* router); + ~IncomingJingleFileTransfer(); virtual void accept(WriteBytestream::ref); private: - IncomingJingleSession::ref session; + void handleSessionTerminateReceived(); + 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); + void stopActiveTransport(); + void checkCandidateSelected(); + JingleIncomingIBBTransport::ref createIBBTransport(JingleIBBTransportPayload::ref ibbTransport); + + private: + JingleSession::ref session; + IQRouter* router; + JingleContentPayload::ref initialContent; + JingleContentID contentID; + State state; + JingleFileTransferDescription::ref description; WriteBytestream::ref stream; + RemoteJingleTransportCandidateSelector* candidateSelector; + LocalJingleTransportCandidateGenerator* candidateGenerator; + bool remoteTransportCandidateSelectFinished; + JingleTransportPayload::ref selectedRemoteTransportCandidate; + bool localTransportCandidateSelectFinished; + JingleTransportPayload::ref selectedLocalTransportCandidate; + + JingleTransport::ref activeTransport; }; } diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp new file mode 100644 index 0000000..0ca899f --- /dev/null +++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp @@ -0,0 +1,23 @@ +/* + * 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 std::string& id, size_t size, IQRouter* router) : ibbSession(from, id, size, router) { + ibbSession.onDataReceived.connect(boost::ref(onDataReceived)); +} + +void JingleIncomingIBBTransport::start() { + ibbSession.start(); +} + +void JingleIncomingIBBTransport::stop() { + ibbSession.stop(); +} + +} diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.h b/Swiften/FileTransfer/JingleIncomingIBBTransport.h new file mode 100644 index 0000000..e2fa485 --- /dev/null +++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.h @@ -0,0 +1,27 @@ +/* + * 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 std::string& id, size_t size, IQRouter* router); + + virtual void start(); + virtual void stop(); + + private: + IBBReceiveSession ibbSession; + }; +} diff --git a/Swiften/Elements/JingleTransport.h b/Swiften/FileTransfer/JingleTransport.cpp index ecd2a34..c507922 100644 --- a/Swiften/Elements/JingleTransport.h +++ b/Swiften/FileTransfer/JingleTransport.cpp @@ -4,11 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#pragma once - -#include <Swiften/Elements/Payload.h> +#include <Swiften/FileTransfer/JingleTransport.h> namespace Swift { - class JingleTransport : public Payload { - }; + +JingleTransport::~JingleTransport() { + +} + } diff --git a/Swiften/FileTransfer/JingleTransport.h b/Swiften/FileTransfer/JingleTransport.h new file mode 100644 index 0000000..1d163d0 --- /dev/null +++ b/Swiften/FileTransfer/JingleTransport.h @@ -0,0 +1,25 @@ +/* + * 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> + +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; + }; +} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp new file mode 100644 index 0000000..852902b --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp @@ -0,0 +1,14 @@ +/* + * 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/LocalJingleTransportCandidateGenerator.h> + +namespace Swift { + +LocalJingleTransportCandidateGenerator::~LocalJingleTransportCandidateGenerator() { +} + +} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h new file mode 100644 index 0000000..c111005 --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h @@ -0,0 +1,27 @@ +/* + * 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/Base/boost_bsignals.h> + +#include <Swiften/Elements/JingleTransportPayload.h> +#include <Swiften/FileTransfer/JingleTransport.h> + +namespace Swift { + class LocalJingleTransportCandidateGenerator { + public: + virtual ~LocalJingleTransportCandidateGenerator(); + + virtual void generateLocalTransportCandidates() = 0; + + virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; + virtual int getPriority(JingleTransportPayload::ref) = 0; + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + + boost::signal<void (JingleTransportPayload::ref)> onLocalTransportCandidatesGenerated; + }; +} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp new file mode 100644 index 0000000..a1e3874 --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp @@ -0,0 +1,14 @@ +/* + * 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 new file mode 100644 index 0000000..c969fc7 --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h @@ -0,0 +1,18 @@ +/* + * 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.cpp b/Swiften/FileTransfer/OutgoingFileTransfer.cpp index 32f7e17..94d4348 100644 --- a/Swiften/FileTransfer/OutgoingFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingFileTransfer.cpp @@ -4,75 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/OutgoingFileTransfer.h" - -#include <boost/bind.hpp> - -#include "Swiften/FileTransfer/StreamInitiationRequest.h" -#include "Swiften/FileTransfer/BytestreamsRequest.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" -#include "Swiften/FileTransfer/IBBSendSession.h" +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> namespace Swift { -OutgoingFileTransfer::OutgoingFileTransfer(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) { -} - -void OutgoingFileTransfer::start() { - StreamInitiation::ref streamInitiation(new StreamInitiation()); - streamInitiation->setID(id); - streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size)); - //streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams"); - streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb"); - StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter); - request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); - request->send(); -} - -void OutgoingFileTransfer::stop() { -} - -void OutgoingFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { - if (error) { - finish(FileTransferError()); - } - else { - if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") { - socksServer->addBytestream(id, from, to, bytestream); - Bytestreams::ref bytestreams(new Bytestreams()); - bytestreams->setStreamID(id); - HostAddressPort addressPort = socksServer->getAddressPort(); - bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort())); - BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter); - request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleBytestreamsRequestResponse, this, _1, _2)); - request->send(); - } - else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") { - ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, to, bytestream, iqRouter)); - ibbSession->onFinished.connect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1)); - ibbSession->start(); - } - } -} - -void OutgoingFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { - if (error) { - finish(FileTransferError()); - } - //socksServer->onTransferFinished.connect(); -} - -void OutgoingFileTransfer::finish(boost::optional<FileTransferError> error) { - if (ibbSession) { - ibbSession->onFinished.disconnect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1)); - ibbSession.reset(); - } - socksServer->removeBytestream(id, from, to); - onFinished(error); -} - -void OutgoingFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) { - finish(error); +OutgoingFileTransfer::~OutgoingFileTransfer() { } } diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.h b/Swiften/FileTransfer/OutgoingFileTransfer.h index a694c13..a8c1e81 100644 --- a/Swiften/FileTransfer/OutgoingFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingFileTransfer.h @@ -6,47 +6,12 @@ #pragma once -#include <boost/shared_ptr.hpp> - -#include "Swiften/FileTransfer/ReadBytestream.h" -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/FileTransfer/FileTransferError.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/StreamInitiation.h" -#include "Swiften/Elements/Bytestreams.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/FileTransfer/IBBSendSession.h" - namespace Swift { - class IQRouter; - class SOCKS5BytestreamServer; - class OutgoingFileTransfer { public: - OutgoingFileTransfer(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); - - void start(); - void stop(); - - boost::signal<void (const boost::optional<FileTransferError>&)> onFinished; - - private: - void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref); - void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref); - void finish(boost::optional<FileTransferError> error); - void handleIBBSessionFinished(boost::optional<FileTransferError> error); + virtual ~OutgoingFileTransfer(); - private: - std::string id; - JID from; - JID to; - std::string name; - int size; - std::string description; - boost::shared_ptr<ReadBytestream> bytestream; - IQRouter* iqRouter; - SOCKS5BytestreamServer* socksServer; - boost::shared_ptr<IBBSendSession> ibbSession; + virtual void start() = 0; + virtual void stop() = 0; }; } diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp new file mode 100644 index 0000000..2ed3a9d --- /dev/null +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/FileTransfer/OutgoingSIFileTransfer.h" + +#include <boost/bind.hpp> + +#include "Swiften/FileTransfer/StreamInitiationRequest.h" +#include "Swiften/FileTransfer/BytestreamsRequest.h" +#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" +#include "Swiften/FileTransfer/IBBSendSession.h" + +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) { +} + +void OutgoingSIFileTransfer::start() { + StreamInitiation::ref streamInitiation(new StreamInitiation()); + streamInitiation->setID(id); + streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size)); + //streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams"); + streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb"); + StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter); + request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); + request->send(); +} + +void OutgoingSIFileTransfer::stop() { +} + +void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { + if (error) { + finish(FileTransferError()); + } + else { + if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") { + socksServer->addBytestream(id, from, to, bytestream); + Bytestreams::ref bytestreams(new Bytestreams()); + bytestreams->setStreamID(id); + HostAddressPort addressPort = socksServer->getAddressPort(); + bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort())); + BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter); + request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleBytestreamsRequestResponse, this, _1, _2)); + request->send(); + } + else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") { + ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, to, bytestream, iqRouter)); + ibbSession->onFinished.connect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); + ibbSession->start(); + } + } +} + +void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { + if (error) { + finish(FileTransferError()); + } + //socksServer->onTransferFinished.connect(); +} + +void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError> error) { + if (ibbSession) { + ibbSession->onFinished.disconnect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); + ibbSession.reset(); + } + socksServer->removeBytestream(id, from, to); + onFinished(error); +} + +void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) { + finish(error); +} + +} diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.h b/Swiften/FileTransfer/OutgoingSIFileTransfer.h new file mode 100644 index 0000000..cdf988f --- /dev/null +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.h @@ -0,0 +1,53 @@ +/* + * 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/shared_ptr.hpp> + +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> +#include "Swiften/FileTransfer/ReadBytestream.h" +#include "Swiften/Base/boost_bsignals.h" +#include "Swiften/FileTransfer/FileTransferError.h" +#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" +#include "Swiften/JID/JID.h" +#include "Swiften/Elements/StreamInitiation.h" +#include "Swiften/Elements/Bytestreams.h" +#include "Swiften/Elements/ErrorPayload.h" +#include "Swiften/FileTransfer/IBBSendSession.h" + +namespace Swift { + class IQRouter; + class SOCKS5BytestreamServer; + + 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); + + virtual void start(); + virtual void stop(); + + boost::signal<void (const boost::optional<FileTransferError>&)> onFinished; + + private: + void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref); + void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref); + void finish(boost::optional<FileTransferError> error); + void handleIBBSessionFinished(boost::optional<FileTransferError> error); + + private: + std::string id; + JID from; + JID to; + std::string name; + int size; + std::string description; + boost::shared_ptr<ReadBytestream> bytestream; + IQRouter* iqRouter; + SOCKS5BytestreamServer* socksServer; + boost::shared_ptr<IBBSendSession> ibbSession; + }; +} diff --git a/Swiften/FileTransfer/ReadBytestream.h b/Swiften/FileTransfer/ReadBytestream.h index 4da2bc2..2601192 100644 --- a/Swiften/FileTransfer/ReadBytestream.h +++ b/Swiften/FileTransfer/ReadBytestream.h @@ -6,13 +6,14 @@ #pragma once -#include "Swiften/Base/ByteArray.h" +#include <vector> +#include <cstring> namespace Swift { class ReadBytestream { public: virtual ~ReadBytestream(); - virtual ByteArray read(size_t size) = 0; + virtual std::vector<unsigned char> read(size_t size) = 0; virtual bool isFinished() const = 0; }; } diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp new file mode 100644 index 0000000..338f221 --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp @@ -0,0 +1,14 @@ +/* + * 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/RemoteJingleTransportCandidateSelector.h> + +namespace Swift { + +RemoteJingleTransportCandidateSelector::~RemoteJingleTransportCandidateSelector() { +} + +} diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h new file mode 100644 index 0000000..b12b06b --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h @@ -0,0 +1,29 @@ +/* + * 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/Base/boost_bsignals.h> + +#include <Swiften/Elements/JingleTransportPayload.h> +#include <Swiften/FileTransfer/JingleTransport.h> + +namespace Swift { + class RemoteJingleTransportCandidateSelector { + public: + virtual ~RemoteJingleTransportCandidateSelector(); + + virtual void addRemoteTransportCandidates(JingleTransportPayload::ref) = 0; + virtual void selectCandidate() = 0; + virtual void setMinimumPriority(int) = 0; + + virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; + virtual int getPriority(JingleTransportPayload::ref) = 0; + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + + boost::signal<void (JingleTransportPayload::ref)> onRemoteTransportCandidateSelectFinished; + }; +} diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp new file mode 100644 index 0000000..36b7cba --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp @@ -0,0 +1,14 @@ +/* + * 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 new file mode 100644 index 0000000..caa3097 --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h @@ -0,0 +1,18 @@ +/* + * 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 ea9e7bb..24fc9e8 100644 --- a/Swiften/FileTransfer/SConscript +++ b/Swiften/FileTransfer/SConscript @@ -1,10 +1,17 @@ -Import("swiften_env") +Import("swiften_env", "env") sources = [ "OutgoingFileTransfer.cpp", + "OutgoingSIFileTransfer.cpp", "IncomingFileTransfer.cpp", "IncomingJingleFileTransfer.cpp", - "IncomingFileTransferManager.cpp", + "IncomingFileTransferManager.cpp", + "RemoteJingleTransportCandidateSelector.cpp", + "RemoteJingleTransportCandidateSelectorFactory.cpp", + "LocalJingleTransportCandidateGenerator.cpp", + "LocalJingleTransportCandidateGeneratorFactory.cpp", + "JingleTransport.cpp", + "JingleIncomingIBBTransport.cpp", "ReadBytestream.cpp", "WriteBytestream.cpp", "FileReadBytestream.cpp", @@ -17,3 +24,9 @@ sources = [ ] swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources)) + +env.Append(UNITTEST_SOURCES = [ + File("UnitTest/SOCKS5BytestreamServerSessionTest.cpp"), + File("UnitTest/IBBSendSessionTest.cpp"), + File("UnitTest/IBBReceiveSessionTest.cpp"), + ]) diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp index 9951f7a..268ba4c 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp @@ -7,6 +7,7 @@ #include "Swiften/FileTransfer/SOCKS5BytestreamServerSession.h" #include <boost/bind.hpp> +#include <iostream> #include "Swiften/Base/ByteArray.h" #include "Swiften/FileTransfer/SOCKS5BytestreamRegistry.h" @@ -98,7 +99,7 @@ void SOCKS5BytestreamServerSession::sendData() { try { connection->write(bytestream->read(chunkSize)); } - catch (const BytestreamException& e) { + catch (const BytestreamException&) { finish(true); } } diff --git a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp new file mode 100644 index 0000000..590443f --- /dev/null +++ b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp @@ -0,0 +1,188 @@ +/* + * 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 <vector> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/ByteArray.h> +#include "Swiften/FileTransfer/IBBReceiveSession.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Client/DummyStanzaChannel.h" + +using namespace Swift; + +class IBBReceiveSessionTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(IBBReceiveSessionTest); + CPPUNIT_TEST(testOpen); + CPPUNIT_TEST(testReceiveData); + CPPUNIT_TEST(testReceiveMultipleData); + CPPUNIT_TEST(testReceiveDataForOtherSession); + CPPUNIT_TEST(testReceiveDataOutOfOrder); + CPPUNIT_TEST(testReceiveLastData); + CPPUNIT_TEST(testReceiveClose); + CPPUNIT_TEST(testStopWhileActive); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + stanzaChannel = new DummyStanzaChannel(); + iqRouter = new IQRouter(stanzaChannel); + finished = false; + } + + void tearDown() { + delete iqRouter; + delete stanzaChannel; + } + + void testOpen() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(0, "id-open")); + CPPUNIT_ASSERT(!finished); + + testling->stop(); + } + + void testReceiveData() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(1, "id-a")); + CPPUNIT_ASSERT(ByteArray::create("abc") == receivedData); + CPPUNIT_ASSERT(!finished); + + testling->stop(); + } + + void testReceiveMultipleData() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, ByteArray::create("def")), "foo@bar.com/baz", "id-b")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); + CPPUNIT_ASSERT(ByteArray::create("abcdef") == receivedData); + CPPUNIT_ASSERT(!finished); + + testling->stop(); + } + + void testReceiveDataForOtherSession() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("othersession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a")); + + CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(1, "id-a")); + + testling->stop(); + } + + void testReceiveDataOutOfOrder() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("def")), "foo@bar.com/baz", "id-b")); + + CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(2, "id-b")); + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(error); + + testling->stop(); + } + + void testReceiveLastData() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession", 6)); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, ByteArray::create("def")), "foo@bar.com/baz", "id-b")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); + CPPUNIT_ASSERT(ByteArray::create("abcdef") == receivedData); + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(!error); + + testling->stop(); + } + + void testReceiveClose() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBClose("mysession"), "foo@bar.com/baz", "id-close")); + + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(error); + + testling->stop(); + } + + void testStopWhileActive() { + std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + testling->stop(); + + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set)); + IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>(); + CPPUNIT_ASSERT_EQUAL(IBB::Close, ibb->getAction()); + CPPUNIT_ASSERT_EQUAL(std::string("mysession"), ibb->getStreamID()); + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(!error); + } + + private: + IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { + IQ::ref request = IQ::createRequest(IQ::Set, JID("baz@fum.com/dum"), id, ibb); + request->setFrom(from); + return request; + } + + IBBReceiveSession* createSession(const std::string& from, const std::string& id, size_t size = 0x1000) { + IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), size, iqRouter); + session->onDataReceived.connect(boost::bind(&IBBReceiveSessionTest::handleDataReceived, this, _1)); + session->onFinished.connect(boost::bind(&IBBReceiveSessionTest::handleFinished, this, _1)); + return session; + } + + + void handleFinished(boost::optional<FileTransferError> error) { + finished = true; + this->error = error; + } + + void handleDataReceived(const std::vector<unsigned char>& data) { + receivedData.insert(receivedData.end(), data.begin(), data.end()); + } + + private: + DummyStanzaChannel* stanzaChannel; + IQRouter* iqRouter; + bool finished; + boost::optional<FileTransferError> error; + std::vector<unsigned char> receivedData; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(IBBReceiveSessionTest); diff --git a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp index 0cd273a..32df34b 100644 --- a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp @@ -4,13 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" - #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <vector> #include <boost/bind.hpp> +#include "Swiften/Base/ByteArray.h" #include "Swiften/FileTransfer/IBBSendSession.h" #include "Swiften/FileTransfer/ByteArrayReadBytestream.h" #include "Swiften/Queries/IQRouter.h" @@ -33,7 +32,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { void setUp() { stanzaChannel = new DummyStanzaChannel(); iqRouter = new IQRouter(stanzaChannel); - bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg"))); + bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray::create("abcdefg"))); } void tearDown() { @@ -66,7 +65,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set)); IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>(); CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction()); - CPPUNIT_ASSERT_EQUAL(ByteArray("abc"), ibb->getData()); + CPPUNIT_ASSERT(ByteArray::create("abc") == ibb->getData()); CPPUNIT_ASSERT_EQUAL(0, ibb->getSequenceNumber()); CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID()); } @@ -82,7 +81,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(2, JID("foo@bar.com/baz"), IQ::Set)); IBB::ref ibb = stanzaChannel->sentStanzas[2]->getPayload<IBB>(); CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction()); - CPPUNIT_ASSERT_EQUAL(ByteArray("def"), ibb->getData()); + CPPUNIT_ASSERT(ByteArray::create("def") == ibb->getData()); CPPUNIT_ASSERT_EQUAL(1, ibb->getSequenceNumber()); CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID()); } diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp index c6d246d..1c1a246 100644 --- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp @@ -35,7 +35,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { eventLoop = new DummyEventLoop(); connection = boost::shared_ptr<DummyConnection>(new DummyConnection(eventLoop)); connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1)); - stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg"))); + stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray::create("abcdefg"))); } void tearDown() { @@ -47,20 +47,20 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - receive(ByteArray("\x05\x02\x01\x02")); + receive(ByteArray::create("\x05\x02\x01\x02")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData); + CPPUNIT_ASSERT(ByteArray::create("\x05\x00", 2) == receivedData); } void testAuthenticate_Chunked() { std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - receive(ByteArray("\x05\x02\x01")); + receive(ByteArray::create("\x05\x02\x01")); - CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.getSize())); - receive(ByteArray("\x01")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.size())); + receive(ByteArray::create("\x01")); + CPPUNIT_ASSERT(ByteArray::create("\x05\x00", 2) == receivedData); } void testRequest() { @@ -70,8 +70,8 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { authenticate(); ByteArray hostname("abcdef"); - receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), ByteArray(receivedData.getData(), 13)); + receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.getSize() + hostname + ByteArray::create("\x00\x00", 2)); + CPPUNIT_ASSERT(ByteArray::create("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == ByteArray::create(&receivedData[0], 13)); } void testRequest_UnknownBytestream() { @@ -80,8 +80,8 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { authenticate(); ByteArray hostname("abcdef"); - receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), receivedData); + receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.getSize() + hostname + ByteArray::create("\x00\x00", 2)); + CPPUNIT_ASSERT(ByteArray::create("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == receivedData); } void testReceiveData() { @@ -93,7 +93,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { eventLoop->processEvents(); skipHeader("abcdef"); - CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData); + CPPUNIT_ASSERT(ByteArray::create("abcdefg") == receivedData); CPPUNIT_ASSERT_EQUAL(2, receivedDataChunks); } @@ -107,7 +107,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { eventLoop->processEvents(); skipHeader("abcdef"); - CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData); + CPPUNIT_ASSERT(ByteArray::create("abcdefg") == receivedData); CPPUNIT_ASSERT_EQUAL(4, receivedDataChunks); } @@ -118,23 +118,23 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { } void authenticate() { - receive(ByteArray("\x05\x02\x01\x02")); + receive(ByteArray::create("\x05\x02\x01\x02")); receivedData.clear(); receivedDataChunks = 0; } void request(const std::string& hostname) { - receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.size() + hostname + ByteArray("\x00\x00", 2)); + receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.size() + hostname + ByteArray::create("\x00\x00", 2)); } void skipHeader(const std::string& hostname) { int headerSize = 7 + hostname.size(); - receivedData = ByteArray(receivedData.getData() + headerSize, receivedData.getSize() - headerSize); + receivedData = ByteArray::create(&receivedData[headerSize], receivedData.size() - headerSize); } void handleDataWritten(const ByteArray& data) { - receivedData += data; + receivedData.insert(receivedData.end(), data.begin(), data.end()); receivedDataChunks++; } @@ -148,7 +148,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { DummyEventLoop* eventLoop; SOCKS5BytestreamRegistry bytestreams; boost::shared_ptr<DummyConnection> connection; - ByteArray receivedData; + std::vector<unsigned char> receivedData; int receivedDataChunks; boost::shared_ptr<ByteArrayReadBytestream> stream1; }; diff --git a/Swiften/FileTransfer/WriteBytestream.h b/Swiften/FileTransfer/WriteBytestream.h index 1dc791c..c27aeff 100644 --- a/Swiften/FileTransfer/WriteBytestream.h +++ b/Swiften/FileTransfer/WriteBytestream.h @@ -7,8 +7,7 @@ #pragma once #include <boost/shared_ptr.hpp> - -#include "Swiften/Base/ByteArray.h" +#include <vector> namespace Swift { class WriteBytestream { @@ -17,6 +16,6 @@ namespace Swift { virtual ~WriteBytestream(); - virtual void write(const ByteArray&) = 0; + virtual void write(const std::vector<unsigned char>&) = 0; }; } diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index e4611b3..00adf34 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -7,12 +7,17 @@ #define SWIFTEN_CACHE_JID_PREP #include <vector> +#include <list> #include <iostream> #include <string> #ifdef SWIFTEN_CACHE_JID_PREP #include <boost/unordered_map.hpp> #endif +#include <boost/assign/list_of.hpp> +#include <boost/algorithm/string/find_format.hpp> +#include <boost/algorithm/string/finder.hpp> +#include <sstream> #include <stringprep.h> #include <Swiften/Base/String.h> @@ -27,6 +32,75 @@ static PrepCache domainPrepCache; static PrepCache resourcePrepCache; #endif +static const std::list<char> escapedChars = boost::assign::list_of(' ')('"')('&')('\'')('/')('<')('>')('@')(':'); + +bool getEscapeSequenceValue(const std::string& sequence, unsigned char& value) { + std::stringstream s; + unsigned int v; + s << std::hex << sequence; + s >> v; + value = static_cast<unsigned char>(v); + return (!s.fail() && !s.bad() && (value == 0x5C || std::find(escapedChars.begin(), escapedChars.end(), value) != escapedChars.end())); +} + +struct UnescapedCharacterFinder { + template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { + for (; begin != end; ++begin) { + if (std::find(escapedChars.begin(), escapedChars.end(), *begin) != escapedChars.end()) { + return boost::iterator_range<Iterator>(begin, begin + 1); + } + else if (*begin == '\\') { + // Check if we have an escaped dissalowed character sequence + Iterator innerBegin = begin + 1; + if (innerBegin != end && innerBegin + 1 != end) { + Iterator innerEnd = innerBegin + 2; + unsigned char value; + if (getEscapeSequenceValue(std::string(innerBegin, innerEnd), value)) { + return boost::iterator_range<Iterator>(begin, begin + 1); + } + } + } + } + return boost::iterator_range<Iterator>(end, end); + } +}; + +struct UnescapedCharacterFormatter { + template<typename FindResult> std::string operator()(const FindResult& match) const { + std::ostringstream s; + s << '\\' << std::hex << static_cast<int>(*match.begin()); + return s.str(); + } +}; + +struct EscapedCharacterFinder { + template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { + for (; begin != end; ++begin) { + if (*begin == '\\') { + Iterator innerEnd = begin + 1; + for (size_t i = 0; i < 2 && innerEnd != end; ++i, ++innerEnd) { + } + unsigned char value; + if (getEscapeSequenceValue(std::string(begin + 1, innerEnd), value)) { + return boost::iterator_range<Iterator>(begin, innerEnd); + } + } + } + return boost::iterator_range<Iterator>(end, end); + } +}; + +struct EscapedCharacterFormatter { + template<typename FindResult> std::string operator()(const FindResult& match) const { + unsigned char value; + if (getEscapeSequenceValue(std::string(match.begin() + 1, match.end()), value)) { + return std::string(reinterpret_cast<const char*>(&value), 1); + } + return boost::copy_range<std::string>(match); + } +}; + + namespace Swift { JID::JID(const char* jid) { @@ -126,5 +200,13 @@ int JID::compare(const Swift::JID& o, CompareType compareType) const { return 0; } +std::string JID::getEscapedNode(const std::string& node) { + return boost::find_format_all_copy(node, UnescapedCharacterFinder(), UnescapedCharacterFormatter()); +} + +std::string JID::getUnescapedNode() const { + return boost::find_format_all_copy(node_, EscapedCharacterFinder(), EscapedCharacterFormatter()); +} + } // namespace Swift diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h index 63e063d..98b42da 100644 --- a/Swiften/JID/JID.h +++ b/Swiften/JID/JID.h @@ -7,7 +7,7 @@ #pragma once #include <string> -#include <ostream> +#include <iosfwd> namespace Swift { class JID { @@ -38,6 +38,18 @@ namespace Swift { return !hasResource_; } + /** + * Returns the given node, escaped according to XEP-0106. + * The resulting node is a valid node for a JID, whereas the input value can contain characters + * that are not allowed. + */ + static std::string getEscapedNode(const std::string& node); + + /** + * Returns the node of the current JID, unescaped according to XEP-0106. + */ + std::string getUnescapedNode() const; + JID toBare() const { JID result(*this); result.hasResource_ = false; diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp index 0f22e15..5e79db2 100644 --- a/Swiften/JID/UnitTest/JIDTest.cpp +++ b/Swiften/JID/UnitTest/JIDTest.cpp @@ -51,6 +51,10 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testSmallerThan_Larger); CPPUNIT_TEST(testHasResource); CPPUNIT_TEST(testHasResource_NoResource); + CPPUNIT_TEST(testGetEscapedNode); + CPPUNIT_TEST(testGetEscapedNode_XEP106Examples); + CPPUNIT_TEST(testGetUnescapedNode); + CPPUNIT_TEST(testGetUnescapedNode_XEP106Examples); CPPUNIT_TEST_SUITE_END(); public: @@ -311,6 +315,57 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_ASSERT(testling.isBare()); } + + void testGetEscapedNode() { + std::string escaped = JID::getEscapedNode("alice@wonderland.lit"); + CPPUNIT_ASSERT_EQUAL(std::string("alice\\40wonderland.lit"), escaped); + + escaped = JID::getEscapedNode("\\& \" ' / <\\\\> @ :\\3a\\40"); + CPPUNIT_ASSERT_EQUAL(std::string("\\\\26\\20\\22\\20\\27\\20\\2f\\20\\3c\\\\\\3e\\20\\40\\20\\3a\\5c3a\\5c40"), escaped); + } + + void testGetEscapedNode_XEP106Examples() { + CPPUNIT_ASSERT_EQUAL(std::string("\\2plus\\2is\\4"), JID::getEscapedNode("\\2plus\\2is\\4")); + CPPUNIT_ASSERT_EQUAL(std::string("foo\\bar"), JID::getEscapedNode("foo\\bar")); + CPPUNIT_ASSERT_EQUAL(std::string("foob\\41r"), JID::getEscapedNode("foob\\41r")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("space cadet"), std::string("space\\20cadet")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("call me \"ishmael\""), std::string("call\\20me\\20\\22ishmael\\22")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("at&t guy"), std::string("at\\26t\\20guy")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("d'artagnan"), std::string("d\\27artagnan")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("/.fanboy"), std::string("\\2f.fanboy")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("::foo::"), std::string("\\3a\\3afoo\\3a\\3a")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("<foo>"), std::string("\\3cfoo\\3e")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("user@host"), std::string("user\\40host")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\net"), std::string("c\\3a\\net")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\\\net"), std::string("c\\3a\\\\net")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\cool stuff"), std::string("c\\3a\\cool\\20stuff")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\5commas"), std::string("c\\3a\\5c5commas")); + } + + void testGetUnescapedNode() { + std::string input = "\\& \" ' / <\\\\> @ : \\5c\\40"; + JID testling(JID::getEscapedNode(input) + "@y"); + CPPUNIT_ASSERT(testling.isValid()); + CPPUNIT_ASSERT_EQUAL(input, testling.getUnescapedNode()); + } + + void testGetUnescapedNode_XEP106Examples() { + CPPUNIT_ASSERT_EQUAL(std::string("\\2plus\\2is\\4"), JID("\\2plus\\2is\\4@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("foo\\bar"), JID("foo\\bar@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("foob\\41r"), JID("foob\\41r@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("space cadet"), JID("space\\20cadet@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("call me \"ishmael\""), JID("call\\20me\\20\\22ishmael\\22@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("at&t guy"), JID("at\\26t\\20guy@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("d'artagnan"), JID("d\\27artagnan@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("/.fanboy"), JID("\\2f.fanboy@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("::foo::"), JID("\\3a\\3afoo\\3a\\3a@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("<foo>"), JID("\\3cfoo\\3e@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("user@host"), JID("user\\40host@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\net"), JID("c\\3a\\net@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\\\net"), JID("c\\3a\\\\net@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\cool stuff"), JID("c\\3a\\cool\\20stuff@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\5commas"), JID("c\\3a\\5c5commas@example.com").getUnescapedNode()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest); diff --git a/Swiften/Jingle/IncomingJingleSession.cpp b/Swiften/Jingle/IncomingJingleSession.cpp deleted file mode 100644 index b18d9d3..0000000 --- a/Swiften/Jingle/IncomingJingleSession.cpp +++ /dev/null @@ -1,15 +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/Jingle/IncomingJingleSession.h> - -namespace Swift { - -IncomingJingleSession::IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : JingleSession(id, contents) { - -} - -} diff --git a/Swiften/Jingle/IncomingJingleSession.h b/Swiften/Jingle/IncomingJingleSession.h deleted file mode 100644 index 64816f6..0000000 --- a/Swiften/Jingle/IncomingJingleSession.h +++ /dev/null @@ -1,20 +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/Jingle/JingleSession.h> - -namespace Swift { - class IncomingJingleSession : public JingleSession { - public: - IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents); - - typedef boost::shared_ptr<IncomingJingleSession> ref; - }; -} diff --git a/Swiften/Jingle/IncomingJingleSessionHandler.h b/Swiften/Jingle/IncomingJingleSessionHandler.h index 5bf9237..4d22a4e 100644 --- a/Swiften/Jingle/IncomingJingleSessionHandler.h +++ b/Swiften/Jingle/IncomingJingleSessionHandler.h @@ -6,13 +6,13 @@ #pragma once -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Jingle/JingleSession.h> namespace Swift { class IncomingJingleSessionHandler { public: virtual ~IncomingJingleSessionHandler(); - virtual bool handleIncomingJingleSession(IncomingJingleSession::ref) = 0; + virtual bool handleIncomingJingleSession(JingleSession::ref, const std::vector<JingleContentPayload::ref>& contents) = 0; }; } diff --git a/Swiften/Jingle/Jingle.h b/Swiften/Jingle/Jingle.h new file mode 100644 index 0000000..ba4dfe3 --- /dev/null +++ b/Swiften/Jingle/Jingle.h @@ -0,0 +1,25 @@ +/* + * 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 <vector> + +#include <Swiften/Elements/JingleContentPayload.h> + +namespace Swift { + namespace Jingle { + template<typename T> + JingleContentPayload::ref getContentWithDescription(const std::vector<JingleContentPayload::ref>& contents) { + for (size_t i = 0; i < contents.size(); ++i) { + if (contents[i]->getDescription<T>()) { + return contents[i]; + } + } + return JingleContentPayload::ref(); + } + } +} diff --git a/Swiften/Jingle/JingleContentID.h b/Swiften/Jingle/JingleContentID.h new file mode 100644 index 0000000..8d75581 --- /dev/null +++ b/Swiften/Jingle/JingleContentID.h @@ -0,0 +1,23 @@ +/* + * 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 <string> + +#include <Swiften/Elements/JingleContentPayload.h> + +namespace Swift { + class JingleContentID { + public: + JingleContentID(const std::string& name, JingleContentPayload::Creator creator) : name(name), creator(creator) { + } + + private: + std::string name; + JingleContentPayload::Creator creator; + }; +} diff --git a/Swiften/Jingle/JingleResponder.cpp b/Swiften/Jingle/JingleResponder.cpp index 2397e63..198f9a2 100644 --- a/Swiften/Jingle/JingleResponder.cpp +++ b/Swiften/Jingle/JingleResponder.cpp @@ -9,7 +9,7 @@ #include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Jingle/JingleSessionManager.h> -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Jingle/JingleSessionImpl.h> namespace Swift { @@ -24,12 +24,12 @@ bool JingleResponder::handleSetRequest(const JID& from, const JID&, const std::s } else { sendResponse(from, id, boost::shared_ptr<JinglePayload>()); - IncomingJingleSession::ref session = boost::make_shared<IncomingJingleSession>(id, payload->getContents()); - sessionManager->handleIncomingSession(from, session); + JingleSessionImpl::ref session = boost::make_shared<JingleSessionImpl>(payload->getInitiator(), payload->getSessionID()); + sessionManager->handleIncomingSession(from, session, payload->getContents()); } } else { - JingleSession::ref session = sessionManager->getSession(from, payload->getSessionID()); + JingleSessionImpl::ref session = sessionManager->getSession(from, payload->getSessionID()); if (session) { session->handleIncomingAction(payload); sendResponse(from, id, boost::shared_ptr<JinglePayload>()); diff --git a/Swiften/Jingle/JingleSession.cpp b/Swiften/Jingle/JingleSession.cpp index d255abd..1366191 100644 --- a/Swiften/Jingle/JingleSession.cpp +++ b/Swiften/Jingle/JingleSession.cpp @@ -10,21 +10,11 @@ namespace Swift { -JingleSession::JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : id(id), contents(contents) { +JingleSession::JingleSession(const JID& initiator, const std::string& id) : initiator(initiator), id(id) { } JingleSession::~JingleSession() { } -void JingleSession::handleIncomingAction(JinglePayload::ref) { -} - -void JingleSession::terminate(JinglePayload::Reason::Type reason) { - JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, id); - payload->setReason(JinglePayload::Reason(reason)); - //onAction(payload) -} - - } diff --git a/Swiften/Jingle/JingleSession.h b/Swiften/Jingle/JingleSession.h index c00492d..fa7da7e 100644 --- a/Swiften/Jingle/JingleSession.h +++ b/Swiften/Jingle/JingleSession.h @@ -7,47 +7,43 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <string> #include <Swiften/Base/boost_bsignals.h> -#include <string> +#include <Swiften/JID/JID.h> #include <Swiften/Elements/JinglePayload.h> -#include <Swiften/Elements/JingleContent.h> -#include <Swiften/Base/foreach.h> namespace Swift { + class JingleContentID; + class JingleSession { - friend class JingleResponder; public: typedef boost::shared_ptr<JingleSession> ref; - JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents); + JingleSession(const JID& initiator, const std::string& id); virtual ~JingleSession(); - std::string getID() const { - return id; + const JID& getInitiator() const { + return initiator; } - template<typename T> - JingleContent::ref getContentWithDescription() const { - foreach (JingleContent::ref content, contents) { - if (content->getDescription<T>()) { - return content; - } - } - return JingleContent::ref(); - } - - const std::vector<JingleContent::ref> getContents() const { - return contents; + std::string getID() const { + return id; } - void terminate(JinglePayload::Reason::Type reason); + virtual void terminate(JinglePayload::Reason::Type reason) = 0; + virtual void accept(JingleTransportPayload::ref = JingleTransportPayload::ref()) = 0; + virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) = 0; + virtual void acceptTransport(const JingleContentID&, JingleTransportPayload::ref) = 0; + virtual void rejectTransport(const JingleContentID&, JingleTransportPayload::ref) = 0; - private: - void handleIncomingAction(JinglePayload::ref); + public: + boost::signal<void ()> onSessionTerminateReceived; + boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportInfoReceived; + boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportReplaceReceived; private: + JID initiator; std::string id; - std::vector<JingleContent::ref> contents; }; } diff --git a/Swiften/Jingle/JingleSessionImpl.cpp b/Swiften/Jingle/JingleSessionImpl.cpp new file mode 100644 index 0000000..cbb2b42 --- /dev/null +++ b/Swiften/Jingle/JingleSessionImpl.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Jingle/JingleSessionImpl.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +JingleSessionImpl::JingleSessionImpl(const JID& initiator, const std::string& id) : JingleSession(initiator, id) { +} + +void JingleSessionImpl::handleIncomingAction(JinglePayload::ref) { +} + +void JingleSessionImpl::terminate(JinglePayload::Reason::Type reason) { + JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, getID()); + payload->setReason(JinglePayload::Reason(reason)); + //onAction(payload) +} + +void JingleSessionImpl::acceptTransport(const JingleContentID&, JingleTransportPayload::ref) { + +} + +void JingleSessionImpl::rejectTransport(const JingleContentID&, JingleTransportPayload::ref) { + +} + +void JingleSessionImpl::accept(JingleTransportPayload::ref) { +} + +void JingleSessionImpl::sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) { + +} + + + +} diff --git a/Swiften/Jingle/JingleSessionImpl.h b/Swiften/Jingle/JingleSessionImpl.h new file mode 100644 index 0000000..a254ead --- /dev/null +++ b/Swiften/Jingle/JingleSessionImpl.h @@ -0,0 +1,30 @@ +/* + * 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/Jingle/JingleSession.h> + +namespace Swift { + class JingleSessionImpl : public JingleSession { + friend class JingleResponder; + public: + typedef boost::shared_ptr<JingleSessionImpl> ref; + + JingleSessionImpl(const JID& initiator, const std::string& id); + + virtual void terminate(JinglePayload::Reason::Type reason); + virtual void accept(JingleTransportPayload::ref); + virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref); + virtual void acceptTransport(const JingleContentID&, JingleTransportPayload::ref); + virtual void rejectTransport(const JingleContentID&, JingleTransportPayload::ref); + + private: + void handleIncomingAction(JinglePayload::ref); + }; +} diff --git a/Swiften/Jingle/JingleSessionManager.cpp b/Swiften/Jingle/JingleSessionManager.cpp index e60449b..58e90c8 100644 --- a/Swiften/Jingle/JingleSessionManager.cpp +++ b/Swiften/Jingle/JingleSessionManager.cpp @@ -7,6 +7,7 @@ #include <Swiften/Jingle/JingleSessionManager.h> #include <Swiften/Jingle/JingleResponder.h> #include <Swiften/Jingle/IncomingJingleSessionHandler.h> +#include <Swiften/Base/foreach.h> namespace Swift { @@ -18,9 +19,9 @@ JingleSessionManager::~JingleSessionManager() { delete responder; } -JingleSession::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const { +JingleSessionImpl::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const { SessionMap::const_iterator i = incomingSessions.find(JIDSession(jid, id)); - return i != incomingSessions.end() ? i->second : JingleSession::ref(); + return i != incomingSessions.end() ? i->second : JingleSessionImpl::ref(); } void JingleSessionManager::addIncomingSessionHandler(IncomingJingleSessionHandler* handler) { @@ -31,10 +32,10 @@ void JingleSessionManager::removeIncomingSessionHandler(IncomingJingleSessionHan incomingSessionHandlers.erase(std::remove(incomingSessionHandlers.begin(), incomingSessionHandlers.end(), handler), incomingSessionHandlers.end()); } -void JingleSessionManager::handleIncomingSession(const JID& from, IncomingJingleSession::ref session) { +void JingleSessionManager::handleIncomingSession(const JID& from, JingleSessionImpl::ref session, const std::vector<JingleContentPayload::ref>& contents) { incomingSessions.insert(std::make_pair(JIDSession(from, session->getID()), session)); foreach (IncomingJingleSessionHandler* handler, incomingSessionHandlers) { - if (handler->handleIncomingJingleSession(session)) { + if (handler->handleIncomingJingleSession(session, contents)) { return; } } diff --git a/Swiften/Jingle/JingleSessionManager.h b/Swiften/Jingle/JingleSessionManager.h index 3e99656..3b23fb0 100644 --- a/Swiften/Jingle/JingleSessionManager.h +++ b/Swiften/Jingle/JingleSessionManager.h @@ -10,7 +10,7 @@ #include <map> #include <Swiften/Base/boost_bsignals.h> -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Jingle/JingleSessionImpl.h> namespace Swift { class IQRouter; @@ -23,13 +23,13 @@ namespace Swift { JingleSessionManager(IQRouter* router); ~JingleSessionManager(); - JingleSession::ref getSession(const JID& jid, const std::string& id) const; + JingleSessionImpl::ref getSession(const JID& jid, const std::string& id) const; void addIncomingSessionHandler(IncomingJingleSessionHandler* handler); void removeIncomingSessionHandler(IncomingJingleSessionHandler* handler); protected: - void handleIncomingSession(const JID& from, IncomingJingleSession::ref); + void handleIncomingSession(const JID& from, JingleSessionImpl::ref, const std::vector<JingleContentPayload::ref>& contents); private: IQRouter* router; @@ -43,7 +43,7 @@ namespace Swift { JID jid; std::string session; }; - typedef std::map<JIDSession, JingleSession::ref> SessionMap; + typedef std::map<JIDSession, JingleSessionImpl::ref> SessionMap; SessionMap incomingSessions; }; } diff --git a/Swiften/Jingle/SConscript b/Swiften/Jingle/SConscript index a8890b7..6b3cfd3 100644 --- a/Swiften/Jingle/SConscript +++ b/Swiften/Jingle/SConscript @@ -1,11 +1,11 @@ Import("swiften_env") sources = [ - "IncomingJingleSession.cpp", + "JingleSession.cpp", + "JingleSessionImpl.cpp", "IncomingJingleSessionHandler.cpp", "JingleSessionManager.cpp", "JingleResponder.cpp", - "JingleSession.cpp", ] swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources)) diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp new file mode 100644 index 0000000..e31bf87 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h> + +#include <boost/bind.hpp> +#include <iostream> + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> + +namespace Swift { + +void AvahiBrowseQuery::startBrowsing() { + std::cout << "Start browsing" << std::endl; + assert(!browser); + avahi_threaded_poll_lock(querier->getThreadedPoll()); + browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0), &handleServiceDiscoveredStatic, this); + if (!browser) { + std::cout << "Error" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); + } + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiBrowseQuery::stopBrowsing() { + std::cout << "Stop browsing" << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + avahi_service_browser_free(browser); + browser = NULL; + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiBrowseQuery::handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) { + switch (event) { + case AVAHI_BROWSER_FAILURE: + std::cout << "Service browse error" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); + break; + case AVAHI_BROWSER_NEW: { + DNSSDServiceID service(name, domain, type, interfaceIndex); + std::cout << "Service discovered " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); + break; + } + case AVAHI_BROWSER_REMOVE: { + std::cout << "Service went away " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; + DNSSDServiceID service(name, domain, type, interfaceIndex); + eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); + break; + } + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; + } +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h index 163a5f6..7641712 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/bind.hpp> +#include <avahi-client/lookup.h> #include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" #include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" @@ -20,54 +20,15 @@ namespace Swift { AvahiBrowseQuery(boost::shared_ptr<AvahiQuerier> q, EventLoop* eventLoop) : AvahiQuery(q, eventLoop), browser(NULL) { } - void startBrowsing() { - std::cout << "Start browsing" << std::endl; - assert(!browser); - avahi_threaded_poll_lock(querier->getThreadedPoll()); - browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0), &handleServiceDiscoveredStatic, this); - if (!browser) { - std::cout << "Error" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); - } - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } - - void stopBrowsing() { - std::cout << "Stop browsing" << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - avahi_service_browser_free(browser); - browser = NULL; - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } + void startBrowsing(); + void stopBrowsing(); private: static void handleServiceDiscoveredStatic(AvahiServiceBrowser *b, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* context) { static_cast<AvahiBrowseQuery*>(context)->handleServiceDiscovered(b, interfaceIndex, protocol, event, name, type, domain, flags); } - void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) { - switch (event) { - case AVAHI_BROWSER_FAILURE: - std::cout << "Service browse error" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); - break; - case AVAHI_BROWSER_NEW: { - DNSSDServiceID service(name, domain, type, interfaceIndex); - std::cout << "Service discovered " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); - break; - } - case AVAHI_BROWSER_REMOVE: { - std::cout << "Service went away " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; - DNSSDServiceID service(name, domain, type, interfaceIndex); - eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); - break; - } - case AVAHI_BROWSER_ALL_FOR_NOW: - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - } - } + void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags); private: AvahiServiceBrowser* browser; diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp new file mode 100644 index 0000000..7975e7b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h> + +#include <iostream> +#include <boost/bind.hpp> + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> + +namespace Swift { + +void AvahiRegisterQuery::registerService() { + std::cout << "Registering service " << name << ":" << port << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + if (!group) { + std::cout << "Creating entry group" << std::endl; + group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this); + if (!group) { + std::cout << "Error ceating entry group" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); + } + } + + doRegisterService(); + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiRegisterQuery::unregisterService() { + if (group) { + avahi_entry_group_free(group); + group = NULL; + } +} + +void AvahiRegisterQuery::updateServiceInfo(const ByteArray& txtRecord) { + this->txtRecord = txtRecord; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + assert(group); + avahi_entry_group_reset(group); + doRegisterService(); + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiRegisterQuery::doRegisterService() { + AvahiStringList* txtList; + avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList); + + int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name.c_str(), "_presence._tcp", NULL, NULL, port, txtList); + if (result < 0) { + std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); + } + result = avahi_entry_group_commit(group); + if (result < 0) { + std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; + } +} + +void AvahiRegisterQuery::handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) { + std::cout << "ENtry group callback: " << state << std::endl; + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + // Domain is a hack! + eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this()); + std::cout << "Entry group established" << std::endl; + break; + case AVAHI_ENTRY_GROUP_COLLISION : { + std::cout << "Entry group collision" << std::endl; + /*char *n; + n = avahi_alternative_service_name(name); + avahi_free(name); + name = n;*/ + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE : + std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl; + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + + /* + DNSServiceErrorType result = DNSServiceRegister( + &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port, + txtRecord.getSize(), txtRecord.getData(), + &AvahiRegisterQuery::handleServiceRegisteredStatic, this); + if (result != kDNSServiceErr_NoError) { + sdRef = NULL; + }*/ + //eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); + } +} + + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h index 07966af..3303f1b 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h @@ -21,94 +21,18 @@ namespace Swift { AvahiRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), name(name), port(port), txtRecord(txtRecord), group(0) { } - void registerService() { - std::cout << "Registering service " << name << ":" << port << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - if (!group) { - std::cout << "Creating entry group" << std::endl; - group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this); - if (!group) { - std::cout << "Error ceating entry group" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); - } - } - - doRegisterService(); - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } - - void unregisterService() { - if (group) { - avahi_entry_group_free(group); - group = NULL; - } - } - - void updateServiceInfo(const ByteArray& txtRecord) { - this->txtRecord = txtRecord; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - assert(group); - avahi_entry_group_reset(group); - doRegisterService(); - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } + void registerService(); + void unregisterService(); + void updateServiceInfo(const ByteArray& txtRecord); private: - void doRegisterService() { - AvahiStringList* txtList; - avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList); - - int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name.c_str(), "_presence._tcp", NULL, NULL, port, txtList); - if (result < 0) { - std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); - } - result = avahi_entry_group_commit(group); - if (result < 0) { - std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; - } - } + void doRegisterService(); static void handleEntryGroupChange(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { static_cast<AvahiRegisterQuery*>(userdata)->handleEntryGroupChange(g, state); } - void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) { - std::cout << "ENtry group callback: " << state << std::endl; - switch (state) { - case AVAHI_ENTRY_GROUP_ESTABLISHED : - // Domain is a hack! - eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this()); - std::cout << "Entry group established" << std::endl; - break; - case AVAHI_ENTRY_GROUP_COLLISION : { - std::cout << "Entry group collision" << std::endl; - /*char *n; - n = avahi_alternative_service_name(name); - avahi_free(name); - name = n;*/ - break; - } - - case AVAHI_ENTRY_GROUP_FAILURE : - std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl; - break; - - case AVAHI_ENTRY_GROUP_UNCOMMITED: - case AVAHI_ENTRY_GROUP_REGISTERING: - ; - - /* - DNSServiceErrorType result = DNSServiceRegister( - &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port, - txtRecord.getSize(), txtRecord.getData(), - &AvahiRegisterQuery::handleServiceRegisteredStatic, this); - if (result != kDNSServiceErr_NoError) { - sdRef = NULL; - }*/ - //eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); - } - } + void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state); /* static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp new file mode 100644 index 0000000..d9a1c5c --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +AvahiResolveHostnameQuery::AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), hostname(hostname) { + std::cout << "Resolving hostname " << hostname << std::endl; +} + +void AvahiResolveHostnameQuery::run() { + eventLoop->postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(HostAddress(hostname))), shared_from_this()); +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h index 00712f1..acc1897 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h @@ -19,13 +19,9 @@ namespace Swift { class AvahiResolveHostnameQuery : public DNSSDResolveHostnameQuery, public AvahiQuery { public: - AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), hostname(hostname) { - std::cout << "Resolving hostname " << hostname << std::endl; - } + AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop); - void run() { - eventLoop->postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(HostAddress(hostname))), shared_from_this()); - } + void run(); void finish() { } diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp new file mode 100644 index 0000000..24fe067 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h> + +#include <boost/bind.hpp> +#include <iostream> + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> + +namespace Swift { + +void AvahiResolveServiceQuery::start() { + std::cout << "Start resolving " << service.getName() << " " << service.getType() << " " << service.getDomain() << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + assert(!resolver); + resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().c_str(), service.getType().c_str(), service.getDomain().c_str(), AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0), handleServiceResolvedStatic, this); + if (!resolver) { + std::cout << "Error starting resolver" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); + } + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiResolveServiceQuery::stop() { + std::cout << "Stop resolving" << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + avahi_service_resolver_free(resolver); + resolver = NULL; + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiResolveServiceQuery::handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) { + std::cout << "Resolve finished" << std::endl; + switch(event) { + case AVAHI_RESOLVER_FAILURE: + std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); + break; + case AVAHI_RESOLVER_FOUND: { + std::cout << "Success" << std::endl; + char a[AVAHI_ADDRESS_STR_MAX]; + avahi_address_snprint(a, sizeof(a), address); + + ByteArray txtRecord; + txtRecord.resize(1024); + avahi_string_list_serialize(txt, txtRecord.getData(), txtRecord.getSize()); + + // FIXME: Probably not accurate + std::string fullname = std::string(name) + "." + std::string(type) + "." + std::string(domain) + "."; + std::cout << "Result: " << fullname << "->" << std::string(a) << ":" << port << std::endl; + eventLoop->postEvent( + boost::bind( + boost::ref(onServiceResolved), + Result(fullname, std::string(a), port, txtRecord)), + shared_from_this()); + break; + } + } +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h index e9c4db1..be48409 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h @@ -6,6 +6,8 @@ #pragma once +#include <avahi-client/lookup.h> + #include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" #include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" #include "Swiften/LinkLocal/LinkLocalServiceInfo.h" @@ -20,59 +22,15 @@ namespace Swift { AvahiResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), service(service), resolver(NULL) { } - void start() { - std::cout << "Start resolving " << service.getName() << " " << service.getType() << " " << service.getDomain() << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - assert(!resolver); - resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().c_str(), service.getType().c_str(), service.getDomain().c_str(), AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0), handleServiceResolvedStatic, this); - if (!resolver) { - std::cout << "Error starting resolver" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); - } - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } - - void stop() { - std::cout << "Stop resolving" << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - avahi_service_resolver_free(resolver); - resolver = NULL; - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } + void start(); + void stop(); private: static void handleServiceResolvedStatic(AvahiServiceResolver* resolver, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* context) { static_cast<AvahiResolveServiceQuery*>(context)->handleServiceResolved(resolver, interfaceIndex, protocol, event, name, type, domain, host_name, address, port, txt, flags); } - void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) { - std::cout << "Resolve finished" << std::endl; - switch(event) { - case AVAHI_RESOLVER_FAILURE: - std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); - break; - case AVAHI_RESOLVER_FOUND: { - std::cout << "Success" << std::endl; - char a[AVAHI_ADDRESS_STR_MAX]; - avahi_address_snprint(a, sizeof(a), address); - - ByteArray txtRecord; - txtRecord.resize(1024); - avahi_string_list_serialize(txt, txtRecord.getData(), txtRecord.getSize()); - - // FIXME: Probably not accurate - std::string fullname = std::string(name) + "." + std::string(type) + "." + std::string(domain) + "."; - std::cout << "Result: " << fullname << "->" << std::string(a) << ":" << port << std::endl; - eventLoop->postEvent( - boost::bind( - boost::ref(onServiceResolved), - Result(fullname, std::string(a), port, txtRecord)), - shared_from_this()); - break; - } - } - } + void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags); private: DNSSDServiceID service; diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h index edd3056..c342247 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h @@ -9,7 +9,7 @@ #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <list> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp index d7d0228..b13b0c4 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp @@ -7,7 +7,9 @@ #include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" #include <boost/bind.hpp> +#include <iostream> +#include <Swiften/Base/foreach.h> #include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h" #include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h" #include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h" diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h index b2871c9..9aef6a5 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h @@ -11,7 +11,6 @@ #include <list> #include <set> -#include "Swiften/Base/foreach.h" #include <string> #include "Swiften/EventLoop/EventOwner.h" #include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" @@ -63,8 +62,8 @@ namespace Swift { template<typename T> std::vector< boost::shared_ptr<T> > getAllQueriesEverRun() const { std::vector< boost::shared_ptr<T> > result; - foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, allQueriesEverRun) { - if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) { + for (QueryList::const_iterator i = allQueriesEverRun.begin(); i != allQueriesEverRun.end(); ++i) { + if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(*i)) { result.push_back(resultQuery); } } @@ -75,8 +74,8 @@ namespace Swift { template<typename T> std::vector< boost::shared_ptr<T> > getQueries() const { std::vector< boost::shared_ptr<T> > result; - foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, runningQueries) { - if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) { + for (QueryList::const_iterator i = runningQueries.begin(); i != runningQueries.end(); ++i) { + if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(*i)) { result.push_back(resultQuery); } } @@ -86,8 +85,9 @@ namespace Swift { private: std::string domain; EventLoop* eventLoop; - std::list< boost::shared_ptr<FakeDNSSDQuery> > runningQueries; - std::list< boost::shared_ptr<FakeDNSSDQuery> > allQueriesEverRun; + typedef std::list< boost::shared_ptr<FakeDNSSDQuery> > QueryList; + QueryList runningQueries; + QueryList allQueriesEverRun; std::set<DNSSDServiceID> services; typedef std::map<DNSSDServiceID,DNSSDResolveServiceQuery::Result> ServiceInfoMap; ServiceInfoMap serviceInfo; diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp index 65542d2..d13032d 100644 --- a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp +++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp @@ -8,6 +8,7 @@ #include <boost/bind.hpp> +#include <Swiften/Base/foreach.h> #include "Swiften/StreamStack/XMPPLayer.h" #include "Swiften/Elements/ProtocolHeader.h" #include "Swiften/Elements/StreamFeatures.h" diff --git a/Swiften/LinkLocal/SConscript b/Swiften/LinkLocal/SConscript index 6edf993..29ea692 100644 --- a/Swiften/LinkLocal/SConscript +++ b/Swiften/LinkLocal/SConscript @@ -31,7 +31,11 @@ elif myenv.get("HAVE_AVAHI", 0) : myenv.Append(CPPDEFINES = ["HAVE_AVAHI"]) sources += [ "DNSSD/Avahi/AvahiQuerier.cpp", - "DNSSD/Avahi/AvahiQuery.cpp" + "DNSSD/Avahi/AvahiQuery.cpp", + "DNSSD/Avahi/AvahiResolveHostnameQuery.cpp", + "DNSSD/Avahi/AvahiResolveServiceQuery.cpp", + "DNSSD/Avahi/AvahiRegisterQuery.cpp", + "DNSSD/Avahi/AvahiBrowseQuery.cpp", ] objects = myenv.SwiftenObject(sources) diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp index 98deed1..a2e8280 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp @@ -7,6 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/bind.hpp> + #include "Swiften/LinkLocal/LinkLocalConnector.h" #include "Swiften/LinkLocal/LinkLocalService.h" #include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp index 68a5a86..553e49d 100644 --- a/Swiften/MUC/MUC.cpp +++ b/Swiften/MUC/MUC.cpp @@ -10,6 +10,7 @@ #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" diff --git a/Swiften/MUC/MUCBookmarkManager.cpp b/Swiften/MUC/MUCBookmarkManager.cpp index d0855cd..65e15e3 100644 --- a/Swiften/MUC/MUCBookmarkManager.cpp +++ b/Swiften/MUC/MUCBookmarkManager.cpp @@ -9,6 +9,7 @@ #include <boost/bind.hpp> #include <iostream> +#include <Swiften/Base/foreach.h> #include "Swiften/Queries/IQRouter.h" #include "Swiften/Queries/Requests/GetPrivateStorageRequest.h" #include "Swiften/Queries/Requests/SetPrivateStorageRequest.h" diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp index f7ff8c4..c0faad9 100644 --- a/Swiften/Network/BoostConnection.cpp +++ b/Swiften/Network/BoostConnection.cpp @@ -9,6 +9,8 @@ #include <iostream> #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <boost/asio/placeholders.hpp> +#include <boost/asio/write.hpp> #include <Swiften/Base/Log.h> #include "Swiften/EventLoop/EventLoop.h" diff --git a/Swiften/Network/BoostConnection.h b/Swiften/Network/BoostConnection.h index 506eedf..16e587d 100644 --- a/Swiften/Network/BoostConnection.h +++ b/Swiften/Network/BoostConnection.h @@ -6,7 +6,8 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/ip/tcp.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/thread/mutex.hpp> diff --git a/Swiften/Network/BoostConnectionFactory.h b/Swiften/Network/BoostConnectionFactory.h index ea9d656..bf1bc6c 100644 --- a/Swiften/Network/BoostConnectionFactory.h +++ b/Swiften/Network/BoostConnectionFactory.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> #include "Swiften/Network/ConnectionFactory.h" #include "Swiften/Network/BoostConnection.h" diff --git a/Swiften/Network/BoostConnectionServer.cpp b/Swiften/Network/BoostConnectionServer.cpp index 4c6403c..e5fb8c0 100644 --- a/Swiften/Network/BoostConnectionServer.cpp +++ b/Swiften/Network/BoostConnectionServer.cpp @@ -8,6 +8,7 @@ #include <boost/bind.hpp> #include <boost/system/system_error.hpp> +#include <boost/asio/placeholders.hpp> #include "Swiften/EventLoop/EventLoop.h" diff --git a/Swiften/Network/BoostConnectionServer.h b/Swiften/Network/BoostConnectionServer.h index a45e598..3424720 100644 --- a/Swiften/Network/BoostConnectionServer.h +++ b/Swiften/Network/BoostConnectionServer.h @@ -7,8 +7,9 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/ip/tcp.hpp> #include <boost/enable_shared_from_this.hpp> -#include <boost/asio.hpp> #include "Swiften/Base/boost_bsignals.h" #include "Swiften/Network/BoostConnection.h" diff --git a/Swiften/Network/BoostIOServiceThread.h b/Swiften/Network/BoostIOServiceThread.h index 1f72049..ea04b02 100644 --- a/Swiften/Network/BoostIOServiceThread.h +++ b/Swiften/Network/BoostIOServiceThread.h @@ -6,8 +6,8 @@ #pragma once -#include <boost/asio.hpp> -#include <boost/thread.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/thread/thread.hpp> #include <boost/shared_ptr.hpp> namespace Swift { diff --git a/Swiften/Network/BoostTimer.cpp b/Swiften/Network/BoostTimer.cpp index 12d06c1..27e4b34 100644 --- a/Swiften/Network/BoostTimer.cpp +++ b/Swiften/Network/BoostTimer.cpp @@ -8,6 +8,7 @@ #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/asio.hpp> +#include <boost/bind.hpp> #include "Swiften/EventLoop/EventLoop.h" diff --git a/Swiften/Network/BoostTimer.h b/Swiften/Network/BoostTimer.h index 1139dcf..614698d 100644 --- a/Swiften/Network/BoostTimer.h +++ b/Swiften/Network/BoostTimer.h @@ -6,8 +6,8 @@ #pragma once -#include <boost/asio.hpp> -#include <boost/thread.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/deadline_timer.hpp> #include <boost/enable_shared_from_this.hpp> #include "Swiften/EventLoop/EventOwner.h" diff --git a/Swiften/Network/BoostTimerFactory.h b/Swiften/Network/BoostTimerFactory.h index c0e9ef7..789ba24 100644 --- a/Swiften/Network/BoostTimerFactory.h +++ b/Swiften/Network/BoostTimerFactory.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> #include "Swiften/Network/TimerFactory.h" #include "Swiften/Network/BoostTimer.h" diff --git a/Swiften/Network/CAresDomainNameResolver.h b/Swiften/Network/CAresDomainNameResolver.h index a630b61..f0973b9 100644 --- a/Swiften/Network/CAresDomainNameResolver.h +++ b/Swiften/Network/CAresDomainNameResolver.h @@ -7,7 +7,7 @@ #pragma once #include <ares.h> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include <list> diff --git a/Swiften/Network/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp new file mode 100644 index 0000000..1a38e53 --- /dev/null +++ b/Swiften/Network/ChainedConnector.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/ChainedConnector.h> + +#include <boost/bind.hpp> +#include <typeinfo> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Network/Connector.h> +#include <Swiften/Network/ConnectionFactory.h> + +using namespace Swift; + +ChainedConnector::ChainedConnector( + const std::string& hostname, + DomainNameResolver* resolver, + const std::vector<ConnectionFactory*>& connectionFactories, + TimerFactory* timerFactory) : + hostname(hostname), + resolver(resolver), + connectionFactories(connectionFactories), + timerFactory(timerFactory), + timeoutMilliseconds(0) { +} + +void ChainedConnector::setTimeoutMilliseconds(int milliseconds) { + timeoutMilliseconds = milliseconds; +} + +void ChainedConnector::start() { + SWIFT_LOG(debug) << "Starting queued connector for " << hostname << std::endl; + + connectionFactoryQueue = std::deque<ConnectionFactory*>(connectionFactories.begin(), connectionFactories.end()); + tryNextConnectionFactory(); +} + +void ChainedConnector::stop() { + if (currentConnector) { + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->stop(); + currentConnector.reset(); + } + finish(boost::shared_ptr<Connection>()); +} + +void ChainedConnector::tryNextConnectionFactory() { + assert(!currentConnector); + if (connectionFactoryQueue.empty()) { + SWIFT_LOG(debug) << "No more connection factories" << std::endl; + finish(boost::shared_ptr<Connection>()); + } + else { + ConnectionFactory* connectionFactory = connectionFactoryQueue.front(); + SWIFT_LOG(debug) << "Trying next connection factory: " << typeid(*connectionFactory).name() << std::endl; + connectionFactoryQueue.pop_front(); + currentConnector = Connector::create(hostname, resolver, connectionFactory, timerFactory); + currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); + currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->start(); + } +} + +void ChainedConnector::handleConnectorFinished(boost::shared_ptr<Connection> connection) { + SWIFT_LOG(debug) << "Connector finished" << std::endl; + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector.reset(); + if (connection) { + finish(connection); + } + else { + tryNextConnectionFactory(); + } +} + +void ChainedConnector::finish(boost::shared_ptr<Connection> connection) { + onConnectFinished(connection); +} diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h new file mode 100644 index 0000000..15b17f3 --- /dev/null +++ b/Swiften/Network/ChainedConnector.h @@ -0,0 +1,47 @@ +/* + * 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 <string> +#include <vector> +#include <deque> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class Connection; + class Connector; + class ConnectionFactory; + class TimerFactory; + class DomainNameResolver; + + class ChainedConnector { + public: + ChainedConnector(const std::string& hostname, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); + + void setTimeoutMilliseconds(int milliseconds); + void start(); + void stop(); + + boost::signal<void (boost::shared_ptr<Connection>)> onConnectFinished; + + private: + void finish(boost::shared_ptr<Connection> connection); + void tryNextConnectionFactory(); + void handleConnectorFinished(boost::shared_ptr<Connection>); + + private: + std::string hostname; + DomainNameResolver* resolver; + std::vector<ConnectionFactory*> connectionFactories; + TimerFactory* timerFactory; + int timeoutMilliseconds; + std::deque<ConnectionFactory*> connectionFactoryQueue; + boost::shared_ptr<Connector> currentConnector; + }; +}; diff --git a/Swiften/Network/Connection.cpp b/Swiften/Network/Connection.cpp new file mode 100644 index 0000000..9bb29e1 --- /dev/null +++ b/Swiften/Network/Connection.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/Connection.h> + +using namespace Swift; + +Connection::Connection() { +} + +Connection::~Connection() { +} diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h index 529dd82..74d25aa 100644 --- a/Swiften/Network/Connection.h +++ b/Swiften/Network/Connection.h @@ -7,13 +7,13 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Base/ByteArray.h" -#include <string> -#include "Swiften/Network/HostAddressPort.h" +#include <Swiften/Base/ByteArray.h> namespace Swift { + class HostAddressPort; + class Connection { public: typedef boost::shared_ptr<Connection> ref; @@ -23,8 +23,8 @@ namespace Swift { WriteError }; - Connection() {} - virtual ~Connection() {} + Connection(); + virtual ~Connection(); virtual void listen() = 0; virtual void connect(const HostAddressPort& address) = 0; diff --git a/Swiften/Network/DummyConnection.cpp b/Swiften/Network/DummyConnection.cpp new file mode 100644 index 0000000..ffc6dc2 --- /dev/null +++ b/Swiften/Network/DummyConnection.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/DummyConnection.h> + +#include <boost/bind.hpp> +#include <cassert> + +namespace Swift { + +DummyConnection::DummyConnection(EventLoop* eventLoop) : eventLoop(eventLoop) { +} + +void DummyConnection::receive(const ByteArray& data) { + eventLoop->postEvent(boost::bind(boost::ref(onDataRead), ByteArray(data)), shared_from_this()); +} + +void DummyConnection::listen() { + assert(false); +} + +void DummyConnection::connect(const HostAddressPort&) { + assert(false); +} + + +} diff --git a/Swiften/Network/DummyConnection.h b/Swiften/Network/DummyConnection.h index 6b426b1..e8cc48b 100644 --- a/Swiften/Network/DummyConnection.h +++ b/Swiften/Network/DummyConnection.h @@ -6,26 +6,20 @@ #pragma once -#include <cassert> -#include <boost/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include "Swiften/Network/Connection.h" +#include "Swiften/Network/HostAddressPort.h" #include "Swiften/EventLoop/EventLoop.h" #include "Swiften/EventLoop/EventOwner.h" namespace Swift { class DummyConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<DummyConnection> { public: - DummyConnection(EventLoop* eventLoop) : eventLoop(eventLoop) {} + DummyConnection(EventLoop* eventLoop); - void listen() { - assert(false); - } - - void connect(const HostAddressPort&) { - assert(false); - } + void listen(); + void connect(const HostAddressPort&); void disconnect() { //assert(false); @@ -36,9 +30,7 @@ namespace Swift { onDataSent(data); } - void receive(const ByteArray& data) { - eventLoop->postEvent(boost::bind(boost::ref(onDataRead), ByteArray(data)), shared_from_this()); - } + void receive(const ByteArray& data); HostAddressPort getLocalAddress() const { return localAddress; diff --git a/Swiften/Network/EnvironmentProxyProvider.cpp b/Swiften/Network/EnvironmentProxyProvider.cpp new file mode 100644 index 0000000..b3bd0f6 --- /dev/null +++ b/Swiften/Network/EnvironmentProxyProvider.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include "Swiften/Base/Log.h" +#include "Swiften/Network/EnvironmentProxyProvider.h" + +namespace Swift { + +EnvironmentProxyProvider::EnvironmentProxyProvider() { + socksProxy = getFromEnv("all_proxy", "socks"); + httpProxy = getFromEnv("http_proxy", "http"); + SWIFT_LOG(debug) << "Environment: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; +} + +HostAddressPort EnvironmentProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort EnvironmentProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort EnvironmentProxyProvider::getFromEnv(const char* envVarName, std::string proxyProtocol) { + char* envVar = NULL; + std::string address; + int port = 0; + + envVar = getenv(envVarName); + + proxyProtocol += "://"; + address = envVar != NULL ? envVar : "0.0.0.0"; + if(envVar != NULL && address.compare(0, proxyProtocol.length(), proxyProtocol) == 0) { + address = address.substr(proxyProtocol.length(), address.length()); + port = atoi(address.substr(address.find(':') + 1, address.length()).c_str()); + address = address.substr(0, address.find(':')); + } + + return HostAddressPort(HostAddress(address), port); +} + +} diff --git a/Swiften/Network/EnvironmentProxyProvider.h b/Swiften/Network/EnvironmentProxyProvider.h new file mode 100644 index 0000000..1743269 --- /dev/null +++ b/Swiften/Network/EnvironmentProxyProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Network/ProxyProvider.h" + +namespace Swift { + class EnvironmentProxyProvider : public ProxyProvider { + public: + EnvironmentProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getFromEnv(const char* envVarName, std::string proxyProtocol); + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} + + diff --git a/Swiften/Network/FakeConnection.cpp b/Swiften/Network/FakeConnection.cpp new file mode 100644 index 0000000..be5555c --- /dev/null +++ b/Swiften/Network/FakeConnection.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/FakeConnection.h> + +#include <boost/bind.hpp> + +namespace Swift { + +FakeConnection::FakeConnection(EventLoop* eventLoop) : eventLoop(eventLoop), state(Initial), delayConnect(false) { +} + +FakeConnection::~FakeConnection() { +} + +void FakeConnection::listen() { + assert(false); +} + +void FakeConnection::setError(const Error& e) { + error = boost::optional<Error>(e); + state = DisconnectedWithError; + if (connectedTo) { + eventLoop->postEvent( + boost::bind(boost::ref(onDisconnected), error), + shared_from_this()); + } +} + +void FakeConnection::connect(const HostAddressPort& address) { + if (delayConnect) { + state = Connecting; + } + else { + if (!error) { + connectedTo = address; + state = Connected; + } + else { + state = DisconnectedWithError; + } + eventLoop->postEvent( + boost::bind(boost::ref(onConnectFinished), error), + shared_from_this()); + } +} + +void FakeConnection::disconnect() { + if (!error) { + state = Disconnected; + } + else { + state = DisconnectedWithError; + } + connectedTo.reset(); + eventLoop->postEvent( + boost::bind(boost::ref(onDisconnected), error), + shared_from_this()); +} + +} diff --git a/Swiften/Network/FakeConnection.h b/Swiften/Network/FakeConnection.h index 4e2e960..693dabf 100644 --- a/Swiften/Network/FakeConnection.h +++ b/Swiften/Network/FakeConnection.h @@ -7,7 +7,6 @@ #pragma once #include <boost/optional.hpp> -#include <boost/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include <vector> @@ -30,56 +29,17 @@ namespace Swift { DisconnectedWithError }; - FakeConnection(EventLoop* eventLoop) : eventLoop(eventLoop), state(Initial), delayConnect(false) {} - - virtual void listen() { - assert(false); - } + FakeConnection(EventLoop* eventLoop); + ~FakeConnection(); + virtual void listen(); virtual HostAddressPort getLocalAddress() const { return HostAddressPort(); } - void setError(const Error& e) { - error = boost::optional<Error>(e); - state = DisconnectedWithError; - if (connectedTo) { - eventLoop->postEvent( - boost::bind(boost::ref(onDisconnected), error), - shared_from_this()); - } - } - - virtual void connect(const HostAddressPort& address) { - if (delayConnect) { - state = Connecting; - } - else { - if (!error) { - connectedTo = address; - state = Connected; - } - else { - state = DisconnectedWithError; - } - eventLoop->postEvent( - boost::bind(boost::ref(onConnectFinished), error), - shared_from_this()); - } - } - - virtual void disconnect() { - if (!error) { - state = Disconnected; - } - else { - state = DisconnectedWithError; - } - connectedTo.reset(); - eventLoop->postEvent( - boost::bind(boost::ref(onDisconnected), error), - shared_from_this()); - } + void setError(const Error& e); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); virtual void write(const ByteArray& data) { dataWritten.push_back(data); diff --git a/Swiften/Network/GConfProxyProvider.cpp b/Swiften/Network/GConfProxyProvider.cpp new file mode 100644 index 0000000..687bf77 --- /dev/null +++ b/Swiften/Network/GConfProxyProvider.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include <gconf/gconf-client.h> + +#include "Swiften/Base/Log.h" +#include "Swiften/Network/GConfProxyProvider.h" + +namespace Swift { + +GConfProxyProvider::GConfProxyProvider() { + socksProxy = getFromGConf("/system/proxy/socks_host", "/system/proxy/socks_port"); + httpProxy = getFromGConf("/system/http_proxy/host", "/system/http_proxy/port"); + SWIFT_LOG(debug) << "GConf: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; +} + +HostAddressPort GConfProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort GConfProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort GConfProxyProvider::getFromGConf(const char* gcHost, const char* gcPort) { + std::string address; + int port = 0; + gchar* str; + + GConfClient* client = gconf_client_get_default(); + + str = gconf_client_get_string(client, gcHost, NULL); + port = static_cast<int> (gconf_client_get_int(client, gcPort, NULL)); + + if(str) { + address = static_cast<char*> (str); + g_free(str); + } + + g_object_unref(client); + return HostAddressPort(HostAddress(address), port); +} + +} diff --git a/Swiften/Network/GConfProxyProvider.h b/Swiften/Network/GConfProxyProvider.h new file mode 100644 index 0000000..15586ad --- /dev/null +++ b/Swiften/Network/GConfProxyProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Network/ProxyProvider.h" + +namespace Swift { + class GConfProxyProvider : public ProxyProvider { + public: + GConfProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getFromGConf(const char* gcHost, const char* gcPort); + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} + + diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp new file mode 100644 index 0000000..51130e5 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/HTTPConnectProxiedConnection.h" + +#include <iostream> +#include <boost/bind.hpp> +#include <boost/thread.hpp> +#include <boost/lexical_cast.hpp> + +#include "Swiften/Base/Log.h" +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/Network/HostAddressPort.h" +#include <Swiften/Network/ConnectionFactory.h> + +using namespace Swift; + +HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy) : connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) { + connected_ = false; +} + +HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { + 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::connect(const HostAddressPort& server) { + server_ = server; + connection_ = connectionFactory_->createConnection(); + connection_->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + connection_->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); + connection_->connect(proxy_); +} + +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 ByteArray& data) { + connection_->write(data); +} + +void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) { + connection_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + if (!error) { + std::stringstream connect; + connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n\r\n"; + connection_->write(ByteArray(connect.str())); + } + else { + onConnectFinished(true); + } +} + +void HTTPConnectProxiedConnection::handleDataRead(const ByteArray& data) { + if (!connected_) { + SWIFT_LOG(debug) << data.toString() << std::endl; + std::vector<std::string> tmp = String::split(data.toString(), ' '); + if(tmp.size() > 1) { + int status = boost::lexical_cast<int> (tmp[1].c_str()); + SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl; + if (status / 100 == 2) { // all 2XX states are OK + connected_ = true; + onConnectFinished(false); + return; + } + SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << data.toString() << std::endl; + } + disconnect(); + onConnectFinished(true); + } + else { + onDataRead(data); + } +} + +HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const { + return connection_->getLocalAddress(); +} diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h new file mode 100644 index 0000000..930f5e1 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#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; + } +} + +namespace Swift { + class ConnectionFactory; + + class HTTPConnectProxiedConnection : public Connection, public boost::enable_shared_from_this<HTTPConnectProxiedConnection> { + public: + typedef boost::shared_ptr<HTTPConnectProxiedConnection> ref; + + ~HTTPConnectProxiedConnection(); + + static ref create(ConnectionFactory* connectionFactory, HostAddressPort proxy) { + return ref(new HTTPConnectProxiedConnection(connectionFactory, proxy)); + } + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const ByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + private: + HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy); + + void handleConnectionConnectFinished(bool error); + void handleDataRead(const ByteArray& data); + void handleDisconnected(const boost::optional<Error>& error); + + private: + bool connected_; + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + HostAddressPort server_; + boost::shared_ptr<Connection> connection_; + }; +} diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp new file mode 100644 index 0000000..050b0c0 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/HTTPConnectProxiedConnectionFactory.h" + +#include "Swiften/Network/HTTPConnectProxiedConnection.h" + +namespace Swift { + +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy) { +} + +boost::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() { + return HTTPConnectProxiedConnection::create(connectionFactory_, proxy_); +} + +} diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h new file mode 100644 index 0000000..2b0c8d5 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Network/ConnectionFactory.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace Swift { + class HTTPConnectProxiedConnectionFactory : public ConnectionFactory { + public: + HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + + virtual boost::shared_ptr<Connection> createConnection(); + + private: + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + }; +} diff --git a/Swiften/Network/HostAddress.cpp b/Swiften/Network/HostAddress.cpp index 7acd407..f734329 100644 --- a/Swiften/Network/HostAddress.cpp +++ b/Swiften/Network/HostAddress.cpp @@ -24,7 +24,7 @@ HostAddress::HostAddress(const std::string& address) { try { address_ = boost::asio::ip::address::from_string(address); } - catch (const std::exception& t) { + catch (const std::exception&) { } } @@ -57,4 +57,8 @@ bool HostAddress::isValid() const { return !(address_.is_v4() && address_.to_v4().to_ulong() == 0); } +boost::asio::ip::address HostAddress::getRawAddress() const { + return address_; +} + } diff --git a/Swiften/Network/HostAddress.h b/Swiften/Network/HostAddress.h index 34ccd24..0b3bdda 100644 --- a/Swiften/Network/HostAddress.h +++ b/Swiften/Network/HostAddress.h @@ -3,16 +3,12 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ - #pragma once #include <string> -#include <vector> -#include <boost/asio.hpp> +#include <boost/asio/ip/address.hpp> namespace Swift { - - class HostAddress { public: HostAddress(); @@ -21,6 +17,7 @@ namespace Swift { HostAddress(const boost::asio::ip::address& address); std::string toString() const; + boost::asio::ip::address getRawAddress() const; bool operator==(const HostAddress& o) const { return address_ == o.address_; diff --git a/Swiften/Network/HostAddressPort.cpp b/Swiften/Network/HostAddressPort.cpp new file mode 100644 index 0000000..e2e6012 --- /dev/null +++ b/Swiften/Network/HostAddressPort.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/HostAddressPort.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +HostAddressPort::HostAddressPort(const HostAddress& address, int port) : address_(address), port_(port) { +} + +HostAddressPort::HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint) { + address_ = HostAddress(endpoint.address()); + port_ = endpoint.port(); +} + +std::string HostAddressPort::toString() const { + return getAddress().toString() + ":" + boost::lexical_cast<std::string>(getPort()); +} diff --git a/Swiften/Network/HostAddressPort.h b/Swiften/Network/HostAddressPort.h index 6883380..23a81b8 100644 --- a/Swiften/Network/HostAddressPort.h +++ b/Swiften/Network/HostAddressPort.h @@ -6,21 +6,15 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/ip/tcp.hpp> #include "Swiften/Network/HostAddress.h" namespace Swift { class HostAddressPort { public: - HostAddressPort(const HostAddress& address = HostAddress(), int port = -1) : address_(address), port_(port) { - } - - HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint) { - address_ = HostAddress(endpoint.address()); - port_ = endpoint.port(); - } - + HostAddressPort(const HostAddress& address = HostAddress(), int port = -1); + HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint); const HostAddress& getAddress() const { return address_; @@ -37,6 +31,8 @@ namespace Swift { bool isValid() const { return address_.isValid() && port_ > 0; } + + std::string toString() const; private: HostAddress address_; diff --git a/Swiften/Network/MacOSXProxyProvider.cpp b/Swiften/Network/MacOSXProxyProvider.cpp new file mode 100644 index 0000000..dd44eff --- /dev/null +++ b/Swiften/Network/MacOSXProxyProvider.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Base/Platform.h> +#include <Swiften/Network/MacOSXProxyProvider.h> + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <utility> + +#ifndef SWIFTEN_PLATFORM_IPHONE +#include <SystemConfiguration/SystemConfiguration.h> +#endif + +using namespace Swift; + +#ifndef SWIFTEN_PLATFORM_IPHONE +static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabledKey, CFStringRef hostKey, CFStringRef portKey) { + CFNumberRef numberValue = NULL; + HostAddressPort ret = HostAddressPort(HostAddress(), 0); + + if(CFDictionaryGetValueIfPresent(dict, reinterpret_cast<const void*> (enabledKey), reinterpret_cast<const void**> (&numberValue)) == true) { + const int i = 0; + CFNumberRef zero = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i); + CFComparisonResult result = CFNumberCompare(numberValue, zero, NULL); + CFRelease(numberValue); + + if(result != kCFCompareEqualTo) { + int port = 0; + std::string host = ""; + + try { + CFNumberRef numberValue = reinterpret_cast<CFNumberRef> (CFDictionaryGetValue(dict, portKey)); + if(numberValue != NULL) { + CFNumberGetValue(numberValue, kCFNumberIntType, &port); + CFRelease(numberValue); + } + + CFStringRef stringValue = reinterpret_cast<CFStringRef> (CFDictionaryGetValue(dict, hostKey)); + if(stringValue != NULL) { + std::vector<char> buffer; + // length must be +1 for the ending zero; and the Docu of CFStringGetCString tells it like + // if the string is toby the length must be at least 5. + CFIndex length = CFStringGetLength(stringValue) + 1; + buffer.resize(length); + if(CFStringGetCString(stringValue, &buffer[0], length, kCFStringEncodingMacRoman)) { + for(std::vector<char>::iterator iter = buffer.begin(); iter != buffer.end(); iter++) { + host += *iter; + } + } + CFRelease(stringValue); + } + } + catch(...) { + std::cerr << "Exception caught ... " << std::endl; + } + + if(host != "" && port != 0) { + ret = HostAddressPort(HostAddress(host), port); + } + } + } + return ret; +} +#endif +namespace Swift { + +MacOSXProxyProvider::MacOSXProxyProvider() { +} + +HostAddressPort MacOSXProxyProvider::getHTTPConnectProxy() const { + HostAddressPort result; +#ifndef SWIFTEN_PLATFORM_IPHONE + CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL); + if(proxies != NULL) { + result = getFromDictionary(proxies, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort); + } +#endif + return result; +} + +HostAddressPort MacOSXProxyProvider::getSOCKS5Proxy() const { + HostAddressPort result; +#ifndef SWIFTEN_PLATFORM_IPHONE + CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL); + if(proxies != NULL) { + result = getFromDictionary(proxies, kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort); + } +#endif + return result; +} + +} diff --git a/Swiften/Network/MacOSXProxyProvider.h b/Swiften/Network/MacOSXProxyProvider.h new file mode 100644 index 0000000..5e7ff8a --- /dev/null +++ b/Swiften/Network/MacOSXProxyProvider.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include "Swiften/Network/ProxyProvider.h" +#include <CoreFoundation/CoreFoundation.h> + +namespace Swift { + class MacOSXProxyProvider : public ProxyProvider { + public: + MacOSXProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + }; +} diff --git a/Swiften/Network/NullProxyProvider.cpp b/Swiften/Network/NullProxyProvider.cpp new file mode 100644 index 0000000..3b9d94d --- /dev/null +++ b/Swiften/Network/NullProxyProvider.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/NullProxyProvider.h> + +using namespace Swift; + +NullProxyProvider::NullProxyProvider() { +} + +HostAddressPort NullProxyProvider::getHTTPConnectProxy() const { + return HostAddressPort(); +} + +HostAddressPort NullProxyProvider::getSOCKS5Proxy() const { + return HostAddressPort(); +} diff --git a/Swiften/Network/NullProxyProvider.h b/Swiften/Network/NullProxyProvider.h new file mode 100644 index 0000000..544bea2 --- /dev/null +++ b/Swiften/Network/NullProxyProvider.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/ProxyProvider.h> + +namespace Swift { + class NullProxyProvider : public ProxyProvider { + public: + NullProxyProvider(); + + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + }; +} diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.cpp b/Swiften/Network/PlatformDomainNameAddressQuery.cpp index 1832255..ec7e663 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.cpp +++ b/Swiften/Network/PlatformDomainNameAddressQuery.cpp @@ -6,6 +6,8 @@ #include <Swiften/Network/PlatformDomainNameAddressQuery.h> +#include <boost/asio/ip/tcp.hpp> + #include <Swiften/Network/PlatformDomainNameResolver.h> #include <Swiften/EventLoop/EventLoop.h> diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.h b/Swiften/Network/PlatformDomainNameAddressQuery.h index c2854ac..e1dc05f 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.h +++ b/Swiften/Network/PlatformDomainNameAddressQuery.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> #include <boost/enable_shared_from_this.hpp> #include <Swiften/Network/DomainNameAddressQuery.h> diff --git a/Swiften/Network/PlatformDomainNameResolver.h b/Swiften/Network/PlatformDomainNameResolver.h index e681331..295ecc5 100644 --- a/Swiften/Network/PlatformDomainNameResolver.h +++ b/Swiften/Network/PlatformDomainNameResolver.h @@ -7,7 +7,7 @@ #pragma once #include <deque> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> diff --git a/Swiften/Network/PlatformProxyProvider.h b/Swiften/Network/PlatformProxyProvider.h new file mode 100644 index 0000000..13b15d2 --- /dev/null +++ b/Swiften/Network/PlatformProxyProvider.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Base/Platform.h" + +#if defined(SWIFTEN_PLATFORM_MACOSX) +#include "Swiften/Network/MacOSXProxyProvider.h" +namespace Swift { + typedef MacOSXProxyProvider PlatformProxyProvider; +} +#elif defined(SWIFTEN_PLATFORM_WIN32) +#include "Swiften/Network/WindowsProxyProvider.h" +namespace Swift { + typedef WindowsProxyProvider PlatformProxyProvider; +} +#else +#include "Swiften/Network/UnixProxyProvider.h" +namespace Swift { + typedef UnixProxyProvider PlatformProxyProvider; +} +#endif diff --git a/Swiften/Network/ProxyProvider.cpp b/Swiften/Network/ProxyProvider.cpp new file mode 100644 index 0000000..fe235b1 --- /dev/null +++ b/Swiften/Network/ProxyProvider.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "ProxyProvider.h" + +namespace Swift { + +ProxyProvider::ProxyProvider() +{ +} + +ProxyProvider::~ProxyProvider() +{ +} + +} diff --git a/Swiften/Network/ProxyProvider.h b/Swiften/Network/ProxyProvider.h new file mode 100644 index 0000000..05bb5a7 --- /dev/null +++ b/Swiften/Network/ProxyProvider.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include <map> + +#include "Swiften/Base/Log.h" +#include "Swiften/Network/HostAddressPort.h" +#include "Swiften/Base/String.h" + +namespace Swift { + class ProxyProvider { + public: + ProxyProvider(); + virtual ~ProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const = 0; + virtual HostAddressPort getSOCKS5Proxy() const = 0; + }; +} + diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index fa186fa..183d09c 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -6,13 +6,21 @@ if myenv.get("HAVE_CARES", False) : myenv.MergeFlags(myenv.get("CARES_FLAGS", {})) sourceList = [ + "HTTPConnectProxiedConnection.cpp", + "HTTPConnectProxiedConnectionFactory.cpp", + "SOCKS5ProxiedConnection.cpp", + "SOCKS5ProxiedConnectionFactory.cpp", "BoostConnection.cpp", "BoostConnectionFactory.cpp", "BoostConnectionServer.cpp", "BoostIOServiceThread.cpp", "ConnectionFactory.cpp", "ConnectionServer.cpp", + "DummyConnection.cpp", + "FakeConnection.cpp", + "ChainedConnector.cpp", "Connector.cpp", + "Connection.cpp", "TimerFactory.cpp", "DummyTimerFactory.cpp", "BoostTimerFactory.cpp", @@ -24,13 +32,30 @@ sourceList = [ "PlatformDomainNameAddressQuery.cpp", "StaticDomainNameResolver.cpp", "HostAddress.cpp", + "HostAddressPort.cpp", "NetworkFactories.cpp", "BoostNetworkFactories.cpp", "Timer.cpp", - "BoostTimer.cpp"] + "BoostTimer.cpp", + "ProxyProvider.cpp", + "NullProxyProvider.cpp" + ] + if myenv.get("HAVE_CARES", False) : sourceList.append("CAresDomainNameResolver.cpp") +if myenv["PLATFORM"] == "darwin" : + myenv.Append(FRAMEWORKS = ["CoreServices", "SystemConfiguration"]) + sourceList += [ "MacOSXProxyProvider.cpp" ] +elif myenv["PLATFORM"] == "win32" : + sourceList += [ "WindowsProxyProvider.cpp" ] +else : + sourceList += [ "UnixProxyProvider.cpp" ] + sourceList += [ "EnvironmentProxyProvider.cpp" ] + if myenv.get("HAVE_GCONF", 0) : + myenv.Append(CPPDEFINES = "HAVE_GCONF") + myenv.MergeFlags(myenv["GCONF_FLAGS"]) + sourceList += [ "GConfProxyProvider.cpp" ] objects = myenv.SwiftenObject(sourceList) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp new file mode 100644 index 0000000..0232ede --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/SOCKS5ProxiedConnection.h" + +#include <iostream> +#include <boost/bind.hpp> +#include <boost/thread.hpp> + +#include <Swiften/Network/ConnectionFactory.h> +#include "Swiften/Base/Log.h" +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/Network/HostAddressPort.h" + +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); +} + +void SOCKS5ProxiedConnection::write(const ByteArray& 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; + + proxyState_ = ProxyAuthenticating; + ByteArray socksConnect; + socksConnect += 0x05; // VER = SOCKS5 = 0x05 + socksConnect += 0x01; // Number of authentication methods after this byte. + socksConnect += 0x00; // 0x00 == no authentication + // buffer.push_back(0x01); // 0x01 == GSSAPI + // buffer.push_back(0x02); // 0x02 == Username/Password + // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928) + connection_->write(socksConnect); + } + else { + onConnectFinished(true); + } +} + +void SOCKS5ProxiedConnection::handleDataRead(const ByteArray& data) { + ByteArray socksConnect; + boost::asio::ip::address rawAddress = server_.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; + unsigned char choosenMethod = static_cast<unsigned char> (data[1]); + if (data[0] == 0x05 && choosenMethod != 0xFF) { + switch(choosenMethod) { // use the correct Method + case 0x00: + try { + proxyState_ = ProxyConnecting; + socksConnect += 0x05; // VER = SOCKS5 = 0x05 + socksConnect += 0x01; // Construct a TCP connection. (CMD) + socksConnect += 0x00; // reserved. + socksConnect += rawAddress.is_v4() ? 0x01 : 0x04; // IPv4 == 0x01, Hostname == 0x02, IPv6 == 0x04. (ATYP) + size_t size = rawAddress.is_v4() ? rawAddress.to_v4().to_bytes().size() : rawAddress.to_v6().to_bytes().size(); + for (size_t s = 0; s < size; s++) { + unsigned char uc; + if(rawAddress.is_v4()) { + uc = rawAddress.to_v4().to_bytes()[s]; // the address. + } + else { + uc = rawAddress.to_v6().to_bytes()[s]; // the address. + } + socksConnect += static_cast<char> (uc); + + } + socksConnect += static_cast<unsigned char> ((server_.getPort() >> 8) & 0xFF); // highbyte of the port. + socksConnect += static_cast<unsigned char> (server_.getPort() & 0xFF); // lowbyte of the port. + connection_->write(socksConnect); + return; + } + catch(...) { + std::cerr << "exception caught" << std::endl; + } + connection_->write(socksConnect); + break; + default: + onConnectFinished(true); + break; + } + return; + } + } + else if (proxyState_ == ProxyConnecting) { + SWIFT_LOG(debug) << "Connect response received, check if successfully." << std::endl; + SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> (data[1]) << std::dec << std::endl; + /* + + data.at(1) can be one of the following: + 0x00 succeeded + 0x01 general SOCKS server failure + 0x02 connection not allowed by ruleset + 0x03 Network unreachable + 0x04 Host unreachable + 0x05 Connection refused + 0x06 TTL expired + 0x07 Command not supported (CMD) + 0x08 Address type not supported (ATYP) + 0x09 bis 0xFF unassigned + */ + if (data[0] == 0x05 && data[1] == 0x0) { + SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; + connected_ = true; + onConnectFinished(false); + return; + } + else { + std::cerr << "SOCKS Proxy returned an error: " << std::hex << data[1] << std::endl; + } + 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 new file mode 100644 index 0000000..779bfa1 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnection.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#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; + } +} + +namespace Swift { + class ConnectionFactory; + + class SOCKS5ProxiedConnection : public Connection, public boost::enable_shared_from_this<SOCKS5ProxiedConnection> { + public: + typedef boost::shared_ptr<SOCKS5ProxiedConnection> ref; + + ~SOCKS5ProxiedConnection(); + + static ref create(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) { + return ref(new SOCKS5ProxiedConnection(connectionFactory, proxy)); + } + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const ByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + + private: + SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + + void handleConnectionConnectFinished(bool error); + void handleDataRead(const ByteArray& data); + void handleDisconnected(const boost::optional<Error>& error); + + private: + enum { + ProxyAuthenticating = 0, + 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 new file mode 100644 index 0000000..ab75644 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/SOCKS5ProxiedConnectionFactory.h" + +#include "Swiften/Network/SOCKS5ProxiedConnection.h" + +namespace Swift { + +SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy) { +} + +boost::shared_ptr<Connection> SOCKS5ProxiedConnectionFactory::createConnection() { + return SOCKS5ProxiedConnection::create(connectionFactory_, proxy_); +} + +} diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h new file mode 100644 index 0000000..8f310c5 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Network/ConnectionFactory.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace Swift { + class SOCKS5ProxiedConnectionFactory : public ConnectionFactory { + public: + SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + + virtual boost::shared_ptr<Connection> createConnection(); + + private: + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + }; +} diff --git a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp new file mode 100644 index 0000000..9c4c99d --- /dev/null +++ b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp @@ -0,0 +1,161 @@ +/* + * 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/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Network/ChainedConnector.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swiften/EventLoop/DummyEventLoop.h> + +using namespace Swift; + +class ChainedConnectorTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ChainedConnectorTest); + CPPUNIT_TEST(testConnect_FirstConnectorSucceeds); + CPPUNIT_TEST(testConnect_SecondConnectorSucceeds); + CPPUNIT_TEST(testConnect_NoConnectorSucceeds); + CPPUNIT_TEST(testStop); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + host = HostAddressPort(HostAddress("1.1.1.1"), 1234); + eventLoop = new DummyEventLoop(); + resolver = new StaticDomainNameResolver(eventLoop); + resolver->addXMPPClientService("foo.com", host); + connectionFactory1 = new MockConnectionFactory(eventLoop, 1); + connectionFactory2 = new MockConnectionFactory(eventLoop, 2); + timerFactory = new DummyTimerFactory(); + } + + void tearDown() { + delete timerFactory; + delete connectionFactory2; + delete connectionFactory1; + delete resolver; + delete eventLoop; + } + + void testConnect_FirstConnectorSucceeds() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = true; + connectionFactory2->connects = false; + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT_EQUAL(1, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + } + + void testConnect_SecondConnectorSucceeds() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = false; + connectionFactory2->connects = true; + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT_EQUAL(2, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + } + + void testConnect_NoConnectorSucceeds() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = false; + connectionFactory2->connects = false; + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + } + + void testStop() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = true; + connectionFactory2->connects = false; + + testling->start(); + testling->stop(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + } + + private: + boost::shared_ptr<ChainedConnector> createConnector() { + std::vector<ConnectionFactory*> factories; + factories.push_back(connectionFactory1); + factories.push_back(connectionFactory2); + boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", resolver, factories, timerFactory); + connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1)); + return connector; + } + + void handleConnectorFinished(boost::shared_ptr<Connection> connection) { + boost::shared_ptr<MockConnection> c(boost::dynamic_pointer_cast<MockConnection>(connection)); + if (connection) { + assert(c); + } + connections.push_back(c); + } + + struct MockConnection : public Connection { + public: + MockConnection(bool connects, int id, EventLoop* eventLoop) : connects(connects), id(id), eventLoop(eventLoop) { + } + + void listen() { assert(false); } + void connect(const HostAddressPort&) { + eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), !connects)); + } + + HostAddressPort getLocalAddress() const { return HostAddressPort(); } + void disconnect() { assert(false); } + void write(const ByteArray&) { assert(false); } + + bool connects; + int id; + EventLoop* eventLoop; + }; + + struct MockConnectionFactory : public ConnectionFactory { + MockConnectionFactory(EventLoop* eventLoop, int id) : eventLoop(eventLoop), connects(true), id(id) { + } + + boost::shared_ptr<Connection> createConnection() { + return boost::make_shared<MockConnection>(connects, id, eventLoop); + } + + EventLoop* eventLoop; + bool connects; + int id; + }; + + private: + HostAddressPort host; + DummyEventLoop* eventLoop; + StaticDomainNameResolver* resolver; + MockConnectionFactory* connectionFactory1; + MockConnectionFactory* connectionFactory2; + DummyTimerFactory* timerFactory; + std::vector< boost::shared_ptr<MockConnection> > connections; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ChainedConnectorTest); diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp new file mode 100644 index 0000000..6c4c89c --- /dev/null +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -0,0 +1,244 @@ +/* + * 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/optional.hpp> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HTTPConnectProxiedConnection.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/EventLoop/DummyEventLoop.h> + +using namespace Swift; + +class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(HTTPConnectProxiedConnectionTest); + CPPUNIT_TEST(testConnect_CreatesConnectionToProxy); + CPPUNIT_TEST(testConnect_SendsConnectRequest); + CPPUNIT_TEST(testConnect_ReceiveConnectResponse); + CPPUNIT_TEST(testConnect_ReceiveMalformedConnectResponse); + CPPUNIT_TEST(testConnect_ReceiveErrorConnectResponse); + CPPUNIT_TEST(testConnect_ReceiveDataAfterConnect); + CPPUNIT_TEST(testWrite_AfterConnect); + CPPUNIT_TEST(testDisconnect_AfterConnectRequest); + CPPUNIT_TEST(testDisconnect_AfterConnect); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + proxyHost = HostAddressPort(HostAddress("1.1.1.1"), 1234); + host = HostAddressPort(HostAddress("2.2.2.2"), 2345); + eventLoop = new DummyEventLoop(); + connectionFactory = new MockConnectionFactory(eventLoop); + connectFinished = false; + disconnected = false; + } + + void tearDown() { + delete connectionFactory; + delete eventLoop; + } + + void testConnect_CreatesConnectionToProxy() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + + testling->connect(host); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connectionFactory->connections.size())); + CPPUNIT_ASSERT(connectionFactory->connections[0]->hostAddressPort); + CPPUNIT_ASSERT(proxyHost == *connectionFactory->connections[0]->hostAddressPort); + CPPUNIT_ASSERT(!connectFinished); + } + + void testConnect_SendsConnectRequest() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(ByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n\r\n"), connectionFactory->connections[0]->dataWritten); + } + + void testConnect_ReceiveConnectResponse() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(connectFinished); + CPPUNIT_ASSERT(!connectFinishedWithError); + CPPUNIT_ASSERT(dataRead.isEmpty()); + } + + void testConnect_ReceiveMalformedConnectResponse() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(ByteArray("FLOOP")); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(connectFinished); + CPPUNIT_ASSERT(connectFinishedWithError); + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + } + + void testConnect_ReceiveErrorConnectResponse() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 401 Unauthorized\r\n\r\n")); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(connectFinished); + CPPUNIT_ASSERT(connectFinishedWithError); + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + } + + void testConnect_ReceiveDataAfterConnect() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(ByteArray("abcdef")); + + CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), dataRead); + } + + void testWrite_AfterConnect() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + connectionFactory->connections[0]->dataWritten.clear(); + + testling->write(ByteArray("abcdef")); + + CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), connectionFactory->connections[0]->dataWritten); + } + + void testDisconnect_AfterConnectRequest() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + testling->disconnect(); + + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + CPPUNIT_ASSERT(disconnected); + CPPUNIT_ASSERT(!disconnectedError); + } + + void testDisconnect_AfterConnect() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + + testling->disconnect(); + + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + CPPUNIT_ASSERT(disconnected); + CPPUNIT_ASSERT(!disconnectedError); + } + + private: + HTTPConnectProxiedConnection::ref createTestling() { + boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(connectionFactory, proxyHost); + c->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleConnectFinished, this, _1)); + c->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDisconnected, this, _1)); + c->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDataRead, this, _1)); + return c; + } + + void handleConnectFinished(bool error) { + connectFinished = true; + connectFinishedWithError = error; + } + + void handleDisconnected(const boost::optional<Connection::Error>& e) { + disconnected = true; + disconnectedError = e; + } + + void handleDataRead(const ByteArray& d) { + dataRead += d; + } + + struct MockConnection : public Connection { + public: + MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) { + } + + void listen() { assert(false); } + + void connect(const HostAddressPort& address) { + hostAddressPort = address; + bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end(); + eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail)); + } + + HostAddressPort getLocalAddress() const { return HostAddressPort(); } + + void disconnect() { + disconnected = true; + onDisconnected(boost::optional<Connection::Error>()); + } + + void write(const ByteArray& d) { + dataWritten += d; + } + + EventLoop* eventLoop; + boost::optional<HostAddressPort> hostAddressPort; + std::vector<HostAddressPort> failingPorts; + ByteArray dataWritten; + bool disconnected; + }; + + struct MockConnectionFactory : public ConnectionFactory { + MockConnectionFactory(EventLoop* eventLoop) : eventLoop(eventLoop) { + } + + boost::shared_ptr<Connection> createConnection() { + boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop); + connections.push_back(connection); + return connection; + } + + EventLoop* eventLoop; + std::vector< boost::shared_ptr<MockConnection> > connections; + std::vector<HostAddressPort> failingPorts; + }; + + private: + HostAddressPort proxyHost; + HostAddressPort host; + DummyEventLoop* eventLoop; + MockConnectionFactory* connectionFactory; + std::vector< boost::shared_ptr<MockConnection> > connections; + bool connectFinished; + bool connectFinishedWithError; + bool disconnected; + boost::optional<Connection::Error> disconnectedError; + ByteArray dataRead; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(HTTPConnectProxiedConnectionTest); diff --git a/Swiften/Network/UnixProxyProvider.cpp b/Swiften/Network/UnixProxyProvider.cpp new file mode 100644 index 0000000..e21b310 --- /dev/null +++ b/Swiften/Network/UnixProxyProvider.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include "Swiften/Base/foreach.h" +#include "Swiften/Network/UnixProxyProvider.h" + +namespace Swift { + +UnixProxyProvider::UnixProxyProvider() : +#if defined(HAVE_GCONF) + gconfProxyProvider(), +#endif + environmentProxyProvider() +{ +} + +HostAddressPort UnixProxyProvider::getSOCKS5Proxy() const { + HostAddressPort proxy; +#if defined(HAVE_GCONF) + proxy = gconfProxyProvider.getSOCKS5Proxy(); + if(proxy.isValid()) { + return proxy; + } +#endif + proxy = environmentProxyProvider.getSOCKS5Proxy(); + if(proxy.isValid()) { + return proxy; + } + return HostAddressPort(HostAddress(), 0); +} + +HostAddressPort UnixProxyProvider::getHTTPConnectProxy() const { + HostAddressPort proxy; +#if defined(HAVE_GCONF) + proxy = gconfProxyProvider.getHTTPConnectProxy(); + if(proxy.isValid()) { + return proxy; + } +#endif + proxy = environmentProxyProvider.getHTTPConnectProxy(); + if(proxy.isValid()) { + return proxy; + } + return HostAddressPort(HostAddress(), 0); +} + + +} diff --git a/Swiften/Network/UnixProxyProvider.h b/Swiften/Network/UnixProxyProvider.h new file mode 100644 index 0000000..509cf4b --- /dev/null +++ b/Swiften/Network/UnixProxyProvider.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#if defined(HAVE_GCONF) +# include "Swiften/Network/GConfProxyProvider.h" +#endif +#include "Swiften/Network/EnvironmentProxyProvider.h" + +namespace Swift { + class UnixProxyProvider : public ProxyProvider { + public: + UnixProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: +#if defined(HAVE_GCONF) + GConfProxyProvider gconfProxyProvider; +#endif + EnvironmentProxyProvider environmentProxyProvider; + }; +} diff --git a/Swiften/Network/WindowsProxyProvider.cpp b/Swiften/Network/WindowsProxyProvider.cpp new file mode 100644 index 0000000..5f6f5d2 --- /dev/null +++ b/Swiften/Network/WindowsProxyProvider.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <iostream> +#include <boost/lexical_cast.hpp> + +#include "Swiften/Base/log.h" +#include "Swiften/Base/foreach.h" +#include "Swiften/Network/WindowsProxyProvider.h" +#include "Swiften/Base/ByteArray.h" + +#include <windows.h> + +namespace Swift { + +WindowsProxyProvider::WindowsProxyProvider() +: ProxyProvider() +{ + HKEY hKey = (HKEY)INVALID_HANDLE_VALUE; + long result; + + result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (result == ERROR_SUCCESS && hKey != INVALID_HANDLE_VALUE && proxyEnabled(hKey)) { + DWORD dataType = REG_SZ; + DWORD dataSize = 0; + ByteArray dataBuffer; + + result = RegQueryValueEx(hKey, "ProxyServer", NULL, &dataType, NULL, &dataSize); + if(result != ERROR_SUCCESS) { + return; + } + dataBuffer.resize(dataSize); + result = RegQueryValueEx(hKey, "ProxyServer", NULL, &dataType, reinterpret_cast<BYTE*>(dataBuffer.getData()), &dataSize); + if(result == ERROR_SUCCESS) { + std::vector<std::string> proxies = String::split(dataBuffer.toString(), ';'); + std::pair<std::string, std::string> protocolAndProxy; + foreach(std::string proxy, proxies) { + if(proxy.find('=') != std::string::npos) { + protocolAndProxy = String::getSplittedAtFirst(proxy, '='); + SWIFT_LOG(debug) << "Found proxy: " << protocolAndProxy.first << " => " << protocolAndProxy.second << std::endl; + if(protocolAndProxy.first.compare("socks") == 0) { + socksProxy = getAsHostAddressPort(protocolAndProxy.second); + } + else if (protocolAndProxy.first.compare("http") == 0) { + httpProxy = getAsHostAddressPort(protocolAndProxy.second); + } + } + } + } + } +} + +HostAddressPort WindowsProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort WindowsProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort WindowsProxyProvider::getAsHostAddressPort(std::string proxy) { + HostAddressPort ret(HostAddress(), 0); + + try { + std::pair<std::string, std::string> tmp; + int port = 0; + tmp = String::getSplittedAtFirst(proxy, ':'); + // .c_str() is needed as tmp.second can include a \0 char which will end in an exception of the lexical cast. + // with .c_str() the \0 will not be part of the string which is to be casted + port = boost::lexical_cast<int> (tmp.second.c_str()); + ret = HostAddressPort(HostAddress(tmp.first), port); + } + catch(...) { + std::cerr << "Exception occured while parsing windows proxy \"getHostAddressPort\"." << std::endl; + } + + return ret; +} + + +bool WindowsProxyProvider::proxyEnabled(HKEY hKey) const { + bool ret = false; + long result; + DWORD dataType = REG_DWORD; + DWORD dataSize = 0; + DWORD data = 0; + ByteArray dataBuffer; + + if(hKey == INVALID_HANDLE_VALUE) + return ret; + + result = RegQueryValueEx(hKey, "ProxyEnable", NULL, &dataType, NULL, &dataSize); + if(result != ERROR_SUCCESS) + return ret; + + dataBuffer.resize(dataSize); + result = RegQueryValueEx(hKey, "ProxyEnable", NULL, &dataType, reinterpret_cast<BYTE*>(dataBuffer.getData()), &dataSize); + if(result != ERROR_SUCCESS) + return ret; + + for(size_t t = 0; t < dataBuffer.getSize(); t++) { + data += static_cast<int> (dataBuffer[t]) * pow(256, static_cast<double>(t)); + } + return (data == 1); +} + +} diff --git a/Swiften/Network/WindowsProxyProvider.h b/Swiften/Network/WindowsProxyProvider.h new file mode 100644 index 0000000..d8d08f0 --- /dev/null +++ b/Swiften/Network/WindowsProxyProvider.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include "Swiften/Network/ProxyProvider.h" + +namespace Swift { + class WindowsProxyProvider : public ProxyProvider { + public: + WindowsProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getAsHostAddressPort(std::string proxy); + bool proxyEnabled(HKEY hKey) const; + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} diff --git a/Swiften/Parser/Attribute.h b/Swiften/Parser/Attribute.h new file mode 100644 index 0000000..f1f9a83 --- /dev/null +++ b/Swiften/Parser/Attribute.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 <string> + +namespace Swift { + class Attribute { + public: + Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) { + } + + const std::string& getName() const { + return name; + } + + const std::string& getNamespace() const { + return ns; + } + + bool operator==(const Attribute& o) const { + return o.name == name && o.ns == ns; + } + + private: + std::string name; + std::string ns; + }; +} diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp new file mode 100644 index 0000000..1aeaf99 --- /dev/null +++ b/Swiften/Parser/AttributeMap.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/AttributeMap.h> + +#include <algorithm> +#include <boost/optional.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; + }; +} + +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))); + if (i == attributes.end()) { + return ""; + } + else { + return i->getValue(); + } +} + +bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultValue) const { + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ""))); + if (i == attributes.end()) { + return defaultValue; + } + else { + return i->getValue() == "true" || i->getValue() == "1"; + } +} + +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, ""))); + if (i == attributes.end()) { + return boost::optional<std::string>(); + } + else { + return i->getValue(); + } +} + +void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) { + attributes.push_back(Entry(Attribute(name, ns), value)); +} diff --git a/Swiften/Parser/AttributeMap.h b/Swiften/Parser/AttributeMap.h index c8b287b..31df606 100644 --- a/Swiften/Parser/AttributeMap.h +++ b/Swiften/Parser/AttributeMap.h @@ -4,38 +4,50 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef ATTRIBUTEMAP_H -#define ATTRIBUTEMAP_H +#pragma once +#include <vector> +#include <string> #include <map> +#include <boost/optional/optional_fwd.hpp> -#include <string> +#include <Swiften/Parser/Attribute.h> namespace Swift { - class AttributeMap : public std::map<std::string,std::string> { + class AttributeMap { public: - AttributeMap() {} - - std::string getAttribute(const std::string& attribute) const { - AttributeMap::const_iterator i = find(attribute); - if (i == end()) { - return ""; - } - else { - return i->second; - } - } + class Entry { + public: + Entry(const Attribute& attribute, const std::string& value) : attribute(attribute), value(value) { + } + + const Attribute& getAttribute() const { + return attribute; + } + + const std::string& getValue() const { + return value; + } + + private: + Attribute attribute; + std::string value; + }; - bool getBoolAttribute(const std::string& attribute, bool defaultValue = false) const { - AttributeMap::const_iterator i = find(attribute); - if (i == end()) { - return defaultValue; - } - else { - return i->second == "true" || i->second == "1"; - } + AttributeMap(); + + std::string getAttribute(const std::string& attribute, const std::string& ns = "") const; + bool getBoolAttribute(const std::string& attribute, bool defaultValue = false) const; + boost::optional<std::string> getAttributeValue(const std::string&) const; + + void addAttribute(const std::string& name, const std::string& ns, const std::string& value); + + const std::vector<Entry>& getEntries() const { + return attributes; } + + private: + typedef std::vector<Entry> AttributeValueMap; + AttributeValueMap attributes; }; } - -#endif diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index 88be752..448b199 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp @@ -30,7 +30,7 @@ static void handleStartElement(void* client, const XML_Char* name, const XML_Cha nsAttributePair.second = nsAttributePair.first; nsAttributePair.first = ""; } - attributeValues[nsAttributePair.second] = std::string(*(currentAttribute+1)); + attributeValues.addAttribute(nsAttributePair.second, nsAttributePair.first, std::string(*(currentAttribute+1))); currentAttribute += 2; } diff --git a/Swiften/Parser/IQParser.cpp b/Swiften/Parser/IQParser.cpp index e0883f2..62d775f 100644 --- a/Swiften/Parser/IQParser.cpp +++ b/Swiften/Parser/IQParser.cpp @@ -5,8 +5,9 @@ */ #include <iostream> +#include <boost/optional.hpp> -#include "Swiften/Parser/IQParser.h" +#include <Swiften/Parser/IQParser.h> namespace Swift { @@ -15,22 +16,22 @@ IQParser::IQParser(PayloadParserFactoryCollection* factories) : } void IQParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "set") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "set") { getStanzaGeneric()->setType(IQ::Set); } - else if (type->second == "get") { + else if (*type == "get") { getStanzaGeneric()->setType(IQ::Get); } - else if (type->second == "result") { + else if (*type == "result") { getStanzaGeneric()->setType(IQ::Result); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(IQ::Error); } else { - std::cerr << "Unknown IQ type: " << type->second << std::endl; + std::cerr << "Unknown IQ type: " << *type << std::endl; getStanzaGeneric()->setType(IQ::Get); } } diff --git a/Swiften/Parser/IQParser.h b/Swiften/Parser/IQParser.h index e104dc4..35ab132 100644 --- a/Swiften/Parser/IQParser.h +++ b/Swiften/Parser/IQParser.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IQParser_H -#define SWIFTEN_IQParser_H +#pragma once #include "Swiften/Parser/GenericStanzaParser.h" #include "Swiften/Elements/IQ.h" @@ -19,5 +18,3 @@ namespace Swift { virtual void handleStanzaAttributes(const AttributeMap&); }; } - -#endif diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index 34db4ca..0b15848 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -15,10 +15,18 @@ namespace Swift { -static void handleStartElement(void *client, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int, const xmlChar ** attributes) { +static void handleStartElement(void *client, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { AttributeMap attributeValues; + if (nbDefaulted != 0) { + // Just because i don't understand what this means yet :-) + std::cerr << "Unexpected nbDefaulted on XML element" << std::endl; + } for (int i = 0; i < nbAttributes*5; i += 5) { - attributeValues[std::string(reinterpret_cast<const char*>(attributes[i]))] = std::string(reinterpret_cast<const char*>(attributes[i+3]), attributes[i+4]-attributes[i+3]); + std::string attributeNS = ""; + if (attributes[i+2]) { + 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])); } static_cast<XMLParserClient*>(client)->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); } diff --git a/Swiften/Parser/MessageParser.cpp b/Swiften/Parser/MessageParser.cpp index 5f4d59c..7f5e6d4 100644 --- a/Swiften/Parser/MessageParser.cpp +++ b/Swiften/Parser/MessageParser.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <iostream> +#include <boost/optional.hpp> -#include "Swiften/Parser/MessageParser.h" +#include <Swiften/Parser/MessageParser.h> namespace Swift { @@ -16,18 +16,18 @@ MessageParser::MessageParser(PayloadParserFactoryCollection* factories) : } void MessageParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "chat") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "chat") { getStanzaGeneric()->setType(Message::Chat); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(Message::Error); } - else if (type->second == "groupchat") { + else if (*type == "groupchat") { getStanzaGeneric()->setType(Message::Groupchat); } - else if (type->second == "headline") { + else if (*type == "headline") { getStanzaGeneric()->setType(Message::Headline); } else { diff --git a/Swiften/Parser/PayloadParser.h b/Swiften/Parser/PayloadParser.h index 423a2bb..3dc04df 100644 --- a/Swiften/Parser/PayloadParser.h +++ b/Swiften/Parser/PayloadParser.h @@ -44,6 +44,6 @@ namespace Swift { /** * Retrieve a pointer to the payload. */ - virtual Payload::ref getPayload() const = 0; + virtual boost::shared_ptr<Payload> getPayload() const = 0; }; } diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp index 35db9ec..3de11ac 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp @@ -27,7 +27,7 @@ void BytestreamsParser::handleStartElement(const std::string& element, const std try { getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::lexical_cast<int>(attributes.getAttribute("port")))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "streamhost-used") { diff --git a/Swiften/Parser/PayloadParsers/DelayParser.cpp b/Swiften/Parser/PayloadParsers/DelayParser.cpp index 3425b84..0ab2d7b 100644 --- a/Swiften/Parser/PayloadParsers/DelayParser.cpp +++ b/Swiften/Parser/PayloadParsers/DelayParser.cpp @@ -9,6 +9,7 @@ #include <locale> #include <boost/date_time/time_facet.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp b/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp index 19d0530..48841d2 100644 --- a/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp +++ b/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp @@ -6,6 +6,7 @@ #include <Swiften/Parser/PayloadParsers/DelayParserFactory.h> +#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/time_facet.hpp> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp index e1fcb20..2e9e87a 100644 --- a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp +++ b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp @@ -15,7 +15,7 @@ DiscoInfoParser::DiscoInfoParser() : level_(TopLevel), formParser_(NULL) { void DiscoInfoParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { if (level_ == PayloadLevel) { if (element == "identity") { - getPayloadInternal()->addIdentity(DiscoInfo::Identity(attributes.getAttribute("name"), attributes.getAttribute("category"), attributes.getAttribute("type"), attributes.getAttribute("lang"))); + getPayloadInternal()->addIdentity(DiscoInfo::Identity(attributes.getAttribute("name"), attributes.getAttribute("category"), attributes.getAttribute("type"), attributes.getAttribute("lang", "http://www.w3.org/XML/1998/namespace"))); } else if (element == "feature") { getPayloadInternal()->addFeature(attributes.getAttribute("var")); diff --git a/Swiften/Parser/PayloadParsers/FormParser.cpp b/Swiften/Parser/PayloadParsers/FormParser.cpp index f8e02a4..72449b8 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.cpp +++ b/Swiften/Parser/PayloadParsers/FormParser.cpp @@ -63,12 +63,9 @@ void FormParser::handleStartElement(const std::string& element, const std::strin else if (type == "text-private") { currentFieldParseHelper_ = TextPrivateFormFieldParseHelper::create(); } - else if (type == "text-single") { + else /*if (type == "text-single") || undefined */ { currentFieldParseHelper_ = TextSingleFormFieldParseHelper::create(); } - else { - currentFieldParseHelper_ = UntypedFormFieldParseHelper::create(); - } if (currentFieldParseHelper_) { currentFieldParseHelper_->getField()->setName(attributes.getAttribute("var")); currentFieldParseHelper_->getField()->setLabel(attributes.getAttribute("label")); diff --git a/Swiften/Parser/PayloadParsers/FormParser.h b/Swiften/Parser/PayloadParsers/FormParser.h index 90a3550..e6e6ec0 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.h +++ b/Swiften/Parser/PayloadParsers/FormParser.h @@ -96,7 +96,6 @@ namespace Swift { SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDSingle, JID); SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDMulti, JIDList); SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(ListMulti, StringList); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Untyped, StringList); enum Level { TopLevel = 0, diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index e20c06d..55deafc 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -17,6 +17,7 @@ #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" @@ -39,6 +40,7 @@ #include "Swiften/Parser/PayloadParsers/DelayParserFactory.h" #include "Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h" #include "Swiften/Parser/PayloadParsers/NicknameParserFactory.h" +#include "Swiften/Parser/PayloadParsers/ReplaceParser.h" using namespace boost; @@ -48,12 +50,14 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<IBBParser>("", "http://jabber.org/protocol/ibb"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StatusShowParser>("show"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StatusParser>("status"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ReplaceParser>("replace", "http://swift.im/protocol/replace"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<BodyParser>("body"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SubjectParser>("subject"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<PriorityParser>("priority"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ErrorParser>("error"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SoftwareVersionParser>("query", "jabber:iq:version"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StorageParser>("storage", "storage:bookmarks"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterItemExchangeParser>("x", "http://jabber.org/protocol/rosterx"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterParser>("query", "jabber:iq:roster"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoInfoParser>("query", "http://jabber.org/protocol/disco#info"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoItemsParser>("query", "http://jabber.org/protocol/disco#items"))); diff --git a/Swiften/Parser/PayloadParsers/IBBParser.cpp b/Swiften/Parser/PayloadParsers/IBBParser.cpp index f36dc43..8196295 100644 --- a/Swiften/Parser/PayloadParsers/IBBParser.cpp +++ b/Swiften/Parser/PayloadParsers/IBBParser.cpp @@ -27,7 +27,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string try { getPayloadInternal()->setSequenceNumber(boost::lexical_cast<int>(attributes.getAttribute("seq"))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "open") { @@ -42,7 +42,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string try { getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttribute("block-size"))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "close") { @@ -64,7 +64,7 @@ void IBBParser::handleEndElement(const std::string& element, const std::string&) data.push_back(c); } } - getPayloadInternal()->setData(Base64::decode(std::string(&data[0], data.size()))); + getPayloadInternal()->setData(Base64::decode(std::string(&data[0], data.size())).getDataVector()); } } } diff --git a/Swiften/Parser/PayloadParsers/PriorityParser.cpp b/Swiften/Parser/PayloadParsers/PriorityParser.cpp index bcbf67f..553a2b1 100644 --- a/Swiften/Parser/PayloadParsers/PriorityParser.cpp +++ b/Swiften/Parser/PayloadParsers/PriorityParser.cpp @@ -24,7 +24,7 @@ void PriorityParser::handleEndElement(const std::string&, const std::string&) { try { priority = boost::lexical_cast<int>(text_); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } getPayloadInternal()->setPriority(priority); } diff --git a/Swiften/Parser/PayloadParsers/ReplaceParser.cpp b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp new file mode 100644 index 0000000..8e5659f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Parser/PayloadParsers/ReplaceParser.h" + +namespace Swift { + + ReplaceParser::ReplaceParser() : level_(0) { + } + + void ReplaceParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level_ == 0) { + std::string id = attributes.getAttribute("id"); + getPayloadInternal()->setId(id); + } + level_++; + } + + void ReplaceParser::handleEndElement(const std::string&, const std::string&) { + --level_; + } + + void ReplaceParser::handleCharacterData(const std::string&) { + } + +} diff --git a/Swiften/Parser/PayloadParsers/ReplaceParser.h b/Swiften/Parser/PayloadParsers/ReplaceParser.h new file mode 100644 index 0000000..0789927 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReplaceParser.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Elements/Replace.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class ReplaceParser : public GenericPayloadParser<Replace> { + public: + ReplaceParser(); + 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/RosterItemExchangeParser.cpp b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp new file mode 100644 index 0000000..ff2a73b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h" +#include "Swiften/Parser/SerializingParser.h" + +namespace Swift { + +RosterItemExchangeParser::RosterItemExchangeParser() : level_(TopLevel), inItem_(false) { +} + +void RosterItemExchangeParser::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& attributes) { + if (level_ == PayloadLevel) { + if (element == "item") { + inItem_ = true; + + currentItem_ = RosterItemExchangePayload::Item(); + + currentItem_.setJID(JID(attributes.getAttribute("jid"))); + currentItem_.setName(attributes.getAttribute("name")); + + std::string action = attributes.getAttribute("action"); + if (action == "add") { + currentItem_.setAction(RosterItemExchangePayload::Item::Add); + } + else if (action == "modify") { + currentItem_.setAction(RosterItemExchangePayload::Item::Modify); + } + else if (action == "delete") { + currentItem_.setAction(RosterItemExchangePayload::Item::Delete); + } + else { + // Add is default action according to XEP + currentItem_.setAction(RosterItemExchangePayload::Item::Add); + } + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentText_ = ""; + } + } + ++level_; +} + +void RosterItemExchangeParser::handleEndElement(const std::string& element, const std::string& /*ns*/) { + --level_; + if (level_ == PayloadLevel) { + if (inItem_) { + getPayloadInternal()->addItem(currentItem_); + inItem_ = false; + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentItem_.addGroup(currentText_); + } + } +} + +void RosterItemExchangeParser::handleCharacterData(const std::string& data) { + currentText_ += data; +} + +} diff --git a/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h new file mode 100644 index 0000000..3d6b8f4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Elements/RosterItemExchangePayload.h" +#include "Swiften/Parser/GenericPayloadParser.h" + +namespace Swift { + class SerializingParser; + + class RosterItemExchangeParser : public GenericPayloadParser<RosterItemExchangePayload> { + public: + RosterItemExchangeParser(); + + 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: + enum Level { + TopLevel = 0, + PayloadLevel = 1, + ItemLevel = 2 + }; + int level_; + bool inItem_; + RosterItemExchangePayload::Item currentItem_; + std::string currentText_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/RosterParser.cpp b/Swiften/Parser/PayloadParsers/RosterParser.cpp index ba19fbf..5fba30b 100644 --- a/Swiften/Parser/PayloadParsers/RosterParser.cpp +++ b/Swiften/Parser/PayloadParsers/RosterParser.cpp @@ -5,6 +5,9 @@ */ #include "Swiften/Parser/PayloadParsers/RosterParser.h" + +#include <boost/optional.hpp> + #include "Swiften/Parser/SerializingParser.h" namespace Swift { @@ -13,7 +16,13 @@ RosterParser::RosterParser() : level_(TopLevel), inItem_(false), unknownContentP } void RosterParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { - if (level_ == PayloadLevel) { + if (level_ == TopLevel) { + boost::optional<std::string> ver = attributes.getAttributeValue("ver"); + if (ver) { + getPayloadInternal()->setVersion(*ver); + } + } + else if (level_ == PayloadLevel) { if (element == "item") { inItem_ = true; currentItem_ = RosterItemPayload(); diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp index 1cf7fcf..0d4a407 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp @@ -42,7 +42,7 @@ void StreamInitiationParser::handleStartElement(const std::string& element, cons try { currentFile.size = boost::lexical_cast<int>(attributes.getAttribute("size")); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "feature" && ns == FEATURE_NEG_NS) { diff --git a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp index 6ec825b..7feada1 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp @@ -77,7 +77,6 @@ class FormParserTest : public CppUnit::TestFixture { "</field>" "<field var=\"untyped\">" "<value>foo</value>" - "<value>baz</value>" "</field>" "</x>")); @@ -114,8 +113,7 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(JID("baz@fum.org"), boost::dynamic_pointer_cast<JIDMultiFormField>(payload->getFields()[8])->getValue()[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<UntypedFormField>(payload->getFields()[9])->getValue()[0]); - CPPUNIT_ASSERT_EQUAL(std::string("baz"), boost::dynamic_pointer_cast<UntypedFormField>(payload->getFields()[9])->getValue()[1]); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), boost::dynamic_pointer_cast<TextSingleFormField>(payload->getFields()[9])->getValue()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp index b4229f2..2fc3e79 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp @@ -32,7 +32,7 @@ class IBBParserTest : public CppUnit::TestFixture { IBB::ref ibb = parser.getPayload<IBB>(); CPPUNIT_ASSERT(ibb->getAction() == IBB::Data); - CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a"), ibb->getData()); + CPPUNIT_ASSERT(ByteArray::create("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a") == ibb->getData()); CPPUNIT_ASSERT_EQUAL(4, ibb->getSequenceNumber()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp index 68a2e4f..e2b8be2 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp @@ -24,7 +24,7 @@ class PriorityParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(parser.parse("<priority>-120</priority>")); - Priority::ref payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); + boost::shared_ptr<Priority> payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); CPPUNIT_ASSERT_EQUAL(-120, payload->getPriority()); } @@ -33,7 +33,7 @@ class PriorityParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(parser.parse("<priority>invalid</priority>")); - Priority::ref payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); + boost::shared_ptr<Priority> payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); CPPUNIT_ASSERT_EQUAL(0, payload->getPriority()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp new file mode 100644 index 0000000..7c34eb1 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * 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/ReplaceParser.h" +#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" + +using namespace Swift; + +class ReplaceParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ReplaceParserTest); + CPPUNIT_TEST(testParseTrivial); + CPPUNIT_TEST(testParseChild); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParseTrivial() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<replace id='bad1' xmlns='http://swift.im/protocol/replace'/>")); + Replace::ref payload = boost::dynamic_pointer_cast <Replace>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("bad1"), payload->getId()); + } + void testParseChild() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<replace id='bad1' xmlns='http://swift.im/protocol/replace' ><child xmlns='blah' id=\"hi\"/></replace>")); + Replace::ref payload = boost::dynamic_pointer_cast <Replace>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("bad1"), payload->getId()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ReplaceParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp new file mode 100644 index 0000000..9533e15 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 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/RosterItemExchangeParser.h" +#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" + +using namespace Swift; + +class RosterItemExchangeParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterItemExchangeParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<x xmlns=\"http://jabber.org/protocol/rosterx\">" + "<item action=\"add\" jid=\"foo@bar.com\" name=\"Foo @ Bar\">" + "<group>Group 1</group>" + "<group>Group 2</group>" + "</item>" + "<item action=\"modify\" jid=\"baz@blo.com\" name=\"Baz\"/>" + "</x>")); + + RosterItemExchangePayload* payload = dynamic_cast<RosterItemExchangePayload*>(parser.getPayload().get()); + const RosterItemExchangePayload::RosterItemExchangePayloadItems& items = payload->getItems(); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items.size()); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), items[0].getJID()); + CPPUNIT_ASSERT_EQUAL(std::string("Foo @ Bar"), items[0].getName()); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Item::Add, items[0].getAction()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items[0].getGroups().size()); + CPPUNIT_ASSERT_EQUAL(std::string("Group 1"), items[0].getGroups()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Group 2"), items[0].getGroups()[1]); + + CPPUNIT_ASSERT_EQUAL(JID("baz@blo.com"), items[1].getJID()); + CPPUNIT_ASSERT_EQUAL(std::string("Baz"), items[1].getName()); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Item::Modify, items[1].getAction()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), items[1].getGroups().size()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RosterItemExchangeParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp index 1bcea0e..3102b74 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp @@ -17,6 +17,8 @@ class RosterParserTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(RosterParserTest); CPPUNIT_TEST(testParse); CPPUNIT_TEST(testParse_ItemWithUnknownContent); + CPPUNIT_TEST(testParse_WithVersion); + CPPUNIT_TEST(testParse_WithEmptyVersion); CPPUNIT_TEST_SUITE_END(); public: @@ -32,6 +34,8 @@ class RosterParserTest : public CppUnit::TestFixture "</query>")); RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + + CPPUNIT_ASSERT(!payload->getVersion()); const RosterPayload::RosterItemPayloads& items = payload->getItems(); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items.size()); @@ -74,6 +78,24 @@ class RosterParserTest : public CppUnit::TestFixture "<baz xmlns=\"jabber:iq:roster\"><fum xmlns=\"jabber:iq:roster\">foo</fum></baz>" ), items[0].getUnknownContent()); } + + void testParse_WithVersion() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<query xmlns='jabber:iq:roster' ver='ver10'/>")); + + RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("ver10"), *payload->getVersion()); + } + + void testParse_WithEmptyVersion() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<query xmlns='jabber:iq:roster' ver=''/>")); + + RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *payload->getVersion()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(RosterParserTest); diff --git a/Swiften/Parser/PresenceParser.cpp b/Swiften/Parser/PresenceParser.cpp index 845ccf0..867155f 100644 --- a/Swiften/Parser/PresenceParser.cpp +++ b/Swiften/Parser/PresenceParser.cpp @@ -5,6 +5,7 @@ */ #include <iostream> +#include <boost/optional.hpp> #include "Swiften/Parser/PresenceParser.h" @@ -15,31 +16,31 @@ PresenceParser::PresenceParser(PayloadParserFactoryCollection* factories) : } void PresenceParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "unavailable") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "unavailable") { getStanzaGeneric()->setType(Presence::Unavailable); } - else if (type->second == "probe") { + else if (*type == "probe") { getStanzaGeneric()->setType(Presence::Probe); } - else if (type->second == "subscribe") { + else if (*type == "subscribe") { getStanzaGeneric()->setType(Presence::Subscribe); } - else if (type->second == "subscribed") { + else if (*type == "subscribed") { getStanzaGeneric()->setType(Presence::Subscribed); } - else if (type->second == "unsubscribe") { + else if (*type == "unsubscribe") { getStanzaGeneric()->setType(Presence::Unsubscribe); } - else if (type->second == "unsubscribed") { + else if (*type == "unsubscribed") { getStanzaGeneric()->setType(Presence::Unsubscribed); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(Presence::Error); } else { - std::cerr << "Unknown Presence type: " << type->second << std::endl; + std::cerr << "Unknown Presence type: " << *type << std::endl; getStanzaGeneric()->setType(Presence::Available); } } diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index cbb2190..d9915ed 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -6,6 +6,7 @@ myenv.MergeFlags(swiften_env.get("LIBXML_FLAGS", "")) myenv.MergeFlags(swiften_env.get("EXPAT_FLAGS", "")) sources = [ + "AttributeMap.cpp", "AuthRequestParser.cpp", "AuthChallengeParser.cpp", "AuthSuccessParser.cpp", @@ -37,6 +38,7 @@ sources = [ "PayloadParsers/PrivateStorageParser.cpp", "PayloadParsers/RawXMLPayloadParser.cpp", "PayloadParsers/ResourceBindParser.cpp", + "PayloadParsers/RosterItemExchangeParser.cpp", "PayloadParsers/RosterParser.cpp", "PayloadParsers/SecurityLabelParser.cpp", "PayloadParsers/SecurityLabelsCatalogParser.cpp", @@ -51,12 +53,15 @@ sources = [ "PayloadParsers/DelayParser.cpp", "PayloadParsers/MUCUserPayloadParser.cpp", "PayloadParsers/NicknameParser.cpp", + "PayloadParsers/ReplaceParser.cpp", "PlatformXMLParserFactory.cpp", "PresenceParser.cpp", "SerializingParser.cpp", "StanzaParser.cpp", "StreamErrorParser.cpp", "StreamFeaturesParser.cpp", + "StreamManagementEnabledParser.cpp", + "StreamResumeParser.cpp", "XMLParser.cpp", "XMLParserClient.cpp", "XMLParserFactory.cpp", diff --git a/Swiften/Parser/SerializingParser.cpp b/Swiften/Parser/SerializingParser.cpp index 43dfc51..03b9575 100644 --- a/Swiften/Parser/SerializingParser.cpp +++ b/Swiften/Parser/SerializingParser.cpp @@ -7,7 +7,6 @@ #include "Swiften/Parser/SerializingParser.h" #include "Swiften/Serializer/XML/XMLTextNode.h" #include "Swiften/Base/foreach.h" -#include <iostream> namespace Swift { @@ -16,8 +15,9 @@ SerializingParser::SerializingParser() { void SerializingParser::handleStartElement(const std::string& tag, const std::string& ns, const AttributeMap& attributes) { boost::shared_ptr<XMLElement> element(new XMLElement(tag, ns)); - for (AttributeMap::const_iterator i = attributes.begin(); i != attributes.end(); ++i) { - element->setAttribute((*i).first, (*i).second); + // FIXME: Ignoring attribute namespace + foreach (const AttributeMap::Entry& e, attributes.getEntries()) { + element->setAttribute(e.getAttribute().getName(), e.getValue()); } if (elementStack_.empty()) { diff --git a/Swiften/Parser/StanzaParser.cpp b/Swiften/Parser/StanzaParser.cpp index 64c4901..051f37e 100644 --- a/Swiften/Parser/StanzaParser.cpp +++ b/Swiften/Parser/StanzaParser.cpp @@ -7,6 +7,7 @@ #include "Swiften/Parser/StanzaParser.h" #include <iostream> +#include <boost/optional.hpp> #include <cassert> #include "Swiften/Parser/PayloadParser.h" @@ -39,17 +40,17 @@ void StanzaParser::handleStartElement(const std::string& element, const std::str currentPayloadParser_->handleStartElement(element, ns, attributes); } else { - AttributeMap::const_iterator from = attributes.find("from"); - if (from != attributes.end()) { - getStanza()->setFrom(JID(from->second)); + boost::optional<std::string> from = attributes.getAttributeValue("from"); + if (from) { + getStanza()->setFrom(JID(*from)); } - AttributeMap::const_iterator to = attributes.find("to"); - if (to != attributes.end()) { - getStanza()->setTo(JID(to->second)); + boost::optional<std::string> to = attributes.getAttributeValue("to"); + if (to) { + getStanza()->setTo(JID(*to)); } - AttributeMap::const_iterator id = attributes.find("id"); - if (id != attributes.end()) { - getStanza()->setID(id->second); + boost::optional<std::string> id = attributes.getAttributeValue("id"); + if (id) { + getStanza()->setID(*id); } handleStanzaAttributes(attributes); } diff --git a/Swiften/Parser/StreamFeaturesParser.cpp b/Swiften/Parser/StreamFeaturesParser.cpp index 377f215..1b3ad54 100644 --- a/Swiften/Parser/StreamFeaturesParser.cpp +++ b/Swiften/Parser/StreamFeaturesParser.cpp @@ -31,6 +31,9 @@ void StreamFeaturesParser::handleStartElement(const std::string& element, const else if (element == "compression" && ns == "http://jabber.org/features/compress") { inCompression_ = true; } + else if (element == "ver" && ns == "urn:xmpp:features:rosterver") { + getElementGeneric()->setHasRosterVersioning(); + } } else if (currentDepth_ == 2) { if (inCompression_ && element == "method") { diff --git a/Swiften/Parser/StreamManagementEnabledParser.cpp b/Swiften/Parser/StreamManagementEnabledParser.cpp new file mode 100644 index 0000000..906e071 --- /dev/null +++ b/Swiften/Parser/StreamManagementEnabledParser.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/StreamManagementEnabledParser.h> + +using namespace Swift; + +StreamManagementEnabledParser::StreamManagementEnabledParser() : level(TopLevel) { +} + +StreamManagementEnabledParser::~StreamManagementEnabledParser() { +} + +void StreamManagementEnabledParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level == TopLevel) { + if (attributes.getBoolAttribute("resume", false)) { + getElementGeneric()->setResumeSupported(); + } + getElementGeneric()->setResumeID(attributes.getAttribute("id")); + } + ++level; +} + +void StreamManagementEnabledParser::handleEndElement(const std::string&, const std::string&) { + --level; +} diff --git a/Swiften/Parser/StreamManagementEnabledParser.h b/Swiften/Parser/StreamManagementEnabledParser.h index adc45ab..db616af 100644 --- a/Swiften/Parser/StreamManagementEnabledParser.h +++ b/Swiften/Parser/StreamManagementEnabledParser.h @@ -1,17 +1,27 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StreamManagementEnabled.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamManagementEnabled.h> namespace Swift { class StreamManagementEnabledParser : public GenericElementParser<StreamManagementEnabled> { public: - StreamManagementEnabledParser() : GenericElementParser<StreamManagementEnabled>() {} + StreamManagementEnabledParser(); + ~StreamManagementEnabledParser(); + + virtual void handleStartElement(const std::string&, const std::string&, const AttributeMap&); + virtual void handleEndElement(const std::string&, const std::string&); + + private: + enum Level { + TopLevel = 0 + }; + int level; }; } diff --git a/Swiften/Parser/StreamResumeParser.cpp b/Swiften/Parser/StreamResumeParser.cpp new file mode 100644 index 0000000..f54dcf0 --- /dev/null +++ b/Swiften/Parser/StreamResumeParser.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/StreamResumeParser.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +StreamResumeParser::StreamResumeParser() : level(TopLevel) { +} + +StreamResumeParser::~StreamResumeParser() { +} + +void StreamResumeParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level == TopLevel) { + boost::optional<std::string> handledStanzasCount = attributes.getAttributeValue("h"); + if (handledStanzasCount) { + try { + getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<int>(*handledStanzasCount)); + } + catch (const boost::bad_lexical_cast &) { + } + } + getElementGeneric()->setResumeID(attributes.getAttribute("previd")); + } + ++level; +} + +void StreamResumeParser::handleEndElement(const std::string&, const std::string&) { + --level; +} diff --git a/Swiften/Parser/StreamResumeParser.h b/Swiften/Parser/StreamResumeParser.h new file mode 100644 index 0000000..0ccd24c --- /dev/null +++ b/Swiften/Parser/StreamResumeParser.h @@ -0,0 +1,27 @@ +/* + * 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/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamResume.h> + +namespace Swift { + class StreamResumeParser : public GenericElementParser<StreamResume> { + public: + StreamResumeParser(); + ~StreamResumeParser(); + + virtual void handleStartElement(const std::string&, const std::string&, const AttributeMap&); + virtual void handleEndElement(const std::string&, const std::string&); + + private: + enum Level { + TopLevel = 0 + }; + int level; + }; +} diff --git a/Swiften/Parser/UnitTest/AttributeMapTest.cpp b/Swiften/Parser/UnitTest/AttributeMapTest.cpp index fb68f29..8e2ccff 100644 --- a/Swiften/Parser/UnitTest/AttributeMapTest.cpp +++ b/Swiften/Parser/UnitTest/AttributeMapTest.cpp @@ -14,6 +14,7 @@ using namespace Swift; class AttributeMapTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(AttributeMapTest); + CPPUNIT_TEST(testGetAttribute_Namespaced); CPPUNIT_TEST(testGetBoolAttribute_True); CPPUNIT_TEST(testGetBoolAttribute_1); CPPUNIT_TEST(testGetBoolAttribute_False); @@ -24,39 +25,46 @@ class AttributeMapTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE_END(); public: - AttributeMapTest() {} + void testGetAttribute_Namespaced() { + AttributeMap testling; + testling.addAttribute("lang", "", "nl"); + testling.addAttribute("lang", "http://www.w3.org/XML/1998/namespace", "en"); + testling.addAttribute("lang", "", "fr"); + + CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); + } void testGetBoolAttribute_True() { AttributeMap testling; - testling["foo"] = "true"; + testling.addAttribute("foo", "", "true"); CPPUNIT_ASSERT(testling.getBoolAttribute("foo")); } void testGetBoolAttribute_1() { AttributeMap testling; - testling["foo"] = "1"; + testling.addAttribute("foo", "", "1"); CPPUNIT_ASSERT(testling.getBoolAttribute("foo")); } void testGetBoolAttribute_False() { AttributeMap testling; - testling["foo"] = "false"; + testling.addAttribute("foo", "", "false"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } void testGetBoolAttribute_0() { AttributeMap testling; - testling["foo"] = "0"; + testling.addAttribute("foo", "", "0"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } void testGetBoolAttribute_Invalid() { AttributeMap testling; - testling["foo"] = "bla"; + testling.addAttribute("foo", "", "bla"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } diff --git a/Swiften/Parser/UnitTest/StanzaParserTest.cpp b/Swiften/Parser/UnitTest/StanzaParserTest.cpp index d57f798..2657750 100644 --- a/Swiften/Parser/UnitTest/StanzaParserTest.cpp +++ b/Swiften/Parser/UnitTest/StanzaParserTest.cpp @@ -40,8 +40,8 @@ class StanzaParserTest : public CppUnit::TestFixture { MyStanzaParser testling(factoryCollection_); AttributeMap attributes; - attributes["foo"] = "fum"; - attributes["bar"] = "baz"; + attributes.addAttribute("foo", "", "fum"); + attributes.addAttribute("bar", "", "baz"); testling.handleStartElement("mystanza", "", attributes); testling.handleStartElement("mypayload1", "", attributes); testling.handleStartElement("child", "", attributes); @@ -107,9 +107,9 @@ class StanzaParserTest : public CppUnit::TestFixture { MyStanzaParser testling(factoryCollection_); AttributeMap attributes; - attributes["to"] = "foo@example.com/blo"; - attributes["from"] = "bar@example.com/baz"; - attributes["id"] = "id-123"; + attributes.addAttribute("to", "", "foo@example.com/blo"); + attributes.addAttribute("from", "", "bar@example.com/baz"); + attributes.addAttribute("id", "", "id-123"); testling.handleStartElement("mystanza", "", attributes); testling.handleEndElement("mypayload1", ""); diff --git a/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp b/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp index 1cdaf54..9fdea88 100644 --- a/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp +++ b/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp @@ -37,6 +37,7 @@ class StreamFeaturesParserTest : public CppUnit::TestFixture { "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>" "<sm xmlns='urn:xmpp:sm:2'/>" "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>" + "<ver xmlns=\"urn:xmpp:features:rosterver\"/>" "</stream:features>")); StreamFeatures::ref element = boost::dynamic_pointer_cast<StreamFeatures>(testling.getElement()); @@ -49,6 +50,7 @@ class StreamFeaturesParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(element->hasAuthenticationMechanism("DIGEST-MD5")); CPPUNIT_ASSERT(element->hasAuthenticationMechanism("PLAIN")); CPPUNIT_ASSERT(element->hasStreamManagement()); + CPPUNIT_ASSERT(element->hasRosterVersioning()); } void testParse_Empty() { diff --git a/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp b/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp new file mode 100644 index 0000000..07b7b31 --- /dev/null +++ b/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/StreamManagementEnabledParser.h> +#include <Swiften/Parser/UnitTest/ElementParserTester.h> + +using namespace Swift; + +class StreamManagementEnabledParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(StreamManagementEnabledParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + StreamManagementEnabledParser testling; + ElementParserTester parser(&testling); + + CPPUNIT_ASSERT(parser.parse( + "<enabled xmlns=\"urn:xmpp:sm:3\" id=\"some-long-sm-id\" resume=\"true\"/>")); + + boost::shared_ptr<StreamManagementEnabled> element = boost::dynamic_pointer_cast<StreamManagementEnabled>(testling.getElement()); + CPPUNIT_ASSERT(element->getResumeSupported()); + CPPUNIT_ASSERT_EQUAL(std::string("some-long-sm-id"), element->getResumeID()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(StreamManagementEnabledParserTest); diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index 426b7a0..27534a1 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -31,6 +31,8 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_InErrorState); CPPUNIT_TEST(testParse_Incremental); CPPUNIT_TEST(testParse_WhitespaceInAttribute); + CPPUNIT_TEST(testParse_AttributeWithoutNamespace); + CPPUNIT_TEST(testParse_AttributeWithNamespace); CPPUNIT_TEST_SUITE_END(); public: @@ -46,13 +48,13 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes["type"]); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes.getAttribute("type")); CPPUNIT_ASSERT_EQUAL(std::string(), client_.events[0].ns); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); @@ -76,7 +78,7 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); @@ -205,6 +207,28 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[2].data); } + + void testParse_AttributeWithoutNamespace() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' attr='3'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + } + + void testParse_AttributeWithNamespace() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' f:attr='3'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + } private: class Client : public XMLParserClient { diff --git a/Swiften/Parser/XMPPParser.cpp b/Swiften/Parser/XMPPParser.cpp index 1fb7682..adcfdf5 100644 --- a/Swiften/Parser/XMPPParser.cpp +++ b/Swiften/Parser/XMPPParser.cpp @@ -29,6 +29,7 @@ #include "Swiften/Parser/EnableStreamManagementParser.h" #include "Swiften/Parser/StreamManagementEnabledParser.h" #include "Swiften/Parser/StreamManagementFailedParser.h" +#include "Swiften/Parser/StreamResumeParser.h" #include "Swiften/Parser/StanzaAckParser.h" #include "Swiften/Parser/StanzaAckRequestParser.h" #include "Swiften/Parser/StartTLSParser.h" @@ -182,6 +183,12 @@ ElementParser* XMPPParser::createElementParser(const std::string& element, const else if (element == "failed" && ns == "urn:xmpp:sm:2") { return new StreamManagementFailedParser(); } + else if (element == "resume" && ns == "urn:xmpp:sm:2") { + return new StreamResumeParser(); + } + else if (element == "resumed" && ns == "urn:xmpp:sm:2") { + return new StreamResumeParser(); + } else if (element == "a" && ns == "urn:xmpp:sm:2") { return new StanzaAckParser(); } diff --git a/Swiften/Presence/PayloadAddingPresenceSender.cpp b/Swiften/Presence/PayloadAddingPresenceSender.cpp index c3d1638..43071b3 100644 --- a/Swiften/Presence/PayloadAddingPresenceSender.cpp +++ b/Swiften/Presence/PayloadAddingPresenceSender.cpp @@ -34,7 +34,7 @@ bool PayloadAddingPresenceSender::isAvailable() const { return sender->isAvailable(); } -void PayloadAddingPresenceSender::setPayload(Payload::ref payload) { +void PayloadAddingPresenceSender::setPayload(boost::shared_ptr<Payload> payload) { this->payload = payload; if (lastSentPresence) { sendPresence(lastSentPresence); diff --git a/Swiften/Presence/PayloadAddingPresenceSender.h b/Swiften/Presence/PayloadAddingPresenceSender.h index ae82970..ba891a8 100644 --- a/Swiften/Presence/PayloadAddingPresenceSender.h +++ b/Swiften/Presence/PayloadAddingPresenceSender.h @@ -21,7 +21,7 @@ namespace Swift { public: PayloadAddingPresenceSender(PresenceSender*); - void sendPresence(Presence::ref); + void sendPresence(boost::shared_ptr<Presence>); bool isAvailable() const; /** @@ -30,11 +30,11 @@ namespace Swift { * with an updated payload. Initial presence is reset when unavailable presence is * sent. */ - void setPayload(Payload::ref); + void setPayload(boost::shared_ptr<Payload>); private: - Presence::ref lastSentPresence; + boost::shared_ptr<Presence> lastSentPresence; PresenceSender* sender; - Payload::ref payload; + boost::shared_ptr<Payload> payload; }; } diff --git a/Swiften/QA/ClientTest/ClientTest.cpp b/Swiften/QA/ClientTest/ClientTest.cpp index 35bb096..09d357c 100644 --- a/Swiften/QA/ClientTest/ClientTest.cpp +++ b/Swiften/QA/ClientTest/ClientTest.cpp @@ -6,6 +6,7 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <iostream> #include "Swiften/Client/Client.h" #include "Swiften/Network/TimerFactory.h" diff --git a/Swiften/QA/ProxyProviderTest/.gitignore b/Swiften/QA/ProxyProviderTest/.gitignore new file mode 100644 index 0000000..9d4b9b8 --- /dev/null +++ b/Swiften/QA/ProxyProviderTest/.gitignore @@ -0,0 +1 @@ +ProxyProviderTest diff --git a/Swiften/QA/ProxyProviderTest/ProxyProviderTest.cpp b/Swiften/QA/ProxyProviderTest/ProxyProviderTest.cpp new file mode 100644 index 0000000..ddaee01 --- /dev/null +++ b/Swiften/QA/ProxyProviderTest/ProxyProviderTest.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2010 Thilo Cestonaro + * Licensed under the BSD License. + * See Documentation/Licenses/BSD.txt for more information. + */ + +#include <iostream> + +#include <Swiften/Network/PlatformProxyProvider.h> +#include <Swiften/Base/foreach.h> + +using namespace Swift; + +int main(void) +{ + int ret = 0; + HostAddressPort hap; + + std::cout << "constructing PlatfromProxyProvider instance ..." << std::endl; + PlatformProxyProvider ppp; + + hap = ppp.getSOCKS5Proxy(); + std::cout << "SOCKS5 Proxy configured: " << hap.isValid() << std::endl; + if(hap.isValid()) { + std::cout << "SOCKS5 Proxy: " << hap.getAddress().toString() << ":" << hap.getPort() << std::endl; + } + + hap = ppp.getHTTPConnectProxy(); + std::cout << "HTTPConnect Proxy configured: " << hap.isValid() << std::endl; + if(hap.isValid()) { + std::cout << "HTTPConnect Proxy: " << hap.getAddress().toString() << ":" << hap.getPort() << std::endl; + } + + return ret; +} diff --git a/Swiften/QA/ProxyProviderTest/SConscript b/Swiften/QA/ProxyProviderTest/SConscript new file mode 100644 index 0000000..2eb123d --- /dev/null +++ b/Swiften/QA/ProxyProviderTest/SConscript @@ -0,0 +1,11 @@ +import os + +Import("env") + +myenv = env.Clone() +myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) +myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) + +myenv.Program("ProxyProviderTest", [ + "ProxyProviderTest.cpp", + ]) diff --git a/Swiften/QA/SConscript b/Swiften/QA/SConscript index 25ba814..2f2be6e 100644 --- a/Swiften/QA/SConscript +++ b/Swiften/QA/SConscript @@ -5,7 +5,8 @@ SConscript(dirs = [ # "ReconnectTest", "ClientTest", # "DNSSDTest", - "StorageTest", +# "StorageTest", "TLSTest", "ScriptedTests", + "ProxyProviderTest", ]) diff --git a/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp b/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp index 925c775..73df0a0 100644 --- a/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp +++ b/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp @@ -7,6 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <Swiften/Base/ByteArray.h> #include "Swiften/FileTransfer/FileReadBytestream.h" #include "SwifTools/Application/PlatformApplicationPathProvider.h" @@ -32,16 +33,16 @@ class FileReadBytestreamTest : public CppUnit::TestFixture { void testRead() { std::auto_ptr<FileReadBytestream> testling(createTestling()); - ByteArray result = testling->read(10); + std::vector<unsigned char> result = testling->read(10); - CPPUNIT_ASSERT_EQUAL(std::string("/*\n * Copy"), result.toString()); + CPPUNIT_ASSERT(ByteArray::create("/*\n * Copy") == result); } void testRead_Twice() { std::auto_ptr<FileReadBytestream> testling(createTestling()); testling->read(10); - ByteArray result = testling->read(10); + ByteArray result(testling->read(10)); CPPUNIT_ASSERT_EQUAL(std::string("right (c) "), result.toString()); } diff --git a/Swiften/Queries/RawRequest.h b/Swiften/Queries/RawRequest.h index 477952f..e5b3a1d 100644 --- a/Swiften/Queries/RawRequest.h +++ b/Swiften/Queries/RawRequest.h @@ -31,7 +31,7 @@ namespace Swift { RawRequest(IQ::Type type, const JID& receiver, const std::string& data, IQRouter* router) : Request(type, receiver, boost::make_shared<RawXMLPayload>(data), router) { } - virtual void handleResponse(Payload::ref payload, ErrorPayload::ref error) { + virtual void handleResponse(boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { if (error) { onResponse(ErrorSerializer().serializePayload(error)); } diff --git a/Swiften/Queries/Request.h b/Swiften/Queries/Request.h index eee89e9..88eda63 100644 --- a/Swiften/Queries/Request.h +++ b/Swiften/Queries/Request.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_Request_H -#define SWIFTEN_Request_H +#pragma once #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> @@ -48,15 +47,15 @@ namespace Swift { const JID& receiver, IQRouter* router); - virtual void setPayload(Payload::ref payload) { + virtual void setPayload(boost::shared_ptr<Payload> payload) { payload_ = payload; } - Payload::ref getPayload() const { + boost::shared_ptr<Payload> getPayload() const { return payload_; } - virtual void handleResponse(Payload::ref, ErrorPayload::ref) = 0; + virtual void handleResponse(boost::shared_ptr<Payload>, boost::shared_ptr<ErrorPayload>) = 0; private: bool handleIQ(boost::shared_ptr<IQ>); @@ -70,5 +69,3 @@ namespace Swift { bool sent_; }; } - -#endif diff --git a/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h b/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h index 0700c65..5dd19b5 100644 --- a/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h +++ b/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h @@ -26,11 +26,11 @@ namespace Swift { SetInBandRegistrationRequest(const JID& to, InBandRegistrationPayload::ref payload, IQRouter* router) : Request(IQ::Set, to, InBandRegistrationPayload::ref(payload), router) { } - virtual void handleResponse(Payload::ref payload, ErrorPayload::ref error) { + virtual void handleResponse(boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { onResponse(payload, error); } public: - boost::signal<void (Payload::ref, ErrorPayload::ref)> onResponse; + boost::signal<void (boost::shared_ptr<Payload>, ErrorPayload::ref)> onResponse; }; } diff --git a/Swiften/Roster/GetRosterRequest.h b/Swiften/Roster/GetRosterRequest.h index 00cf77f..a3486f0 100644 --- a/Swiften/Roster/GetRosterRequest.h +++ b/Swiften/Roster/GetRosterRequest.h @@ -19,6 +19,12 @@ namespace Swift { return ref(new GetRosterRequest(router)); } + static ref create(IQRouter* router, const std::string& version) { + ref result(new GetRosterRequest(router)); + result->getPayloadGeneric()->setVersion(version); + return result; + } + private: GetRosterRequest(IQRouter* router) : GenericRequest<RosterPayload>(IQ::Get, JID(), boost::shared_ptr<Payload>(new RosterPayload()), router) { diff --git a/Swiften/Roster/RosterMemoryStorage.cpp b/Swiften/Roster/RosterMemoryStorage.cpp new file mode 100644 index 0000000..cbf4563 --- /dev/null +++ b/Swiften/Roster/RosterMemoryStorage.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/RosterMemoryStorage.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +RosterMemoryStorage::RosterMemoryStorage() { +} + +void RosterMemoryStorage::setRoster(boost::shared_ptr<RosterPayload> r) { + roster.reset(); + if (r) { + roster = boost::make_shared<RosterPayload>(*r); + } +} + +} diff --git a/Swiften/Roster/RosterMemoryStorage.h b/Swiften/Roster/RosterMemoryStorage.h new file mode 100644 index 0000000..b659d77 --- /dev/null +++ b/Swiften/Roster/RosterMemoryStorage.h @@ -0,0 +1,25 @@ +/* + * 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/Roster/RosterStorage.h> + +namespace Swift { + class RosterMemoryStorage : public RosterStorage { + public: + RosterMemoryStorage(); + + virtual boost::shared_ptr<RosterPayload> getRoster() const { + return roster; + } + + virtual void setRoster(boost::shared_ptr<RosterPayload>); + + private: + boost::shared_ptr<RosterPayload> roster; + }; +} diff --git a/Swiften/Roster/RosterStorage.cpp b/Swiften/Roster/RosterStorage.cpp new file mode 100644 index 0000000..6bf58de --- /dev/null +++ b/Swiften/Roster/RosterStorage.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/RosterStorage.h> + +namespace Swift { + +RosterStorage::~RosterStorage() { +} + +} diff --git a/Swiften/Roster/RosterStorage.h b/Swiften/Roster/RosterStorage.h new file mode 100644 index 0000000..ba24cb3 --- /dev/null +++ b/Swiften/Roster/RosterStorage.h @@ -0,0 +1,21 @@ +/* + * 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/Elements/RosterPayload.h> + +namespace Swift { + class RosterStorage { + public: + virtual ~RosterStorage(); + + virtual boost::shared_ptr<RosterPayload> getRoster() const = 0; + virtual void setRoster(boost::shared_ptr<RosterPayload>) = 0; + }; +} diff --git a/Swiften/Roster/SetRosterRequest.h b/Swiften/Roster/SetRosterRequest.h index e5ae974..606b431 100644 --- a/Swiften/Roster/SetRosterRequest.h +++ b/Swiften/Roster/SetRosterRequest.h @@ -19,11 +19,15 @@ namespace Swift { typedef boost::shared_ptr<SetRosterRequest> ref; static ref create(RosterPayload::ref payload, IQRouter* router) { - return ref(new SetRosterRequest(payload, router)); + return ref(new SetRosterRequest(JID(), payload, router)); + } + + static ref create(RosterPayload::ref payload, const JID& to, IQRouter* router) { + return ref(new SetRosterRequest(to, payload, router)); } private: - SetRosterRequest(boost::shared_ptr<RosterPayload> payload, IQRouter* router) : Request(IQ::Set, JID(), boost::shared_ptr<RosterPayload>(payload), router) { + SetRosterRequest(const JID& to, boost::shared_ptr<RosterPayload> payload, IQRouter* router) : Request(IQ::Set, to, boost::shared_ptr<RosterPayload>(payload), router) { } virtual void handleResponse(boost::shared_ptr<Payload> /*payload*/, ErrorPayload::ref error) { diff --git a/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp b/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp index 4ef1cc1..4c98673 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp +++ b/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp @@ -16,15 +16,24 @@ #include "Swiften/Client/DummyStanzaChannel.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Roster/XMPPRosterImpl.h" +#include <Swiften/Roster/RosterMemoryStorage.h> using namespace Swift; class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(XMPPRosterControllerTest); + CPPUNIT_TEST(testGet_Response); CPPUNIT_TEST(testGet_EmptyResponse); + CPPUNIT_TEST(testGet_NoRosterInStorage); + CPPUNIT_TEST(testGet_NoVersionInStorage); + CPPUNIT_TEST(testGet_VersionInStorage); + CPPUNIT_TEST(testGet_ServerDoesNotSupportVersion); + CPPUNIT_TEST(testGet_ResponseWithoutNewVersion); + CPPUNIT_TEST(testGet_ResponseWithNewVersion); CPPUNIT_TEST(testAdd); CPPUNIT_TEST(testModify); CPPUNIT_TEST(testRemove); + CPPUNIT_TEST(testRemove_RosterStorageUpdated); CPPUNIT_TEST(testMany); CPPUNIT_TEST_SUITE_END(); @@ -34,20 +43,36 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { router_ = new IQRouter(channel_); xmppRoster_ = new XMPPRosterImpl(); handler_ = new XMPPRosterSignalHandler(xmppRoster_); + rosterStorage_ = new RosterMemoryStorage(); jid1_ = JID("foo@bar.com"); jid2_ = JID("alice@wonderland.lit"); jid3_ = JID("jane@austen.lit"); } void tearDown() { + delete rosterStorage_; delete handler_; delete xmppRoster_; delete router_; delete channel_; } + void testGet_Response() { + std::auto_ptr<XMPPRosterController> testling(createController()); + + testling->requestRoster(); + boost::shared_ptr<RosterPayload> payload = boost::make_shared<RosterPayload>(); + payload->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + payload->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), payload)); + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + } + void testGet_EmptyResponse() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); controller.requestRoster(); @@ -55,7 +80,7 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { } void testAdd() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload(new RosterPayload()); payload->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); @@ -68,8 +93,115 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Bob"), xmppRoster_->getNameForJID(jid1_)); } + void testGet_NoRosterInStorage() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *roster->getVersion()); + } + + void testGet_NoVersionInStorage() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + rosterStorage_->setRoster(boost::make_shared<RosterPayload>()); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *roster->getVersion()); + } + + void testGet_VersionInStorage() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> payload(new RosterPayload()); + payload->setVersion("foover"); + rosterStorage_->setRoster(payload); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("foover"), *roster->getVersion()); + } + + void testGet_ServerDoesNotSupportVersion() { + std::auto_ptr<XMPPRosterController> testling(createController()); + boost::shared_ptr<RosterPayload> payload(new RosterPayload()); + payload->setVersion("foover"); + rosterStorage_->setRoster(payload); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(!roster->getVersion()); + } + + void testGet_ResponseWithoutNewVersion() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + storedRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), boost::shared_ptr<RosterPayload>())); + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid2_, handler_->getLastJID()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version10"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + } + + void testGet_ResponseWithNewVersion() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> serverRoster(new RosterPayload()); + serverRoster->setVersion("version12"); + serverRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + std::vector<std::string> groups; + groups.push_back("foo"); + groups.push_back("bar"); + serverRoster->addItem(RosterItemPayload(jid3_, "Rabbit", RosterItemPayload::Both, groups)); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), serverRoster)); + + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(!xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid3_)); + CPPUNIT_ASSERT_EQUAL(jid3_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version12"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(!rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid3_)); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(rosterStorage_->getRoster()->getItem(jid3_)->getGroups().size())); + } + void testModify() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -87,9 +219,9 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Bob2"), xmppRoster_->getNameForJID(jid1_)); } - + void testRemove() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -107,8 +239,31 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { } + void testRemove_RosterStorageUpdated() { + std::auto_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + storedRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), boost::shared_ptr<RosterPayload>())); + + boost::shared_ptr<RosterPayload> payload2(new RosterPayload()); + payload2->setVersion("version15"); + payload2->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Remove)); + channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id2", payload2)); + + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version15"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(!rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + } + void testMany() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -171,12 +326,18 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { handler_->reset(); } + + private: + XMPPRosterController* createController() { + return new XMPPRosterController(router_, xmppRoster_, rosterStorage_); + } private: DummyStanzaChannel* channel_; IQRouter* router_; XMPPRosterImpl* xmppRoster_; XMPPRosterSignalHandler* handler_; + RosterMemoryStorage* rosterStorage_; JID jid1_; JID jid2_; JID jid3_; diff --git a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp new file mode 100644 index 0000000..d89644a --- /dev/null +++ b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010-2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h> + +#include <boost/bind.hpp> +#include <cassert> + +using namespace Swift; + +XMPPRosterSignalHandler::XMPPRosterSignalHandler(Swift::XMPPRoster* roster) : eventCount(0) { + lastEvent_ = None; + roster->onJIDAdded.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDAdded, this, _1)); + roster->onJIDRemoved.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDRemoved, this, _1)); + roster->onJIDUpdated.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDUpdated, this, _1, _2, _3)); +} + +void XMPPRosterSignalHandler::handleJIDUpdated(const Swift::JID& jid, const std::string& oldName, const std::vector<std::string>& oldGroups) { + assert(lastEvent_ == None); + lastJID_ = jid; + lastOldName_ = oldName; + lastOldGroups_ = oldGroups; + lastEvent_ = Update; + eventCount++; +} diff --git a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h index 1bbd8e9..2cf1159 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h +++ b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h @@ -3,34 +3,25 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ + #pragma once -#include <boost/shared_ptr.hpp> -#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> #include <vector> - #include "Swiften/Roster/XMPPRosterImpl.h" -using namespace Swift; - - enum XMPPRosterEvents {None, Add, Remove, Update}; class XMPPRosterSignalHandler { public: - XMPPRosterSignalHandler(XMPPRoster* roster) { - lastEvent_ = None; - roster->onJIDAdded.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDAdded, this, _1)); - roster->onJIDRemoved.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDRemoved, this, _1)); - roster->onJIDUpdated.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDUpdated, this, _1, _2, _3)); - } + XMPPRosterSignalHandler(Swift::XMPPRoster* roster); XMPPRosterEvents getLastEvent() { return lastEvent_; } - JID getLastJID() { + Swift::JID getLastJID() { return lastJID_; } @@ -46,28 +37,28 @@ public: lastEvent_ = None; } + int getEventCount() const { + return eventCount; + } + private: - void handleJIDAdded(const JID& jid) { + void handleJIDAdded(const Swift::JID& jid) { lastJID_ = jid; lastEvent_ = Add; + eventCount++; } - void handleJIDRemoved(const JID& jid) { + void handleJIDRemoved(const Swift::JID& jid) { lastJID_ = jid; lastEvent_ = Remove; + eventCount++; } - void handleJIDUpdated(const JID& jid, const std::string& oldName, const std::vector<std::string>& oldGroups) { - CPPUNIT_ASSERT_EQUAL(None, lastEvent_); - lastJID_ = jid; - lastOldName_ = oldName; - lastOldGroups_ = oldGroups; - lastEvent_ = Update; - } + void handleJIDUpdated(const Swift::JID& jid, const std::string& oldName, const std::vector<std::string>& oldGroups); XMPPRosterEvents lastEvent_; - JID lastJID_; + Swift::JID lastJID_; std::string lastOldName_; std::vector<std::string> lastOldGroups_; - + int eventCount; }; diff --git a/Swiften/Roster/XMPPRosterController.cpp b/Swiften/Roster/XMPPRosterController.cpp index a294d35..bd7e079 100644 --- a/Swiften/Roster/XMPPRosterController.cpp +++ b/Swiften/Roster/XMPPRosterController.cpp @@ -7,20 +7,22 @@ #include "Swiften/Roster/XMPPRosterController.h" #include <boost/bind.hpp> +#include <iostream> #include "Swiften/Base/foreach.h" #include "Swiften/Elements/RosterItemPayload.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Roster/GetRosterRequest.h" #include "Swiften/Roster/XMPPRosterImpl.h" +#include <Swiften/Roster/RosterStorage.h> namespace Swift { /** * The controller does not gain ownership of these parameters. */ -XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRosterImpl* xmppRoster) : iqRouter_(iqRouter), rosterPushResponder_(iqRouter), xmppRoster_(xmppRoster) { - rosterPushResponder_.onRosterReceived.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, false)); +XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRosterImpl* xmppRoster, RosterStorage* rosterStorage) : iqRouter_(iqRouter), rosterPushResponder_(iqRouter), xmppRoster_(xmppRoster), rosterStorage_(rosterStorage), useVersioning(false) { + rosterPushResponder_.onRosterReceived.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, false, boost::shared_ptr<RosterPayload>())); rosterPushResponder_.start(); } @@ -30,12 +32,24 @@ XMPPRosterController::~XMPPRosterController() { void XMPPRosterController::requestRoster() { xmppRoster_->clear(); - GetRosterRequest::ref rosterRequest = GetRosterRequest::create(iqRouter_); - rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, true)); + + boost::shared_ptr<RosterPayload> storedRoster = rosterStorage_->getRoster(); + GetRosterRequest::ref rosterRequest; + if (useVersioning) { + std::string version = ""; + if (storedRoster && storedRoster->getVersion()) { + version = *storedRoster->getVersion(); + } + rosterRequest = GetRosterRequest::create(iqRouter_, version); + } + else { + rosterRequest = GetRosterRequest::create(iqRouter_); + } + rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, true, storedRoster)); rosterRequest->send(); } -void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial) { +void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial, boost::shared_ptr<RosterPayload> previousRoster) { if (rosterPayload) { foreach(const RosterItemPayload& item, rosterPayload->getItems()) { //Don't worry about the updated case, the XMPPRoster sorts that out. @@ -46,9 +60,33 @@ void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> } } } + else if (previousRoster) { + // The cached version hasn't changed; emit all items + foreach(const RosterItemPayload& item, previousRoster->getItems()) { + if (item.getSubscription() != RosterItemPayload::Remove) { + xmppRoster_->addContact(item.getJID(), item.getName(), item.getGroups(), item.getSubscription()); + } + else { + std::cerr << "ERROR: Stored invalid roster item" << std::endl; + } + } + } if (initial) { xmppRoster_->onInitialRosterPopulated(); } + if (rosterPayload && rosterPayload->getVersion() && useVersioning) { + saveRoster(*rosterPayload->getVersion()); + } +} + +void XMPPRosterController::saveRoster(const std::string& version) { + std::vector<XMPPRosterItem> items = xmppRoster_->getItems(); + boost::shared_ptr<RosterPayload> roster(new RosterPayload()); + roster->setVersion(version); + foreach(const XMPPRosterItem& item, items) { + roster->addItem(RosterItemPayload(item.getJID(), item.getName(), item.getSubscription(), item.getGroups())); + } + rosterStorage_->setRoster(roster); } } diff --git a/Swiften/Roster/XMPPRosterController.h b/Swiften/Roster/XMPPRosterController.h index eeb84f6..9313bb6 100644 --- a/Swiften/Roster/XMPPRosterController.h +++ b/Swiften/Roster/XMPPRosterController.h @@ -18,21 +18,29 @@ namespace Swift { class IQRouter; class XMPPRosterImpl; + class RosterStorage; class XMPPRosterController { public: - XMPPRosterController(IQRouter *iqRouter, XMPPRosterImpl* xmppRoster); + XMPPRosterController(IQRouter *iqRouter, XMPPRosterImpl* xmppRoster, RosterStorage* storage); ~XMPPRosterController(); void requestRoster(); + void setUseVersioning(bool b) { + useVersioning = b; + } + private: - void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial); + void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial, boost::shared_ptr<RosterPayload> previousRoster); + void saveRoster(const std::string& version); private: IQRouter* iqRouter_; RosterPushResponder rosterPushResponder_; XMPPRosterImpl* xmppRoster_; + RosterStorage* rosterStorage_; + bool useVersioning; }; } diff --git a/Swiften/SASL/SConscript b/Swiften/SASL/SConscript index 5a0cdef..085e49d 100644 --- a/Swiften/SASL/SConscript +++ b/Swiften/SASL/SConscript @@ -12,6 +12,7 @@ objects = myenv.SwiftenObject([ "DIGESTMD5ClientAuthenticator.cpp", ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) + env.Append(UNITTEST_SOURCES = [ File("UnitTest/PLAINMessageTest.cpp"), File("UnitTest/PLAINClientAuthenticatorTest.cpp"), diff --git a/Swiften/SConscript b/Swiften/SConscript index 9b53e32..c45da6e 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -6,7 +6,7 @@ Import("env") # Flags ################################################################################ -swiften_dep_modules = ["BOOST", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI"] +swiften_dep_modules = ["BOOST", "GCONF", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI"] if env["SCONS_STAGE"] == "flags" : env["SWIFTEN_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift") @@ -77,25 +77,34 @@ if env["SCONS_STAGE"] == "build" : "Client/ClientSessionStanzaChannel.cpp", "Client/CoreClient.cpp", "Client/Client.cpp", + "Client/ClientXMLTracer.cpp", "Client/ClientSession.cpp", "Client/MemoryStorages.cpp", - "Client/FileStorages.cpp", "Client/NickResolver.cpp", "Client/NickManager.cpp", "Client/NickManagerImpl.cpp", + "Client/Storages.cpp", "Compress/ZLibCodecompressor.cpp", "Compress/ZLibDecompressor.cpp", "Compress/ZLibCompressor.cpp", "Elements/DiscoInfo.cpp", + "Elements/Presence.cpp", "Elements/Form.cpp", + "Elements/StreamFeatures.cpp", "Elements/Element.cpp", "Elements/IQ.cpp", "Elements/Payload.cpp", + "Elements/RosterItemExchangePayload.cpp", "Elements/RosterPayload.cpp", "Elements/Stanza.cpp", + "Elements/StatusShow.cpp", + "Elements/StreamManagementEnabled.cpp", + "Elements/StreamResume.cpp", + "Elements/StreamResumed.cpp", "Elements/VCard.cpp", "Elements/MUCOccupant.cpp", "Entity/Entity.cpp", + "Entity/PayloadPersister.cpp", "MUC/MUC.cpp", "MUC/MUCManager.cpp", "MUC/MUCRegistry.cpp", @@ -107,6 +116,8 @@ if env["SCONS_STAGE"] == "build" : "Queries/Requests/GetInBandRegistrationFormRequest.cpp", "Queries/Requests/SubmitInBandRegistrationFormRequest.cpp", "Queries/Responders/SoftwareVersionResponder.cpp", + "Roster/RosterStorage.cpp", + "Roster/RosterMemoryStorage.cpp", "Roster/XMPPRoster.cpp", "Roster/XMPPRosterImpl.cpp", "Roster/XMPPRosterController.cpp", @@ -117,6 +128,9 @@ if env["SCONS_STAGE"] == "build" : "Serializer/CompressRequestSerializer.cpp", "Serializer/ElementSerializer.cpp", "Serializer/MessageSerializer.cpp", + "Serializer/StreamManagementEnabledSerializer.cpp", + "Serializer/StreamResumeSerializer.cpp", + "Serializer/StreamResumedSerializer.cpp", "Serializer/ComponentHandshakeSerializer.cpp", "Serializer/PayloadSerializer.cpp", "Serializer/PayloadSerializerCollection.cpp", @@ -131,6 +145,7 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp", "Serializer/PayloadSerializers/ResourceBindSerializer.cpp", + "Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp", "Serializer/PayloadSerializers/RosterSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp", @@ -160,6 +175,7 @@ if env["SCONS_STAGE"] == "build" : "Server/SimpleUserRegistry.cpp", "Server/UserRegistry.cpp", "Session/Session.cpp", + "Session/SessionTracer.cpp", "Session/SessionStream.cpp", "Session/BasicSessionStream.cpp", "StringCodecs/Base64.cpp", @@ -191,6 +207,7 @@ if env["SCONS_STAGE"] == "build" : "StreamManagement", "Component", "Config", + "AdHoc" ]) SConscript(test_only = True, dirs = [ "QA", @@ -200,6 +217,8 @@ if env["SCONS_STAGE"] == "build" : ]) myenv = swiften_env.Clone() + 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) and myenv["PLATFORM"] == "posix" : myenv.Append(LINKFLAGS = ["-Wl,-soname,$SWIFTEN_LIBRARY_NAME"]) myenv["SHLIBSUFFIX"] = "" @@ -237,8 +256,6 @@ if env["SCONS_STAGE"] == "build" : File("Elements/UnitTest/FormTest.cpp"), File("EventLoop/UnitTest/EventLoopTest.cpp"), File("EventLoop/UnitTest/SimpleEventLoopTest.cpp"), - File("FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp"), - File("FileTransfer/UnitTest/IBBSendSessionTest.cpp"), # File("History/UnitTest/SQLiteHistoryManagerTest.cpp"), File("JID/UnitTest/JIDTest.cpp"), File("LinkLocal/UnitTest/LinkLocalConnectorTest.cpp"), @@ -248,6 +265,8 @@ if env["SCONS_STAGE"] == "build" : File("MUC/UnitTest/MUCTest.cpp"), File("Network/UnitTest/HostAddressTest.cpp"), File("Network/UnitTest/ConnectorTest.cpp"), + File("Network/UnitTest/ChainedConnectorTest.cpp"), + File("Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp"), File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp"), @@ -256,6 +275,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/IBBParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp"), @@ -269,6 +289,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/StorageParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ReplaceTest.cpp"), File("Parser/UnitTest/AttributeMapTest.cpp"), File("Parser/UnitTest/IQParserTest.cpp"), File("Parser/UnitTest/MessageParserTest.cpp"), @@ -278,6 +299,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/UnitTest/SerializingParserTest.cpp"), File("Parser/UnitTest/StanzaParserTest.cpp"), File("Parser/UnitTest/StreamFeaturesParserTest.cpp"), + File("Parser/UnitTest/StreamManagementEnabledParserTest.cpp"), File("Parser/UnitTest/XMLParserTest.cpp"), File("Parser/UnitTest/XMPPParserTest.cpp"), File("Presence/UnitTest/PresenceOracleTest.cpp"), @@ -289,6 +311,7 @@ if env["SCONS_STAGE"] == "build" : File("Queries/UnitTest/ResponderTest.cpp"), File("Roster/UnitTest/XMPPRosterImplTest.cpp"), File("Roster/UnitTest/XMPPRosterControllerTest.cpp"), + File("Roster/UnitTest/XMPPRosterSignalHandler.cpp"), File("Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp"), File("Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp"), @@ -296,6 +319,7 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp"), @@ -309,6 +333,7 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp"), File("Serializer/UnitTest/StreamFeaturesSerializerTest.cpp"), File("Serializer/UnitTest/AuthSuccessSerializerTest.cpp"), File("Serializer/UnitTest/AuthChallengeSerializerTest.cpp"), diff --git a/Swiften/Serializer/IQSerializer.h b/Swiften/Serializer/IQSerializer.h index 21ec300..784ce09 100644 --- a/Swiften/Serializer/IQSerializer.h +++ b/Swiften/Serializer/IQSerializer.h @@ -7,8 +7,6 @@ #ifndef SWIFTEN_IQSerializer_H #define SWIFTEN_IQSerializer_H -#include <cassert> - #include "Swiften/Serializer/GenericStanzaSerializer.h" #include "Swiften/Elements/IQ.h" #include "Swiften/Serializer/XML/XMLElement.h" diff --git a/Swiften/Serializer/PayloadSerializer.h b/Swiften/Serializer/PayloadSerializer.h index 34e6679..c4ad23b 100644 --- a/Swiften/Serializer/PayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializer.h @@ -4,15 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PAYLOADSERIALIZER_H -#define SWIFTEN_PAYLOADSERIALIZER_H - -#include <boost/shared_ptr.hpp> +#pragma once #include <string> -#include "Swiften/Elements/Payload.h" +#include <boost/shared_ptr.hpp> namespace Swift { + class Payload; + class PayloadSerializer { public: virtual ~PayloadSerializer(); @@ -21,5 +20,3 @@ namespace Swift { virtual std::string serialize(boost::shared_ptr<Payload>) const = 0; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp b/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp index 0fa45ce..12a38a8 100644 --- a/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp @@ -21,7 +21,7 @@ CommandSerializer::CommandSerializer() { } std::string CommandSerializer::serializePayload(boost::shared_ptr<Command> command) const { - XMLElement commandElement("command", "http://jabber.org/protocol/comands"); + XMLElement commandElement("command", "http://jabber.org/protocol/commands"); commandElement.setAttribute("node", command->getNode()); if (!command->getSessionID().empty()) { diff --git a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp index 4922042..bdf5505 100644 --- a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp @@ -7,6 +7,7 @@ #include "Swiften/Serializer/PayloadSerializers/DelaySerializer.h" #include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> #include <Swiften/Base/String.h> #include "Swiften/Serializer/XML/XMLElement.h" diff --git a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp index 53b4241..51cb90f 100644 --- a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp @@ -129,14 +129,6 @@ boost::shared_ptr<XMLElement> FormSerializer::fieldToXML(boost::shared_ptr<FormF fieldType = "text-multi"; multiLineify(boost::dynamic_pointer_cast<TextMultiFormField>(field)->getValue(), "value", fieldElement); } - else if (boost::dynamic_pointer_cast<UntypedFormField>(field)) { - std::vector<std::string> lines = boost::dynamic_pointer_cast<UntypedFormField>(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 { assert(false); } diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 1bbcbf2..a1f412b 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -14,6 +14,7 @@ #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/MUCOwnerPayloadSerializer.h" @@ -40,6 +41,7 @@ #include "Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h" #include "Swiften/Serializer/PayloadSerializers/NicknameSerializer.h" #include "Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h" +#include "Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h" namespace Swift { @@ -51,6 +53,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new PrioritySerializer()); serializers_.push_back(new ErrorSerializer()); serializers_.push_back(new RosterSerializer()); + serializers_.push_back(new RosterItemExchangeSerializer()); serializers_.push_back(new MUCPayloadSerializer()); serializers_.push_back(new MUCUserPayloadSerializer()); serializers_.push_back(new MUCOwnerPayloadSerializer(this)); @@ -77,6 +80,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new InBandRegistrationPayloadSerializer()); serializers_.push_back(new NicknameSerializer()); serializers_.push_back(new SearchPayloadSerializer()); + serializers_.push_back(new ReplaceSerializer()); foreach(PayloadSerializer* serializer, serializers_) { addSerializer(serializer); } diff --git a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp index d7e1613..f19874a 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp @@ -6,6 +6,9 @@ #include "Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h" +#include <boost/lexical_cast.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + #include "Swiften/Serializer/XML/XMLElement.h" #include <Swiften/Base/String.h> diff --git a/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h b/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h new file mode 100644 index 0000000..303b2b8 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Serializer/GenericPayloadSerializer.h" +#include "Swiften/Serializer/XML/XMLTextNode.h" +#include "Swiften/Elements/Replace.h" + +namespace Swift { + class ReplaceSerializer : public GenericPayloadSerializer<Replace> { + public: + ReplaceSerializer() : GenericPayloadSerializer<Replace>() {} + + virtual std::string serializePayload(boost::shared_ptr<Replace> replace) const { + return "<replace id = '" + replace->getId() + "' xmlns='http://swift.im/protocol/replace'/>"; + } + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp new file mode 100644 index 0000000..c9ed6ea --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h" + +#include <boost/shared_ptr.hpp> + +#include "Swiften/Base/foreach.h" +#include "Swiften/Serializer/XML/XMLTextNode.h" +#include "Swiften/Serializer/XML/XMLRawTextNode.h" +#include "Swiften/Serializer/XML/XMLElement.h" + +namespace Swift { + +RosterItemExchangeSerializer::RosterItemExchangeSerializer() : GenericPayloadSerializer<RosterItemExchangePayload>() { +} + +std::string RosterItemExchangeSerializer::serializePayload(boost::shared_ptr<RosterItemExchangePayload> roster) const { + XMLElement queryElement("x", "http://jabber.org/protocol/rosterx"); + foreach(const RosterItemExchangePayload::Item& item, roster->getItems()) { + boost::shared_ptr<XMLElement> itemElement(new XMLElement("item")); + itemElement->setAttribute("jid", item.getJID()); + itemElement->setAttribute("name", item.getName()); + + switch (item.getAction()) { + case RosterItemExchangePayload::Item::Add: itemElement->setAttribute("action", "add"); break; + case RosterItemExchangePayload::Item::Modify: itemElement->setAttribute("action", "modify"); break; + case RosterItemExchangePayload::Item::Delete: itemElement->setAttribute("action", "delete"); break; + } + + foreach(const std::string& group, item.getGroups()) { + boost::shared_ptr<XMLElement> groupElement(new XMLElement("group")); + groupElement->addNode(boost::shared_ptr<XMLTextNode>(new XMLTextNode(group))); + itemElement->addNode(groupElement); + } + + queryElement.addNode(itemElement); + } + + return queryElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h new file mode 100644 index 0000000..ec2cc13 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * 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/RosterItemExchangePayload.h" + +namespace Swift { + class RosterItemExchangeSerializer : public GenericPayloadSerializer<RosterItemExchangePayload> { + public: + RosterItemExchangeSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<RosterItemExchangePayload>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp b/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp index 40faf73..886676a 100644 --- a/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp @@ -20,6 +20,9 @@ RosterSerializer::RosterSerializer() : GenericPayloadSerializer<RosterPayload>() std::string RosterSerializer::serializePayload(boost::shared_ptr<RosterPayload> roster) const { XMLElement queryElement("query", "jabber:iq:roster"); + if (roster->getVersion()) { + queryElement.setAttribute("ver", *roster->getVersion()); + } foreach(const RosterItemPayload& item, roster->getItems()) { boost::shared_ptr<XMLElement> itemElement(new XMLElement("item")); itemElement->setAttribute("jid", item.getJID()); diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp index 70fb2ac..ee9f279 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp @@ -49,7 +49,7 @@ std::string StreamInitiationSerializer::serializePayload(boost::shared_ptr<Strea siElement.addNode(fileElement); } - boost::shared_ptr<XMLElement> featureElement(new XMLElement("feature", "http://jabber.org/protocol/feature-neg")); + boost::shared_ptr<XMLElement> featureElement(new XMLElement("feature", FEATURE_NEG_NS)); if (streamInitiation->getProvidedMethods().size() > 0) { Form::ref form(new Form(Form::FormType)); ListSingleFormField::ref field = ListSingleFormField::create(); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp index e4a6661..5b52c0a 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp @@ -96,13 +96,6 @@ class FormSerializerTest : public CppUnit::TestFixture { field->setDescription("Tell all your friends about your new bot!"); form->addField(field); - std::vector<std::string> values2; - values2.push_back("foo"); - values2.push_back("bar"); - field = UntypedFormField::create(values2); - field->setName("fum"); - form->addField(field); - CPPUNIT_ASSERT_EQUAL(std::string( "<x type=\"form\" xmlns=\"jabber:x:data\">" "<field type=\"hidden\" var=\"FORM_TYPE\">" @@ -139,10 +132,6 @@ class FormSerializerTest : public CppUnit::TestFixture { "<value>foo@bar.com</value>" "<value>baz@fum.org</value>" "</field>" - "<field var=\"fum\">" - "<value>foo</value>" - "<value>bar</value>" - "</field>" "</x>"), testling.serialize(form)); } }; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp new file mode 100644 index 0000000..8fe96e5 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * 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/ReplaceSerializer.h" + +using namespace Swift; + +class ReplaceSerializerTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ReplaceSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + ReplaceSerializerTest() {} + + void testSerialize() { + ReplaceSerializer testling; + 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_TEST_SUITE_REGISTRATION(ReplaceSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp new file mode 100644 index 0000000..f4de783 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 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/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h" + +using namespace Swift; + +class RosterItemExchangeSerializerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterItemExchangeSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + RosterItemExchangeSerializerTest() {} + + void testSerialize() { + RosterItemExchangeSerializer testling; + boost::shared_ptr<RosterItemExchangePayload> roster(new RosterItemExchangePayload()); + + RosterItemExchangePayload::Item item1; + item1.setJID("foo@bar.com"); + item1.setName("Foo @ Bar"); + item1.setAction(RosterItemExchangePayload::Item::Add); + item1.addGroup("Group 1"); + item1.addGroup("Group 2"); + roster->addItem(item1); + + RosterItemExchangePayload::Item item2; + item2.setJID("baz@blo.com"); + item2.setName("Baz"); + item2.setAction(RosterItemExchangePayload::Item::Modify); + roster->addItem(item2); + + std::string expectedResult = + "<x xmlns=\"http://jabber.org/protocol/rosterx\">" + "<item action=\"add\" jid=\"foo@bar.com\" name=\"Foo @ Bar\">" + "<group>Group 1</group>" + "<group>Group 2</group>" + "</item>" + "<item action=\"modify\" jid=\"baz@blo.com\" name=\"Baz\"/>" + "</x>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RosterItemExchangeSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp index b8ceac3..61316df 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp @@ -11,16 +11,15 @@ using namespace Swift; -class RosterSerializerTest : public CppUnit::TestFixture -{ +class RosterSerializerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(RosterSerializerTest); CPPUNIT_TEST(testSerialize); CPPUNIT_TEST(testSerialize_ItemWithUnknownContent); + CPPUNIT_TEST(testSerialize_WithVersion); + CPPUNIT_TEST(testSerialize_WithEmptyVersion); CPPUNIT_TEST_SUITE_END(); public: - RosterSerializerTest() {} - void testSerialize() { RosterSerializer testling; boost::shared_ptr<RosterPayload> roster(new RosterPayload()); @@ -77,6 +76,26 @@ class RosterSerializerTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); } + + void testSerialize_WithVersion() { + RosterSerializer testling; + boost::shared_ptr<RosterPayload> roster(new RosterPayload()); + roster->setVersion("ver20"); + + std::string expectedResult = "<query ver=\"ver20\" xmlns=\"jabber:iq:roster\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); + } + + void testSerialize_WithEmptyVersion() { + RosterSerializer testling; + boost::shared_ptr<RosterPayload> roster(new RosterPayload()); + roster->setVersion(""); + + std::string expectedResult = "<query ver=\"\" xmlns=\"jabber:iq:roster\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(RosterSerializerTest); diff --git a/Swiften/Serializer/PresenceSerializer.h b/Swiften/Serializer/PresenceSerializer.h index 3cb9aab..be31597 100644 --- a/Swiften/Serializer/PresenceSerializer.h +++ b/Swiften/Serializer/PresenceSerializer.h @@ -7,8 +7,6 @@ #ifndef SWIFTEN_PresenceSerializer_H #define SWIFTEN_PresenceSerializer_H -#include <cassert> - #include "Swiften/Serializer/GenericStanzaSerializer.h" #include "Swiften/Elements/Presence.h" diff --git a/Swiften/Serializer/StanzaSerializer.cpp b/Swiften/Serializer/StanzaSerializer.cpp index cfc9a43..6bd2ef0 100644 --- a/Swiften/Serializer/StanzaSerializer.cpp +++ b/Swiften/Serializer/StanzaSerializer.cpp @@ -10,6 +10,7 @@ #include <typeinfo> #include <iostream> +#include <Swiften/Base/foreach.h> #include "Swiften/Serializer/XML/XMLElement.h" #include "Swiften/Serializer/XML/XMLRawTextNode.h" #include "Swiften/Serializer/PayloadSerializer.h" diff --git a/Swiften/Serializer/StreamFeaturesSerializer.cpp b/Swiften/Serializer/StreamFeaturesSerializer.cpp index 915433c..11744b4 100644 --- a/Swiften/Serializer/StreamFeaturesSerializer.cpp +++ b/Swiften/Serializer/StreamFeaturesSerializer.cpp @@ -6,6 +6,8 @@ #include "Swiften/Serializer/StreamFeaturesSerializer.h" +#include <boost/smart_ptr/make_shared.hpp> + #include "Swiften/Serializer/XML/XMLElement.h" #include "Swiften/Serializer/XML/XMLTextNode.h" #include "Swiften/Base/foreach.h" @@ -49,6 +51,9 @@ std::string StreamFeaturesSerializer::serialize(boost::shared_ptr<Element> eleme if (streamFeatures->hasStreamManagement()) { streamFeaturesElement.addNode(boost::shared_ptr<XMLElement>(new XMLElement("sm", "urn:xmpp:sm:2"))); } + if (streamFeatures->hasRosterVersioning()) { + streamFeaturesElement.addNode(boost::make_shared<XMLElement>("ver", "urn:xmpp:features:rosterver")); + } return streamFeaturesElement.serialize(); } diff --git a/Swiften/Serializer/StreamManagementEnabledSerializer.cpp b/Swiften/Serializer/StreamManagementEnabledSerializer.cpp new file mode 100644 index 0000000..02cf948 --- /dev/null +++ b/Swiften/Serializer/StreamManagementEnabledSerializer.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/StreamManagementEnabledSerializer.h> + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/StreamManagementEnabled.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +StreamManagementEnabledSerializer::StreamManagementEnabledSerializer() : GenericElementSerializer<StreamManagementEnabled>() { +} + +std::string StreamManagementEnabledSerializer::serialize(boost::shared_ptr<Element> el) const { + boost::shared_ptr<StreamManagementEnabled> e(boost::dynamic_pointer_cast<StreamManagementEnabled>(el)); + XMLElement element("enabled", "urn:xmpp:sm:2"); + if (!e->getResumeID().empty()) { + element.setAttribute("id", e->getResumeID()); + } + if (e->getResumeSupported()) { + element.setAttribute("resume", "true"); + } + return element.serialize(); +} diff --git a/Swiften/Serializer/StreamManagementEnabledSerializer.h b/Swiften/Serializer/StreamManagementEnabledSerializer.h index fc7bd86..8ee9e31 100644 --- a/Swiften/Serializer/StreamManagementEnabledSerializer.h +++ b/Swiften/Serializer/StreamManagementEnabledSerializer.h @@ -10,16 +10,12 @@ #include "Swiften/Elements/StreamManagementEnabled.h" #include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" namespace Swift { class StreamManagementEnabledSerializer : public GenericElementSerializer<StreamManagementEnabled> { public: - StreamManagementEnabledSerializer() : GenericElementSerializer<StreamManagementEnabled>() { - } + StreamManagementEnabledSerializer(); - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("enabled", "urn:xmpp:sm:2").serialize(); - } + virtual std::string serialize(boost::shared_ptr<Element>) const; }; } diff --git a/Swiften/Serializer/StreamResumeSerializer.cpp b/Swiften/Serializer/StreamResumeSerializer.cpp new file mode 100644 index 0000000..a7a2e3b --- /dev/null +++ b/Swiften/Serializer/StreamResumeSerializer.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/StreamResumeSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Elements/StreamResume.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +StreamResumeSerializer::StreamResumeSerializer() : GenericElementSerializer<StreamResume>() { +} + +std::string StreamResumeSerializer::serialize(boost::shared_ptr<Element> 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())); + } + return element.serialize(); +} diff --git a/Swiften/Serializer/StreamResumeSerializer.h b/Swiften/Serializer/StreamResumeSerializer.h new file mode 100644 index 0000000..6ea7365 --- /dev/null +++ b/Swiften/Serializer/StreamResumeSerializer.h @@ -0,0 +1,21 @@ +/* + * 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/Elements/StreamResume.h> +#include <Swiften/Serializer/GenericElementSerializer.h> + +namespace Swift { + class StreamResumeSerializer : public GenericElementSerializer<StreamResume> { + public: + StreamResumeSerializer(); + + virtual std::string serialize(boost::shared_ptr<Element>) const; + }; +} diff --git a/Swiften/Serializer/StreamResumedSerializer.cpp b/Swiften/Serializer/StreamResumedSerializer.cpp new file mode 100644 index 0000000..d3beafb --- /dev/null +++ b/Swiften/Serializer/StreamResumedSerializer.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/StreamResumedSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Elements/StreamResumed.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +StreamResumedSerializer::StreamResumedSerializer() : GenericElementSerializer<StreamResumed>() { +} + +std::string StreamResumedSerializer::serialize(boost::shared_ptr<Element> 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())); + } + return element.serialize(); +} diff --git a/Swiften/Serializer/StreamResumedSerializer.h b/Swiften/Serializer/StreamResumedSerializer.h new file mode 100644 index 0000000..38d846f --- /dev/null +++ b/Swiften/Serializer/StreamResumedSerializer.h @@ -0,0 +1,21 @@ +/* + * 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/Elements/StreamResumed.h> +#include <Swiften/Serializer/GenericElementSerializer.h> + +namespace Swift { + class StreamResumedSerializer : public GenericElementSerializer<StreamResumed> { + public: + StreamResumedSerializer(); + + virtual std::string serialize(boost::shared_ptr<Element>) const; + }; +} diff --git a/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp b/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp index 65caa81..aa896c2 100644 --- a/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp @@ -32,6 +32,7 @@ class StreamFeaturesSerializerTest : public CppUnit::TestFixture streamFeatures->setHasResourceBind(); streamFeatures->setHasSession(); streamFeatures->setHasStreamManagement(); + streamFeatures->setHasRosterVersioning(); CPPUNIT_ASSERT_EQUAL(std::string( "<stream:features>" @@ -47,6 +48,7 @@ class StreamFeaturesSerializerTest : public CppUnit::TestFixture "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>" "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>" "<sm xmlns=\"urn:xmpp:sm:2\"/>" + "<ver xmlns=\"urn:xmpp:features:rosterver\"/>" "</stream:features>"), testling.serialize(streamFeatures)); } }; diff --git a/Swiften/Serializer/XMPPSerializer.cpp b/Swiften/Serializer/XMPPSerializer.cpp index 06f3558..19a30ce 100644 --- a/Swiften/Serializer/XMPPSerializer.cpp +++ b/Swiften/Serializer/XMPPSerializer.cpp @@ -4,36 +4,38 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/XMPPSerializer.h" +#include <Swiften/Serializer/XMPPSerializer.h> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <iostream> #include <cassert> -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/CompressRequestSerializer.h" -#include "Swiften/Serializer/CompressFailureSerializer.h" -#include "Swiften/Serializer/StreamErrorSerializer.h" -#include "Swiften/Serializer/StreamFeaturesSerializer.h" -#include "Swiften/Serializer/AuthRequestSerializer.h" -#include "Swiften/Serializer/AuthFailureSerializer.h" -#include "Swiften/Serializer/AuthSuccessSerializer.h" -#include "Swiften/Serializer/AuthChallengeSerializer.h" -#include "Swiften/Serializer/AuthResponseSerializer.h" -#include "Swiften/Serializer/EnableStreamManagementSerializer.h" -#include "Swiften/Serializer/StreamManagementEnabledSerializer.h" -#include "Swiften/Serializer/StreamManagementFailedSerializer.h" -#include "Swiften/Serializer/StanzaAckSerializer.h" -#include "Swiften/Serializer/StanzaAckRequestSerializer.h" -#include "Swiften/Serializer/StartTLSRequestSerializer.h" -#include "Swiften/Serializer/StartTLSFailureSerializer.h" -#include "Swiften/Serializer/TLSProceedSerializer.h" -#include "Swiften/Serializer/MessageSerializer.h" -#include "Swiften/Serializer/PresenceSerializer.h" -#include "Swiften/Serializer/IQSerializer.h" -#include "Swiften/Serializer/ComponentHandshakeSerializer.h" +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/CompressRequestSerializer.h> +#include <Swiften/Serializer/CompressFailureSerializer.h> +#include <Swiften/Serializer/StreamErrorSerializer.h> +#include <Swiften/Serializer/StreamFeaturesSerializer.h> +#include <Swiften/Serializer/AuthRequestSerializer.h> +#include <Swiften/Serializer/AuthFailureSerializer.h> +#include <Swiften/Serializer/AuthSuccessSerializer.h> +#include <Swiften/Serializer/AuthChallengeSerializer.h> +#include <Swiften/Serializer/AuthResponseSerializer.h> +#include <Swiften/Serializer/EnableStreamManagementSerializer.h> +#include <Swiften/Serializer/StreamManagementEnabledSerializer.h> +#include <Swiften/Serializer/StreamResumeSerializer.h> +#include <Swiften/Serializer/StreamResumedSerializer.h> +#include <Swiften/Serializer/StreamManagementFailedSerializer.h> +#include <Swiften/Serializer/StanzaAckSerializer.h> +#include <Swiften/Serializer/StanzaAckRequestSerializer.h> +#include <Swiften/Serializer/StartTLSRequestSerializer.h> +#include <Swiften/Serializer/StartTLSFailureSerializer.h> +#include <Swiften/Serializer/TLSProceedSerializer.h> +#include <Swiften/Serializer/MessageSerializer.h> +#include <Swiften/Serializer/PresenceSerializer.h> +#include <Swiften/Serializer/IQSerializer.h> +#include <Swiften/Serializer/ComponentHandshakeSerializer.h> namespace Swift { @@ -56,6 +58,8 @@ XMPPSerializer::XMPPSerializer(PayloadSerializerCollection* payloadSerializers, serializers_.push_back(boost::make_shared<EnableStreamManagementSerializer>()); serializers_.push_back(boost::make_shared<StreamManagementEnabledSerializer>()); serializers_.push_back(boost::make_shared<StreamManagementFailedSerializer>()); + serializers_.push_back(boost::make_shared<StreamResumeSerializer>()); + serializers_.push_back(boost::make_shared<StreamResumedSerializer>()); serializers_.push_back(boost::make_shared<StanzaAckSerializer>()); serializers_.push_back(boost::make_shared<StanzaAckRequestSerializer>()); serializers_.push_back(boost::make_shared<ComponentHandshakeSerializer>()); diff --git a/Swiften/Session/SessionTracer.cpp b/Swiften/Session/SessionTracer.cpp new file mode 100644 index 0000000..6d41e40 --- /dev/null +++ b/Swiften/Session/SessionTracer.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Session/SessionTracer.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +SessionTracer::SessionTracer(boost::shared_ptr<Session> session) : session(session) { + session->onDataRead.connect(boost::bind(&SessionTracer::printData, this, '<', _1)); + session->onDataWritten.connect(boost::bind(&SessionTracer::printData, this, '>', _1)); +} + +void SessionTracer::printData(char direction, const ByteArray& data) { + std::cerr << direction << direction << " " << session->getLocalJID() << " "; + for (unsigned int i = 0; i < 72 - session->getLocalJID().toString().size() - session->getRemoteJID().toString().size(); ++i) { + std::cerr << direction; + } + std::cerr << " " << session->getRemoteJID()<< " " << direction << direction << std::endl; + std::cerr << data.toString() << std::endl; +} + +} diff --git a/Swiften/Session/SessionTracer.h b/Swiften/Session/SessionTracer.h index cce45eb..51b8d16 100644 --- a/Swiften/Session/SessionTracer.h +++ b/Swiften/Session/SessionTracer.h @@ -6,29 +6,18 @@ #pragma once -#include <iostream> +#include <string> #include "Swiften/Session/Session.h" -#include <string> #include "Swiften/Base/ByteArray.h" namespace Swift { class SessionTracer { public: - SessionTracer(boost::shared_ptr<Session> session) : session(session) { - session->onDataRead.connect(boost::bind(&SessionTracer::printData, this, '<', _1)); - session->onDataWritten.connect(boost::bind(&SessionTracer::printData, this, '>', _1)); - } + SessionTracer(boost::shared_ptr<Session> session); private: - void printData(char direction, const ByteArray& data) { - std::cerr << direction << direction << " " << session->getLocalJID() << " "; - for (unsigned int i = 0; i < 72 - session->getLocalJID().toString().size() - session->getRemoteJID().toString().size(); ++i) { - std::cerr << direction; - } - std::cerr << " " << session->getRemoteJID()<< " " << direction << direction << std::endl; - std::cerr << data.toString() << std::endl; - } + void printData(char direction, const ByteArray& data); boost::shared_ptr<Session> session; }; diff --git a/Swiften/StreamManagement/StanzaAckRequester.cpp b/Swiften/StreamManagement/StanzaAckRequester.cpp index f7d603b..4b626c9 100644 --- a/Swiften/StreamManagement/StanzaAckRequester.cpp +++ b/Swiften/StreamManagement/StanzaAckRequester.cpp @@ -7,6 +7,7 @@ #include "Swiften/StreamManagement/StanzaAckRequester.h" #include <boost/numeric/conversion/cast.hpp> +#include <iostream> #include "Swiften/Elements/Message.h" diff --git a/Swiften/StreamStack/CompressionLayer.h b/Swiften/StreamStack/CompressionLayer.h index b8293a8..7d8656e 100644 --- a/Swiften/StreamStack/CompressionLayer.h +++ b/Swiften/StreamStack/CompressionLayer.h @@ -27,7 +27,7 @@ namespace Swift { try { writeDataToChildLayer(compressor_.process(data)); } - catch (const ZLibException& e) { + catch (const ZLibException&) { onError(); } } @@ -36,7 +36,7 @@ namespace Swift { try { writeDataToParentLayer(decompressor_.process(data)); } - catch (const ZLibException& e) { + catch (const ZLibException&) { onError(); } } diff --git a/Swiften/StreamStack/ConnectionLayer.cpp b/Swiften/StreamStack/ConnectionLayer.cpp new file mode 100644 index 0000000..00b4289 --- /dev/null +++ b/Swiften/StreamStack/ConnectionLayer.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/StreamStack/ConnectionLayer.h> +#include <boost/bind.hpp> + +namespace Swift { + +ConnectionLayer::ConnectionLayer(boost::shared_ptr<Connection> connection) : connection(connection) { + connection->onDataRead.connect(boost::bind(&ConnectionLayer::writeDataToParentLayer, this, _1)); +} + +ConnectionLayer::~ConnectionLayer() { + connection->onDataRead.disconnect(boost::bind(&ConnectionLayer::writeDataToParentLayer, this, _1)); +} + + +} diff --git a/Swiften/StreamStack/ConnectionLayer.h b/Swiften/StreamStack/ConnectionLayer.h index 0da0900..bd9c093 100644 --- a/Swiften/StreamStack/ConnectionLayer.h +++ b/Swiften/StreamStack/ConnectionLayer.h @@ -6,9 +6,7 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" #include <boost/shared_ptr.hpp> -#include <boost/bind.hpp> #include "Swiften/StreamStack/LowLayer.h" #include "Swiften/Network/Connection.h" @@ -16,13 +14,8 @@ namespace Swift { class ConnectionLayer : public LowLayer { public: - ConnectionLayer(boost::shared_ptr<Connection> connection) : connection(connection) { - connection->onDataRead.connect(boost::bind(&ConnectionLayer::writeDataToParentLayer, this, _1)); - } - - ~ConnectionLayer() { - connection->onDataRead.disconnect(boost::bind(&ConnectionLayer::writeDataToParentLayer, this, _1)); - } + ConnectionLayer(boost::shared_ptr<Connection> connection); + ~ConnectionLayer(); void writeData(const ByteArray& data) { connection->write(data); diff --git a/Swiften/StreamStack/SConscript b/Swiften/StreamStack/SConscript index 022c695..06fcc03 100644 --- a/Swiften/StreamStack/SConscript +++ b/Swiften/StreamStack/SConscript @@ -6,6 +6,7 @@ sources = [ "HighLayer.cpp", "LowLayer.cpp", "StreamStack.cpp", + "ConnectionLayer.cpp", "TLSLayer.cpp", "WhitespacePingLayer.cpp", "XMPPLayer.cpp", diff --git a/Swiften/StreamStack/StreamStack.h b/Swiften/StreamStack/StreamStack.h index 562245e..c9ebecd 100644 --- a/Swiften/StreamStack/StreamStack.h +++ b/Swiften/StreamStack/StreamStack.h @@ -11,7 +11,6 @@ #include <vector> #include "Swiften/Elements/Stanza.h" -#include "Swiften/Base/foreach.h" namespace Swift { class XMPPLayer; @@ -30,8 +29,8 @@ namespace Swift { } template<typename T> T* getLayer() { - foreach(StreamLayer* streamLayer, layers_) { - T* layer = dynamic_cast<T*>(streamLayer); + for (size_t i = 0; i < layers_.size(); ++i) { + T* layer = dynamic_cast<T*>(layers_[i]); if (layer) { return layer; } diff --git a/Swiften/StringCodecs/SHA1.cpp b/Swiften/StringCodecs/SHA1.cpp index 9882f70..2703796 100644 --- a/Swiften/StringCodecs/SHA1.cpp +++ b/Swiften/StringCodecs/SHA1.cpp @@ -4,10 +4,14 @@ * 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> @@ -25,21 +29,9 @@ A million repetitions of "a" /* #define LITTLE_ENDIAN * This should be #define'd if true. */ /* #define SHA1HANDSOFF * Copies data before messing with it. */ -#include <boost/cstdint.hpp> #include <stdio.h> #include <string.h> -typedef struct { - boost::uint32_t state[5]; - boost::uint32_t count[2]; - boost::uint8_t buffer[64]; -} SHA1_CTX; - -void SHA1Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, boost::uint8_t* data, unsigned int len); -void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context); - #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ @@ -63,7 +55,7 @@ void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context); /* Hash a single 512-bit block. This is the core of the algorithm. */ -void SHA1Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]) +void SHA1::Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]) { boost::uint32_t a, b, c, d, e; typedef union { @@ -118,7 +110,7 @@ static boost::uint8_t workspace[64]; /* SHA1Init - Initialize new context */ -void SHA1Init(SHA1_CTX* context) +void SHA1::Init(SHA1::CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; @@ -132,7 +124,7 @@ void SHA1Init(SHA1_CTX* context) /* Run your data through this. */ -void SHA1Update(SHA1_CTX* context, boost::uint8_t* data, unsigned int len) +void SHA1::Update(SHA1::CTX* context, boost::uint8_t* data, unsigned int len) { unsigned int i, j; @@ -141,9 +133,9 @@ unsigned int i, j; context->count[1] += (len >> 29); if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); + Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); + Transform(context->state, &data[i]); } j = 0; } @@ -154,7 +146,7 @@ unsigned int i, j; /* Add padding and return the message digest. */ -void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context) +void SHA1::Final(boost::uint8_t digest[20], SHA1::CTX* context) { boost::uint32_t i, j; boost::uint8_t finalcount[8]; @@ -163,11 +155,11 @@ boost::uint8_t finalcount[8]; finalcount[i] = (boost::uint8_t) ((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } - SHA1Update(context, (boost::uint8_t *)("\200"), 1); + Update(context, (boost::uint8_t *)("\200"), 1); while ((context->count[0] & 504) != 448) { - SHA1Update(context, (boost::uint8_t *)("\0"), 1); + Update(context, (boost::uint8_t *)("\0"), 1); } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + 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); @@ -179,24 +171,43 @@ boost::uint8_t finalcount[8]; memset(context->count, 0, 8); memset(&finalcount, 0, 8); #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); + Transform(context->state, context->buffer); #endif } // ----------------------------------------------------------------------------- -#include "Swiften/StringCodecs/SHA1.h" - 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*) ByteArray::data(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*) ByteArray::data(digest), &contextCopy); + return digest; +} + ByteArray SHA1::getHash(const ByteArray& input) { - ByteArray inputCopy(input); + CTX context; + Init(&context); + + std::vector<unsigned char> inputCopy(input.getVector()); + Update(&context, (boost::uint8_t*) ByteArray::data(inputCopy), inputCopy.size()); + ByteArray digest; digest.resize(20); - SHA1_CTX context; - SHA1Init(&context); - SHA1Update(&context, (boost::uint8_t*) inputCopy.getData(), inputCopy.getSize()); - SHA1Final((boost::uint8_t*) digest.getData(), &context); + Final((boost::uint8_t*) digest.getData(), &context); + return digest; } diff --git a/Swiften/StringCodecs/SHA1.h b/Swiften/StringCodecs/SHA1.h index fc5ba0e..9c0232a 100644 --- a/Swiften/StringCodecs/SHA1.h +++ b/Swiften/StringCodecs/SHA1.h @@ -6,11 +6,38 @@ #pragma once +#include <vector> +#include <boost/cstdint.hpp> + #include "Swiften/Base/ByteArray.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); + + 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); + + private: + CTX context; }; } diff --git a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp index 9434235..984f512 100644 --- a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp +++ b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp @@ -16,18 +16,65 @@ using namespace Swift; class SHA1Test : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(SHA1Test); CPPUNIT_TEST(testGetHash); - CPPUNIT_TEST(testGetHash_Twice); + 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(ByteArray::create("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(ByteArray::create("\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(ByteArray::create("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); + sha.update(ByteArray::create("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(ByteArray::create("\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(ByteArray::create("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(ByteArray::create("\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(ByteArray::create("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); + sha.getHash(); + sha.update(ByteArray::create("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(ByteArray::create("\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(ByteArray::create("\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("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(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); } - void testGetHash_Twice() { + void testGetHashStatic_Twice() { ByteArray input("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)); @@ -35,7 +82,7 @@ class SHA1Test : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); } - void testGetHash_NoData() { + void testGetHashStatic_NoData() { ByteArray result(SHA1::getHash(ByteArray())); CPPUNIT_ASSERT_EQUAL(ByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), result); diff --git a/Swiften/VCards/SConscript b/Swiften/VCards/SConscript index e980ba3..c20c17d 100644 --- a/Swiften/VCards/SConscript +++ b/Swiften/VCards/SConscript @@ -3,6 +3,5 @@ Import("swiften_env") objects = swiften_env.SwiftenObject([ "VCardManager.cpp", "VCardStorage.cpp", - "VCardFileStorage.cpp", ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/VCards/VCardFileStorage.cpp b/Swiften/VCards/VCardFileStorage.cpp deleted file mode 100644 index a246838..0000000 --- a/Swiften/VCards/VCardFileStorage.cpp +++ /dev/null @@ -1,129 +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/VCards/VCardFileStorage.h" - -#include <boost/filesystem/fstream.hpp> - -#include <Swiften/Base/String.h> -#include <Swiften/StringCodecs/Hexify.h> -#include <Swiften/StringCodecs/SHA1.h> -#include <Swiften/Base/foreach.h> -#include "Swiften/JID/JID.h" -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/VCard.h" -#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h" -#include "Swiften/Parser/PayloadParsers/VCardParser.h" - -namespace Swift { - -VCardFileStorage::VCardFileStorage(boost::filesystem::path dir) : vcardsPath(dir) { - cacheFile = vcardsPath / "phashes"; - if (boost::filesystem::exists(cacheFile)) { - try { - boost::filesystem::ifstream file(cacheFile); - std::string line; - if (file.is_open()) { - while (!file.eof()) { - getline(file, line); - std::pair<std::string, std::string> r = String::getSplittedAtFirst(line, ' '); - JID jid(r.second); - if (jid.isValid()) { - photoHashes.insert(std::make_pair(jid, r.first)); - } - else if (!r.first.empty() || !r.second.empty()) { - std::cerr << "Invalid entry in phashes file" << std::endl; - } - } - } - } - catch (...) { - std::cerr << "Error reading phashes file" << std::endl; - } - } -} - -boost::shared_ptr<VCard> VCardFileStorage::getVCard(const JID& jid) const { - boost::filesystem::path vcardPath(getVCardPath(jid)); - if (boost::filesystem::exists(vcardPath)) { - ByteArray data; - data.readFromFile(vcardPath.string()); - - VCardParser parser; - PayloadParserTester tester(&parser); - tester.parse(data.toString()); - return boost::dynamic_pointer_cast<VCard>(parser.getPayload()); - } - else { - return boost::shared_ptr<VCard>(); - } -} - -void VCardFileStorage::setVCard(const JID& jid, VCard::ref v) { - boost::filesystem::path vcardPath(getVCardPath(jid)); - if (!boost::filesystem::exists(vcardPath.parent_path())) { - try { - boost::filesystem::create_directories(vcardPath.parent_path()); - } - catch (const boost::filesystem::filesystem_error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - } - } - boost::filesystem::ofstream file(getVCardPath(jid)); - file << VCardSerializer().serializePayload(v); - file.close(); - getAndUpdatePhotoHash(jid, v); -} - -boost::filesystem::path VCardFileStorage::getVCardPath(const JID& jid) const { - std::string file(jid.toString()); - String::replaceAll(file, '/', "%2f"); - return boost::filesystem::path(vcardsPath / (file + ".xml")); -} - -std::string VCardFileStorage::getPhotoHash(const JID& jid) const { - PhotoHashMap::const_iterator i = photoHashes.find(jid); - if (i != photoHashes.end()) { - return i->second; - } - else { - VCard::ref vCard = getVCard(jid); - return getAndUpdatePhotoHash(jid, vCard); - } -} - -std::string VCardFileStorage::getAndUpdatePhotoHash(const JID& jid, VCard::ref vCard) const { - std::string hash; - if (vCard && !vCard->getPhoto().isEmpty()) { - hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); - } - std::pair<PhotoHashMap::iterator, bool> r = photoHashes.insert(std::make_pair(jid, hash)); - if (r.second) { - savePhotoHashes(); - } - else if (r.first->second != hash) { - r.first->second = hash; - savePhotoHashes(); - } - return hash; -} - -void VCardFileStorage::savePhotoHashes() const { - try { - boost::filesystem::ofstream file(cacheFile); - for (PhotoHashMap::const_iterator i = photoHashes.begin(); i != photoHashes.end(); ++i) { - file << i->second << " " << i->first.toString() << std::endl; - } - file.close(); - } - catch (...) { - std::cerr << "Error writing vcards file" << std::endl; - } -} - - -} diff --git a/Swiften/VCards/VCardFileStorage.h b/Swiften/VCards/VCardFileStorage.h deleted file mode 100644 index 26bf4b2..0000000 --- a/Swiften/VCards/VCardFileStorage.h +++ /dev/null @@ -1,38 +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/shared_ptr.hpp> -#include <boost/filesystem.hpp> -#include <string> -#include <map> - -#include "Swiften/VCards/VCardStorage.h" - -namespace Swift { - class VCardFileStorage : public VCardStorage { - public: - VCardFileStorage(boost::filesystem::path dir); - - virtual VCard::ref getVCard(const JID& jid) const; - virtual void setVCard(const JID& jid, VCard::ref v); - - virtual std::string getPhotoHash(const JID&) const; - - private: - boost::filesystem::path getVCardPath(const JID&) const; - - std::string getAndUpdatePhotoHash(const JID& jid, VCard::ref vcard) const; - void savePhotoHashes() const; - - private: - boost::filesystem::path vcardsPath; - boost::filesystem::path cacheFile; - typedef std::map<JID, std::string> PhotoHashMap; - mutable PhotoHashMap photoHashes; - }; -} |