diff options
25 files changed, 676 insertions, 6 deletions
diff --git a/BuildTools/scons2ninja.py b/BuildTools/scons2ninja.py index 2666ae6..0ca3e42 100755 --- a/BuildTools/scons2ninja.py +++ b/BuildTools/scons2ninja.py @@ -343,6 +343,9 @@ ninja.rule('generator', generator = '1', description = 'Regenerating build.ninja') +ninja.rule('sdef', + command = 'sdef $in | sdp -fh --basename $basename -o $outdir', + description = 'SDEF $out') ################################################################################ # Build Statements @@ -580,6 +583,15 @@ for line in build_lines : files, flags = extract_non_flags(flags) ninja.build(out, 'dsymutil', files, dsymutilflags = flags) + elif tool == 'sdef' : + source = flags[0]; + outdir, flags = extract_binary_flag("-o", flags) + basename, flags = extract_binary_flag("--basename", flags) + ninja.build(os.path.join(outdir, basename + ".h"), 'sdef', [source], + basename = basename, + outdir = outdir) + + elif not ninja_custom_command(ninja, line) : raise Exception("Unknown tool: '" + line + "'") diff --git a/Sluift/.gitignore b/Sluift/.gitignore index e2d8bbf..4e4c2a4 100644 --- a/Sluift/.gitignore +++ b/Sluift/.gitignore @@ -4,5 +4,6 @@ sluift_dll.cpp sluift dll.c core.c +iTunes.h dll/ exe/ diff --git a/Sluift/ElementConvertors/ElementConvertors.ipp b/Sluift/ElementConvertors/ElementConvertors.ipp index b7b9166..da25eb6 100644 --- a/Sluift/ElementConvertors/ElementConvertors.ipp +++ b/Sluift/ElementConvertors/ElementConvertors.ipp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Remko Tronçon + * Copyright (c) 2013-2014 Remko Tronçon * Licensed under the GNU General Public License. * See the COPYING file for more information. */ @@ -10,6 +10,7 @@ #include <Sluift/ElementConvertors/PubSubItemsConvertor.h> #include <Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h> #include <Sluift/ElementConvertors/PubSubEventRedirectConvertor.h> +#include <Sluift/ElementConvertors/UserTuneConvertor.h> #include <Sluift/ElementConvertors/PubSubConfigureConvertor.h> #include <Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h> #include <Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h> @@ -48,6 +49,7 @@ void LuaElementConvertors::registerConvertors() { convertors.push_back(boost::make_shared<PubSubItemsConvertor>(this)); convertors.push_back(boost::make_shared<PubSubOwnerRedirectConvertor>(this)); convertors.push_back(boost::make_shared<PubSubEventRedirectConvertor>(this)); + convertors.push_back(boost::make_shared<UserTuneConvertor>(this)); convertors.push_back(boost::make_shared<PubSubConfigureConvertor>(this)); convertors.push_back(boost::make_shared<PubSubEventDisassociateConvertor>(this)); convertors.push_back(boost::make_shared<PubSubOwnerAffiliationsConvertor>(this)); diff --git a/Sluift/ElementConvertors/SConscript b/Sluift/ElementConvertors/SConscript index e98f7c4..921e325 100644 --- a/Sluift/ElementConvertors/SConscript +++ b/Sluift/ElementConvertors/SConscript @@ -8,6 +8,7 @@ convertors = [ env.File("PubSubItemsConvertor.cpp"), env.File("PubSubOwnerRedirectConvertor.cpp"), env.File("PubSubEventRedirectConvertor.cpp"), + env.File("UserTuneConvertor.cpp"), env.File("PubSubConfigureConvertor.cpp"), env.File("PubSubEventDisassociateConvertor.cpp"), env.File("PubSubOwnerAffiliationsConvertor.cpp"), diff --git a/Sluift/ElementConvertors/UserTuneConvertor.cpp b/Sluift/ElementConvertors/UserTuneConvertor.cpp new file mode 100644 index 0000000..22ca94e --- /dev/null +++ b/Sluift/ElementConvertors/UserTuneConvertor.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ElementConvertors/UserTuneConvertor.h> + +#include <lua.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/numeric/conversion/cast.hpp> + + + +#pragma clang diagnostic ignored "-Wunused-private-field" + +using namespace Swift; + +UserTuneConvertor::UserTuneConvertor(LuaElementConvertors* convertors) : + GenericLuaElementConvertor<UserTune>("user_tune"), + convertors(convertors) { +} + +UserTuneConvertor::~UserTuneConvertor() { +} + +boost::shared_ptr<UserTune> UserTuneConvertor::doConvertFromLua(lua_State* L) { + boost::shared_ptr<UserTune> result = boost::make_shared<UserTune>(); + lua_getfield(L, -1, "rating"); + if (lua_isnumber(L, -1)) { + result->setRating(boost::numeric_cast<unsigned int>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "title"); + if (lua_isstring(L, -1)) { + result->setTitle(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "track"); + if (lua_isstring(L, -1)) { + result->setTrack(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "artist"); + if (lua_isstring(L, -1)) { + result->setArtist(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "uri"); + if (lua_isstring(L, -1)) { + result->setURI(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "source"); + if (lua_isstring(L, -1)) { + result->setSource(std::string(lua_tostring(L, -1))); + } + lua_pop(L, 1); + lua_getfield(L, -1, "length"); + if (lua_isnumber(L, -1)) { + result->setLength(boost::numeric_cast<unsigned int>(lua_tonumber(L, -1))); + } + lua_pop(L, 1); + return result; +} + +void UserTuneConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<UserTune> payload) { + lua_createtable(L, 0, 0); + if (payload->getRating()) { + lua_pushnumber(L, (*payload->getRating())); + lua_setfield(L, -2, "rating"); + } + if (payload->getTitle()) { + lua_pushstring(L, (*payload->getTitle()).c_str()); + lua_setfield(L, -2, "title"); + } + if (payload->getTrack()) { + lua_pushstring(L, (*payload->getTrack()).c_str()); + lua_setfield(L, -2, "track"); + } + if (payload->getArtist()) { + lua_pushstring(L, (*payload->getArtist()).c_str()); + lua_setfield(L, -2, "artist"); + } + if (payload->getURI()) { + lua_pushstring(L, (*payload->getURI()).c_str()); + lua_setfield(L, -2, "uri"); + } + if (payload->getSource()) { + lua_pushstring(L, (*payload->getSource()).c_str()); + lua_setfield(L, -2, "source"); + } + if (payload->getLength()) { + lua_pushnumber(L, (*payload->getLength())); + lua_setfield(L, -2, "length"); + } +} + +boost::optional<LuaElementConvertor::Documentation> UserTuneConvertor::getDocumentation() const { + return Documentation( + "UserTune", + "This table has the following fields:\n\n" + "- `rating`: number (Optional)\n" + "- `title`: string (Optional)\n" + "- `track`: string (Optional)\n" + "- `artist`: string (Optional)\n" + "- `uri`: string (Optional)\n" + "- `source`: string (Optional)\n" + "- `length`: number (Optional)\n" + ); +} diff --git a/Sluift/ElementConvertors/UserTuneConvertor.h b/Sluift/ElementConvertors/UserTuneConvertor.h new file mode 100644 index 0000000..6f95164 --- /dev/null +++ b/Sluift/ElementConvertors/UserTuneConvertor.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> + +#include <Sluift/GenericLuaElementConvertor.h> +#include <Swiften/Elements/UserTune.h> + +namespace Swift { + class LuaElementConvertors; + + class UserTuneConvertor : public GenericLuaElementConvertor<UserTune> { + public: + UserTuneConvertor(LuaElementConvertors* convertors); + virtual ~UserTuneConvertor(); + + virtual boost::shared_ptr<UserTune> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE; + virtual void doConvertToLua(lua_State*, boost::shared_ptr<UserTune>) SWIFTEN_OVERRIDE; + virtual boost::optional<Documentation> getDocumentation() const SWIFTEN_OVERRIDE; + + private: + LuaElementConvertors* convertors; + }; +} diff --git a/Sluift/Examples/Tunes.lua b/Sluift/Examples/Tunes.lua new file mode 100644 index 0000000..37ad996 --- /dev/null +++ b/Sluift/Examples/Tunes.lua @@ -0,0 +1,68 @@ +--[[ + Copyright (c) 2014 Remko Tronçon + Licensed under the GNU General Public License v3. + See Documentation/Licenses/GPLv3.txt for more information. +--]] + +--[[ + + Tune Publisher/Listener + + Publishes the currently playing tune in iTunes, and prints + the playing tunes of contacts + + The following environment variables are used: + - SLUIFT_JID, SWIFT_PASS: JID and password to log in with + - SLUIFT_DEBUG: Sets whether debugging should be turned on + +--]] + +require 'sluift' + +sluift.debug = os.getenv('SLUIFT_DEBUG') or false + +client = sluift.new_client(os.getenv('SLUIFT_JID'), os.getenv('SLUIFT_PASS')) +client:connect(function (c) + -- Send initial presence (with service discovery information) + c:set_caps_node('http://swift.im/Tunes') + c:set_disco_info{ + identities = {{name = 'Tunes'}}, + features = { + sluift.disco.features.DISCO_INFO, + sluift.disco.features.USER_TUNE .. '+notify' + }} + c:send_presence{priority = -1} + + local pubsub = c:pubsub(sluift.jid.to_bare(c:jid())) + local tunes_node = pubsub:node(sluift.disco.features.USER_TUNE) + local current_track = nil + while true do + -- Publish currently playing tune + if sluift.itunes then + local track = sluift.itunes.get_current_track() + if track ~= current_track then + tunes_node:publish{item = { + _type = 'user_tune', + title = track.name, + artist = track.artist, + track = track.track_number, + source = track.album, + length = track.length, + rating = track.rating and track.rating / 10 or nil + }} + current_track = track + end + end + + -- Print incoming events for a while + for event in c:pubsub_events{timeout = 1000} do + if event._type == 'pubsub_event_items' + and event.node == sluift.disco.features.USER_TUNE + and event.item.title then + print(event.from .. ' is playing "' + .. (event.item.artist or '<Unknown Artist>') .. ' - ' + .. event.item.title .. '"') + end + end + end +end) diff --git a/Sluift/ITunesInterface.h b/Sluift/ITunesInterface.h new file mode 100644 index 0000000..c3cccd2 --- /dev/null +++ b/Sluift/ITunesInterface.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> + +#include <boost/shared_ptr.hpp> +#include <boost/optional/optional_fwd.hpp> + +namespace Swift { + class SWIFTEN_API ITunesInterface { + public: + struct Track { + std::string name; + std::string artist; + std::string album; + long trackNumber; + double duration; + long rating; + }; + + ITunesInterface(); + virtual ~ITunesInterface(); + + boost::optional<Track> getCurrentTrack() const; + + private: + bool haveApplication() const; + + private: + struct Private; + boost::shared_ptr<Private> p; + }; +} diff --git a/Sluift/ITunesInterface.mm b/Sluift/ITunesInterface.mm new file mode 100644 index 0000000..19c6253 --- /dev/null +++ b/Sluift/ITunesInterface.mm @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/ITunesInterface.h> + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfour-char-constants" +#import <Sluift/iTunes.h> +#pragma clang diagnostic pop +#include <ScriptingBridge/ScriptingBridge.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/optional.hpp> +#include <SwifTools/Cocoa/CocoaUtil.h> + +using namespace Swift; + +struct ITunesInterface::Private { + Private() : iTunes(nil) { + } + + iTunesApplication* iTunes; +}; + +ITunesInterface::ITunesInterface() : p(boost::make_shared<Private>()) { +} + +ITunesInterface::~ITunesInterface() { +} + +boost::optional<ITunesInterface::Track> ITunesInterface::getCurrentTrack() const { + if (!haveApplication()) { + return boost::optional<ITunesInterface::Track>(); + } + iTunesTrack* currentTrack = p->iTunes.currentTrack; + if (!currentTrack) { + return boost::optional<ITunesInterface::Track>(); + } + ITunesInterface::Track result; + result.name = NS2STDSTRING(currentTrack.name); + result.artist = NS2STDSTRING(currentTrack.artist); + result.album = NS2STDSTRING(currentTrack.album); + result.trackNumber = currentTrack.trackNumber; + result.duration = currentTrack.duration; + result.rating = currentTrack.rating; + return result; +} + + +bool ITunesInterface::haveApplication() const { + if (!p->iTunes) { + p->iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; + } + return p->iTunes != nil && [p->iTunes isRunning]; +} diff --git a/Sluift/Lua/LuaUtils.cpp b/Sluift/Lua/LuaUtils.cpp index 2192689..915f3cc 100644 --- a/Sluift/Lua/LuaUtils.cpp +++ b/Sluift/Lua/LuaUtils.cpp @@ -32,6 +32,17 @@ void Swift::Lua::registerTableToString(lua_State* L, int index) { lua_pop(L, 1); } +void Swift::Lua::registerTableEquals(lua_State* L, int index) { + index = Lua::absoluteOffset(L, index); + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex); + lua_getfield(L, -1, "register_table_equals"); + lua_pushvalue(L, index); + if (lua_pcall(L, 1, 0, 0) != 0) { + throw Lua::Exception(lua_tostring(L, -1)); + } + lua_pop(L, 1); +} + void Swift::Lua::registerGetByTypeIndex(lua_State* L, int index) { index = Lua::absoluteOffset(L, index); lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex); diff --git a/Sluift/Lua/LuaUtils.h b/Sluift/Lua/LuaUtils.h index 19ab74e..105f249 100644 --- a/Sluift/Lua/LuaUtils.h +++ b/Sluift/Lua/LuaUtils.h @@ -23,6 +23,7 @@ namespace Swift { int convertTableToString(lua_State* L); void registerTableToString(lua_State* L, int index); + void registerTableEquals(lua_State* L, int index); void registerGetByTypeIndex(lua_State* L, int index); void registerHelp(lua_State* L, int index, const std::string& description, const std::string& parameters, const std::string& options); diff --git a/Sluift/SConscript b/Sluift/SConscript index c2bbff5..3cc1f29 100644 --- a/Sluift/SConscript +++ b/Sluift/SConscript @@ -1,6 +1,6 @@ import Version, os.path -Import(["env", "conf_env"]) +Import(["env"]) if env["SCONS_STAGE"] == "build" and not GetOption("help") and not env.get("HAVE_LUA", 0) : print "Warning: Lua was not found. Sluift will not be built." @@ -42,6 +42,8 @@ elif env["SCONS_STAGE"] == "build" : ] sluift_sources += env.SConscript("ElementConvertors/SConscript") + + sluift_env = env.Clone() sluift_env.UseFlags(env.get("LUA_FLAGS", {})) sluift_env.UseFlags(env["SWIFTEN_FLAGS"]) @@ -51,6 +53,13 @@ elif env["SCONS_STAGE"] == "build" : if sluift_env["PLATFORM"] == "win32" : sluift_env.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"]) + if sluift_env["PLATFORM"] == "darwin" and os.path.isdir("/Applications/iTunes.app") : + sluift_env.Append(FRAMEWORKS = ["ScriptingBridge"]) + sluift_env.Command("iTunes.h", "/Applications/iTunes.app", + "sdef ${SOURCE} | sdp -fh --basename iTunes -o ${TARGET.dir}") + sluift_env.Append(CPPDEFINES = ["HAVE_ITUNES"]) + sluift_sources += ["ITunesInterface.mm"] + # Generate Version.h version_header = "#pragma once\n\n" version_header += "#define SLUIFT_VERSION_STRING \"" + Version.getBuildVersion(env.Dir("#").abspath, "sluift") + "\"\n" diff --git a/Sluift/SluiftGlobals.h b/Sluift/SluiftGlobals.h index 5de7cfe..e89f495 100644 --- a/Sluift/SluiftGlobals.h +++ b/Sluift/SluiftGlobals.h @@ -9,6 +9,9 @@ #include <Sluift/LuaElementConvertors.h> #include <Swiften/EventLoop/SimpleEventLoop.h> #include <Swiften/Network/BoostNetworkFactories.h> +#ifdef HAVE_ITUNES +#include <Sluift/ITunesInterface.h> +#endif #include <signal.h> namespace Swift { @@ -25,5 +28,8 @@ namespace Swift { int coreLibIndex; int moduleLibIndex; sig_atomic_t interruptRequested; +#ifdef HAVE_ITUNES + ITunesInterface iTunes; +#endif }; } diff --git a/Sluift/core.lua b/Sluift/core.lua index f387354..1969690 100644 --- a/Sluift/core.lua +++ b/Sluift/core.lua @@ -72,7 +72,22 @@ local function register_table_tostring(table, print_functions) metatable.__tostring = table_tostring end end - return table +end + +-- FIXME: Not really a good or efficiant equals, but does the trick for now +local function table_equals(t1, t2) + return tostring(t1) == tostring(t2) +end + +local function register_table_equals(table) + if type(table) == 'table' then + local metatable = getmetatable(table) + if not metatable then + metatable = {} + setmetatable(table, metatable) + end + metatable.__eq = table_equals + end end local function merge_tables(...) @@ -983,6 +998,7 @@ return { register_help = register_help, register_class_help = register_class_help, register_table_tostring = register_table_tostring, + register_table_equals = register_table_equals, register_get_by_type_index = register_get_by_type_index, process_pubsub_event = process_pubsub_event, tprint = tprint, diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp index 08ffd92..17990e8 100644 --- a/Sluift/sluift.cpp +++ b/Sluift/sluift.cpp @@ -33,6 +33,7 @@ #include <Swiften/IDN/IDNConverter.h> #include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Crypto/PlatformCryptoProvider.h> +#include <Sluift/ITunesInterface.h> using namespace Swift; @@ -176,7 +177,6 @@ SLUIFT_LUA_FUNCTION_WITH_HELP( return 1; } - /******************************************************************************* * JID Functions ******************************************************************************/ @@ -271,6 +271,34 @@ SLUIFT_LUA_FUNCTION(IDN, stringprep) { return 1; } +/******************************************************************************* + * iTunes Functions + ******************************************************************************/ + +#ifdef HAVE_ITUNES +SLUIFT_LUA_FUNCTION(iTunes, get_current_track) { + boost::optional<ITunesInterface::Track> track = Sluift::globals.iTunes.getCurrentTrack(); + if (!track) { + return 0; + } + lua_createtable(L, 0, 0); + lua_pushstring(L, track->artist.c_str()); + lua_setfield(L, -2, "artist"); + lua_pushstring(L, track->name.c_str()); + lua_setfield(L, -2, "name"); + lua_pushstring(L, track->album.c_str()); + lua_setfield(L, -2, "album"); + lua_pushinteger(L, track->trackNumber); + lua_setfield(L, -2, "track_number"); + lua_pushnumber(L, track->duration); + lua_setfield(L, -2, "duration"); + lua_pushinteger(L, track->rating); + lua_setfield(L, -2, "rating"); + Lua::registerTableToString(L, -1); + Lua::registerTableEquals(L, -1); + return 1; +} +#endif /******************************************************************************* * Module registration @@ -296,6 +324,11 @@ SLUIFT_API int luaopen_sluift(lua_State* L) { lua_call(L, 0, 1); Sluift::globals.coreLibIndex = luaL_ref(L, LUA_REGISTRYINDEX); + lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex); + lua_getfield(L, -1, "Client"); + lua_setmetatable(L, -3); + lua_pop(L, 1); + // Register functions Lua::FunctionRegistry::getInstance().addFunctionsToTable(L, "Sluift"); Lua::FunctionRegistry::getInstance().createFunctionTable(L, "JID"); @@ -304,6 +337,10 @@ SLUIFT_API int luaopen_sluift(lua_State* L) { lua_setfield(L, -2, "base64"); Lua::FunctionRegistry::getInstance().createFunctionTable(L, "IDN"); lua_setfield(L, -2, "idn"); +#ifdef HAVE_ITUNES + Lua::FunctionRegistry::getInstance().createFunctionTable(L, "iTunes"); + lua_setfield(L, -2, "itunes"); +#endif // Register convenience functions lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex); diff --git a/Swiften/Elements/UserTune.cpp b/Swiften/Elements/UserTune.cpp new file mode 100644 index 0000000..e4c0241 --- /dev/null +++ b/Swiften/Elements/UserTune.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Elements/UserTune.h> + +using namespace Swift; + +UserTune::UserTune() { +} + +UserTune::~UserTune() { +} diff --git a/Swiften/Elements/UserTune.h b/Swiften/Elements/UserTune.h new file mode 100644 index 0000000..5e0999a --- /dev/null +++ b/Swiften/Elements/UserTune.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Elements/Payload.h> +#include <boost/optional.hpp> +#include <string> + + + +namespace Swift { + class SWIFTEN_API UserTune : public Payload { + public: + + UserTune(); + + virtual ~UserTune(); + + const boost::optional< unsigned int >& getRating() const { + return rating; + } + + void setRating(const boost::optional< unsigned int >& value) { + this->rating = value ; + } + + const boost::optional< std::string >& getTitle() const { + return title; + } + + void setTitle(const boost::optional< std::string >& value) { + this->title = value ; + } + + const boost::optional< std::string >& getTrack() const { + return track; + } + + void setTrack(const boost::optional< std::string >& value) { + this->track = value ; + } + + const boost::optional< std::string >& getArtist() const { + return artist; + } + + void setArtist(const boost::optional< std::string >& value) { + this->artist = value ; + } + + const boost::optional< std::string >& getURI() const { + return uri; + } + + void setURI(const boost::optional< std::string >& value) { + this->uri = value ; + } + + const boost::optional< std::string >& getSource() const { + return source; + } + + void setSource(const boost::optional< std::string >& value) { + this->source = value ; + } + + const boost::optional< unsigned int >& getLength() const { + return length; + } + + void setLength(const boost::optional< unsigned int >& value) { + this->length = value ; + } + + + private: + boost::optional< unsigned int > rating; + boost::optional< std::string > title; + boost::optional< std::string > track; + boost::optional< std::string > artist; + boost::optional< std::string > uri; + boost::optional< std::string > source; + boost::optional< unsigned int > length; + }; +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index 3ec5a7a..22019b4 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -75,6 +75,7 @@ #include <Swiften/Parser/PayloadParsers/PubSubEventParser.h> #include <Swiften/Parser/PayloadParsers/PubSubErrorParserFactory.h> #include <Swiften/Parser/PayloadParsers/UserLocationParser.h> +#include <Swiften/Parser/PayloadParsers/UserTuneParser.h> using namespace boost; @@ -135,6 +136,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(boost::make_shared<GenericPayloadParserFactory<S5BProxyRequestParser> >("query", "http://jabber.org/protocol/bytestreams")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<WhiteboardParser> >("wb", "http://swift.im/whiteboard")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<UserLocationParser> >("geoloc", "http://jabber.org/protocol/geoloc")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<UserTuneParser> >("tune", "http://jabber.org/protocol/tune")); factories_.push_back(boost::make_shared<DeliveryReceiptParserFactory>()); factories_.push_back(boost::make_shared<DeliveryReceiptRequestParserFactory>()); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<IdleParser> >("idle", "urn:xmpp:idle:1")); diff --git a/Swiften/Parser/PayloadParsers/UserTuneParser.cpp b/Swiften/Parser/PayloadParsers/UserTuneParser.cpp new file mode 100644 index 0000000..bb299e4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UserTuneParser.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/UserTuneParser.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +UserTuneParser::UserTuneParser() : level(0) { +} + +UserTuneParser::~UserTuneParser() { +} + +void UserTuneParser::handleStartElement(const std::string&, const std::string&, const AttributeMap&) { + if (level == 1) { + currentText = ""; + } + ++level; +} + +void UserTuneParser::handleEndElement(const std::string& element, const std::string&) { + --level; + if (level == 1) { + try { + if (element == "artist") { + getPayloadInternal()->setArtist(currentText); + } + else if (element == "length") { + getPayloadInternal()->setLength(boost::lexical_cast<unsigned int>(currentText)); + } + else if (element == "rating") { + getPayloadInternal()->setRating(boost::lexical_cast<unsigned int>(currentText)); + } + else if (element == "source") { + getPayloadInternal()->setSource(currentText); + } + else if (element == "title") { + getPayloadInternal()->setTitle(currentText); + } + else if (element == "track") { + getPayloadInternal()->setTrack(currentText); + } + else if (element == "URI") { + getPayloadInternal()->setURI(currentText); + } + } + catch (const boost::bad_lexical_cast&) { + } + } +} + +void UserTuneParser::handleCharacterData(const std::string& data) { + currentText += data; +} diff --git a/Swiften/Parser/PayloadParsers/UserTuneParser.h b/Swiften/Parser/PayloadParsers/UserTuneParser.h new file mode 100644 index 0000000..1cfadea --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UserTuneParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Base/Override.h> +#include <Swiften/Base/API.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Elements/UserTune.h> + +namespace Swift { + class SWIFTEN_API UserTuneParser : public GenericPayloadParser<UserTune> { + public: + UserTuneParser(); + virtual ~UserTuneParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) SWIFTEN_OVERRIDE; + virtual void handleEndElement(const std::string& element, const std::string&) SWIFTEN_OVERRIDE; + virtual void handleCharacterData(const std::string& data) SWIFTEN_OVERRIDE; + + private: + int level; + std::string currentText; + }; +} diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 0a6972e..4d6db11 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -74,6 +74,7 @@ sources = [ "PayloadParsers/DeliveryReceiptParser.cpp", "PayloadParsers/DeliveryReceiptRequestParser.cpp", "PayloadParsers/UserLocationParser.cpp", + "PayloadParsers/UserTuneParser.cpp", "PayloadParsers/WhiteboardParser.cpp", "PayloadParsers/PubSubErrorParserFactory.cpp", "PlatformXMLParserFactory.cpp", diff --git a/Swiften/SConscript b/Swiften/SConscript index 75944f0..b5e13a9 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -137,6 +137,7 @@ if env["SCONS_STAGE"] == "build" : "Elements/StreamResume.cpp", "Elements/StreamResumed.cpp", "Elements/UserLocation.cpp", + "Elements/UserTune.cpp", "Elements/VCard.cpp", "Elements/MUCOccupant.cpp", "Entity/Entity.cpp", @@ -215,6 +216,7 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/DeliveryReceiptSerializer.cpp", "Serializer/PayloadSerializers/DeliveryReceiptRequestSerializer.cpp", "Serializer/PayloadSerializers/UserLocationSerializer.cpp", + "Serializer/PayloadSerializers/UserTuneSerializer.cpp", "Serializer/PayloadSerializers/WhiteboardSerializer.cpp", "Serializer/PresenceSerializer.cpp", "Serializer/StanzaSerializer.cpp", diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index a57a74e..16c79d5 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -52,6 +52,7 @@ #include <Swiften/Serializer/PayloadSerializers/LastSerializer.h> #include <Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h> #include <Swiften/Serializer/PayloadSerializers/UserLocationSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h> #include <Swiften/Serializer/PayloadSerializers/IdleSerializer.h> #include <Swiften/Serializer/PayloadSerializers/PubSubSerializer.h> #include <Swiften/Serializer/PayloadSerializers/PubSubOwnerPubSubSerializer.h> @@ -117,6 +118,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new LastSerializer()); serializers_.push_back(new WhiteboardSerializer()); serializers_.push_back(new UserLocationSerializer()); + serializers_.push_back(new UserTuneSerializer()); serializers_.push_back(new IdleSerializer()); serializers_.push_back(new StreamInitiationFileInfoSerializer()); diff --git a/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp new file mode 100644 index 0000000..6c7799e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +namespace Swift { + +UserTuneSerializer::UserTuneSerializer() { +} + +std::string UserTuneSerializer::serializePayload( + boost::shared_ptr<UserTune> payload) const { + XMLElement result("tune", "http://jabber.org/protocol/tune"); + if (boost::optional<std::string> value = payload->getArtist()) { + result.addNode(boost::make_shared<XMLElement>("artist", "", *value)); + } + if (boost::optional<unsigned int> value = payload->getLength()) { + result.addNode(boost::make_shared<XMLElement>("length", "", boost::lexical_cast<std::string>(*value))); + } + if (boost::optional<unsigned int> value = payload->getRating()) { + result.addNode(boost::make_shared<XMLElement>("rating", "", boost::lexical_cast<std::string>(*value))); + } + if (boost::optional<std::string> value = payload->getSource()) { + result.addNode(boost::make_shared<XMLElement>("source", "", *value)); + } + if (boost::optional<std::string> value = payload->getTitle()) { + result.addNode(boost::make_shared<XMLElement>("title", "", *value)); + } + if (boost::optional<std::string> value = payload->getTrack()) { + result.addNode(boost::make_shared<XMLElement>("track", "", *value)); + } + if (boost::optional<std::string> value = payload->getURI()) { + result.addNode(boost::make_shared<XMLElement>("uri", "", *value)); + } + return result.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h new file mode 100644 index 0000000..8c20cbd --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/UserTune.h> + +namespace Swift { + class UserTuneSerializer : public GenericPayloadSerializer<UserTune> { + public: + UserTuneSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<UserTune>) const; + }; +} |