summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2014-01-19 11:46:51 (GMT)
committerRemko Tronçon <git@el-tramo.be>2014-01-19 16:49:19 (GMT)
commitcbd01a5368f0b761d2032d75c9f7dfde2bf61578 (patch)
tree5016505b1e977e84655cc3bba4435ef7cb80e811
parent4083d6da47ac0e3b77da9c7c222a9439b3e1c04c (diff)
downloadswift-contrib-cbd01a5368f0b761d2032d75c9f7dfde2bf61578.zip
swift-contrib-cbd01a5368f0b761d2032d75c9f7dfde2bf61578.tar.bz2
Sluift: Add iTunes & PEP User Tune support
Change-Id: I25b3840bb40ce38531922cc737bc82828e026d3f
-rwxr-xr-xBuildTools/scons2ninja.py12
-rw-r--r--Sluift/.gitignore1
-rw-r--r--Sluift/ElementConvertors/ElementConvertors.ipp4
-rw-r--r--Sluift/ElementConvertors/SConscript1
-rw-r--r--Sluift/ElementConvertors/UserTuneConvertor.cpp111
-rw-r--r--Sluift/ElementConvertors/UserTuneConvertor.h29
-rw-r--r--Sluift/Examples/Tunes.lua68
-rw-r--r--Sluift/ITunesInterface.h38
-rw-r--r--Sluift/ITunesInterface.mm58
-rw-r--r--Sluift/Lua/LuaUtils.cpp11
-rw-r--r--Sluift/Lua/LuaUtils.h1
-rw-r--r--Sluift/SConscript11
-rw-r--r--Sluift/SluiftGlobals.h6
-rw-r--r--Sluift/core.lua18
-rw-r--r--Sluift/sluift.cpp39
-rw-r--r--Swiften/Elements/UserTune.cpp15
-rw-r--r--Swiften/Elements/UserTune.h91
-rw-r--r--Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp4
-rw-r--r--Swiften/Parser/PayloadParsers/UserTuneParser.cpp59
-rw-r--r--Swiften/Parser/PayloadParsers/UserTuneParser.h31
-rw-r--r--Swiften/Parser/SConscript1
-rw-r--r--Swiften/SConscript2
-rw-r--r--Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp4
-rw-r--r--Swiften/Serializer/PayloadSerializers/UserTuneSerializer.cpp48
-rw-r--r--Swiften/Serializer/PayloadSerializers/UserTuneSerializer.h19
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;
+ };
+}