/*
* Copyright (C) 2011-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, see
* .
*
*/
#include "AddonsOperations.h"
#include "JSONUtils.h"
#include "addons/AddonManager.h"
#include "addons/AddonDatabase.h"
#include "addons/PluginSource.h"
#include "ApplicationMessenger.h"
#include "TextureCache.h"
#include "filesystem/File.h"
#include "utils/StringUtils.h"
using namespace std;
using namespace JSONRPC;
using namespace ADDON;
using namespace XFILE;
JSONRPC_STATUS CAddonsOperations::GetAddons(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
vector addonTypes;
TYPE addonType = TranslateType(parameterObject["type"].asString());
CPluginSource::Content content = CPluginSource::Translate(parameterObject["content"].asString());
CVariant enabled = parameterObject["enabled"];
// ignore the "content" parameter if the type is specified but not a plugin or script
if (addonType != ADDON_UNKNOWN && addonType != ADDON_PLUGIN && addonType != ADDON_SCRIPT)
content = CPluginSource::UNKNOWN;
if (addonType >= ADDON_VIDEO && addonType <= ADDON_EXECUTABLE)
{
addonTypes.push_back(ADDON_PLUGIN);
addonTypes.push_back(ADDON_SCRIPT);
switch (addonType)
{
case ADDON_VIDEO:
content = CPluginSource::VIDEO;
break;
case ADDON_AUDIO:
content = CPluginSource::AUDIO;
break;
case ADDON_IMAGE:
content = CPluginSource::IMAGE;
break;
case ADDON_EXECUTABLE:
content = CPluginSource::EXECUTABLE;
break;
default:
break;
}
}
else
addonTypes.push_back(addonType);
VECADDONS addons;
for (vector::const_iterator typeIt = addonTypes.begin(); typeIt != addonTypes.end(); ++typeIt)
{
VECADDONS typeAddons;
if (*typeIt == ADDON_UNKNOWN)
{
if (!enabled.isBoolean())
{
CAddonMgr::Get().GetAllAddons(typeAddons, false);
CAddonMgr::Get().GetAllAddons(typeAddons, true);
}
else
CAddonMgr::Get().GetAllAddons(typeAddons, enabled.asBoolean());
}
else
{
if (!enabled.isBoolean())
{
CAddonMgr::Get().GetAddons(*typeIt, typeAddons, false);
VECADDONS enabledAddons;
CAddonMgr::Get().GetAddons(*typeIt, enabledAddons, true);
typeAddons.insert(typeAddons.end(), enabledAddons.begin(), enabledAddons.end());
}
else
CAddonMgr::Get().GetAddons(*typeIt, typeAddons, enabled.asBoolean());
}
addons.insert(addons.end(), typeAddons.begin(), typeAddons.end());
}
// remove library addons
for (int index = 0; index < (int)addons.size(); index++)
{
PluginPtr plugin;
if (content != CPluginSource::UNKNOWN)
plugin = boost::dynamic_pointer_cast(addons.at(index));
if ((addons.at(index)->Type() <= ADDON_UNKNOWN || addons.at(index)->Type() >= ADDON_MAX) ||
((content != CPluginSource::UNKNOWN && plugin == NULL) || (plugin != NULL && !plugin->Provides(content))))
{
addons.erase(addons.begin() + index);
index--;
}
}
int start, end;
HandleLimits(parameterObject, result, addons.size(), start, end);
CAddonDatabase addondb;
for (int index = start; index < end; index++)
FillDetails(addons.at(index), parameterObject["properties"], result["addons"], addondb, true);
return OK;
}
JSONRPC_STATUS CAddonsOperations::GetAddonDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
string id = parameterObject["addonid"].asString();
AddonPtr addon;
if (!CAddonMgr::Get().GetAddon(id, addon, ADDON::ADDON_UNKNOWN, false) || addon.get() == NULL ||
addon->Type() <= ADDON_UNKNOWN || addon->Type() >= ADDON_MAX)
return InvalidParams;
CAddonDatabase addondb;
FillDetails(addon, parameterObject["properties"], result["addon"], addondb);
return OK;
}
JSONRPC_STATUS CAddonsOperations::SetAddonEnabled(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
string id = parameterObject["addonid"].asString();
bool disabled = false;
if (parameterObject["enabled"].isBoolean())
disabled = !parameterObject["enabled"].asBoolean();
// we need to toggle the current disabled state of the addon
else if (parameterObject["enabled"].isString())
disabled = !CAddonMgr::Get().IsAddonDisabled(id);
else
return InvalidParams;
if (!CAddonMgr::Get().DisableAddon(id, disabled))
return InvalidParams;
return ACK;
}
JSONRPC_STATUS CAddonsOperations::ExecuteAddon(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
string id = parameterObject["addonid"].asString();
AddonPtr addon;
if (!CAddonMgr::Get().GetAddon(id, addon) || addon.get() == NULL ||
addon->Type() < ADDON_VIZ || addon->Type() >= ADDON_MAX)
return InvalidParams;
string argv;
CVariant params = parameterObject["params"];
if (params.isObject())
{
for (CVariant::const_iterator_map it = params.begin_map(); it != params.end_map(); it++)
{
if (it != params.begin_map())
argv += ",";
argv += it->first + "=" + it->second.asString();
}
}
else if (params.isArray())
{
for (CVariant::const_iterator_array it = params.begin_array(); it != params.end_array(); it++)
{
if (it != params.begin_array())
argv += ",";
argv += StringUtils::Paramify(it->asString());
}
}
else if (params.isString())
{
if (!params.empty())
argv = StringUtils::Paramify(params.asString());
}
std::string cmd;
if (params.size() == 0)
cmd = StringUtils::Format("RunAddon(%s)", id.c_str());
else
cmd = StringUtils::Format("RunAddon(%s, %s)", id.c_str(), argv.c_str());
CApplicationMessenger::Get().ExecBuiltIn(cmd, parameterObject["wait"].asBoolean());
return ACK;
}
void CAddonsOperations::FillDetails(AddonPtr addon, const CVariant& fields, CVariant &result, CAddonDatabase &addondb, bool append /* = false */)
{
if (addon.get() == NULL)
return;
CVariant addonInfo;
addon->Props().Serialize(addonInfo);
CVariant object;
object["addonid"] = addonInfo["addonid"];
object["type"] = addonInfo["type"];
for (unsigned int index = 0; index < fields.size(); index++)
{
string field = fields[index].asString();
// we need to manually retrieve the enabled state of every addon
// from the addon database because it can't be read from addon.xml
if (field == "enabled")
{
object[field] = !CAddonMgr::Get().IsAddonDisabled(addon->ID());
}
else if (field == "fanart" || field == "thumbnail")
{
std::string url = addonInfo[field].asString();
// We need to check the existence of fanart and thumbnails as the addon simply
// holds where the art will be, not whether it exists.
bool needsRecaching;
std::string image = CTextureCache::Get().CheckCachedImage(url, false, needsRecaching);
if (!image.empty() || CFile::Exists(url))
object[field] = CTextureUtils::GetWrappedImageURL(url);
else
object[field] = "";
}
else if (addonInfo.isMember(field))
object[field] = addonInfo[field];
}
if (append)
result.append(object);
else
result = object;
}