[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / interfaces / json-rpc / AddonsOperations.cpp
1 /*
2  *      Copyright (C) 2011-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "AddonsOperations.h"
23 #include "JSONUtils.h"
24 #include "addons/AddonManager.h"
25 #include "addons/AddonDatabase.h"
26 #include "addons/PluginSource.h"
27 #include "ApplicationMessenger.h"
28 #include "TextureCache.h"
29 #include "filesystem/File.h"
30
31 using namespace std;
32 using namespace JSONRPC;
33 using namespace ADDON;
34 using namespace XFILE;
35
36 JSONRPC_STATUS CAddonsOperations::GetAddons(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
37 {
38   vector<TYPE> addonTypes;
39   TYPE addonType = TranslateType(parameterObject["type"].asString());
40   CPluginSource::Content content = CPluginSource::Translate(parameterObject["content"].asString());
41   CVariant enabled = parameterObject["enabled"];
42
43   // ignore the "content" parameter if the type is specified but not a plugin or script
44   if (addonType != ADDON_UNKNOWN && addonType != ADDON_PLUGIN && addonType != ADDON_SCRIPT)
45     content = CPluginSource::UNKNOWN;
46
47   if (addonType >= ADDON_VIDEO && addonType <= ADDON_EXECUTABLE)
48   {
49     addonTypes.push_back(ADDON_PLUGIN);
50     addonTypes.push_back(ADDON_SCRIPT);
51
52     switch (addonType)
53     {
54     case ADDON_VIDEO:
55       content = CPluginSource::VIDEO;
56       break;
57     case ADDON_AUDIO:
58       content = CPluginSource::AUDIO;
59       break;
60     case ADDON_IMAGE:
61       content = CPluginSource::IMAGE;
62       break;
63     case ADDON_EXECUTABLE:
64       content = CPluginSource::EXECUTABLE;
65       break;
66
67     default:
68       break;
69     }
70   }
71   else
72     addonTypes.push_back(addonType);
73
74   VECADDONS addons;
75   for (vector<TYPE>::const_iterator typeIt = addonTypes.begin(); typeIt != addonTypes.end(); typeIt++)
76   {
77     VECADDONS typeAddons;
78     if (*typeIt == ADDON_UNKNOWN)
79     {
80       if (!enabled.isBoolean())
81       {
82         CAddonMgr::Get().GetAllAddons(typeAddons, false);
83         CAddonMgr::Get().GetAllAddons(typeAddons, true);
84       }
85       else
86         CAddonMgr::Get().GetAllAddons(typeAddons, enabled.asBoolean());
87     }
88     else
89     {
90       if (!enabled.isBoolean())
91       {
92         CAddonMgr::Get().GetAddons(*typeIt, typeAddons, false);
93         VECADDONS enabledAddons;
94         CAddonMgr::Get().GetAddons(*typeIt, enabledAddons, true);
95         typeAddons.insert(typeAddons.end(), enabledAddons.begin(), enabledAddons.end());
96       }
97       else
98         CAddonMgr::Get().GetAddons(*typeIt, typeAddons, enabled.asBoolean());
99     }
100
101     addons.insert(addons.end(), typeAddons.begin(), typeAddons.end());
102   }
103
104   // remove library addons
105   for (int index = 0; index < (int)addons.size(); index++)
106   {
107     PluginPtr plugin;
108     if (content != CPluginSource::UNKNOWN)
109       plugin = boost::dynamic_pointer_cast<CPluginSource>(addons.at(index));
110
111     if ((addons.at(index)->Type() <= ADDON_UNKNOWN || addons.at(index)->Type() >= ADDON_VIZ_LIBRARY) ||
112        ((content != CPluginSource::UNKNOWN && plugin == NULL) || (plugin != NULL && !plugin->Provides(content))))
113     {
114       addons.erase(addons.begin() + index);
115       index--;
116     }
117   }
118
119   int start, end;
120   HandleLimits(parameterObject, result, addons.size(), start, end);
121   
122   CAddonDatabase addondb;
123   for (int index = start; index < end; index++)
124     FillDetails(addons.at(index), parameterObject["properties"], result["addons"], addondb, true);
125   
126   return OK;
127 }
128
129 JSONRPC_STATUS CAddonsOperations::GetAddonDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
130 {
131   string id = parameterObject["addonid"].asString();
132   AddonPtr addon;
133   if (!CAddonMgr::Get().GetAddon(id, addon, ADDON::ADDON_UNKNOWN, false) || addon.get() == NULL ||
134       addon->Type() <= ADDON_UNKNOWN || addon->Type() >= ADDON_VIZ_LIBRARY)
135     return InvalidParams;
136     
137   CAddonDatabase addondb;
138   FillDetails(addon, parameterObject["properties"], result["addon"], addondb);
139
140   return OK;
141 }
142
143 JSONRPC_STATUS CAddonsOperations::SetAddonEnabled(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
144 {
145   CAddonDatabase addondatabase;
146   if (!addondatabase.Open())
147     return InternalError;
148
149   string id = parameterObject["addonid"].asString();
150   bool disabled = false;
151   if (parameterObject["enabled"].isBoolean())
152     disabled = !parameterObject["enabled"].asBoolean();
153   // we need to toggle the current disabled state of the addon
154   else if (parameterObject["enabled"].isString())
155     disabled = !addondatabase.IsAddonDisabled(id);
156   else
157     return InvalidParams;
158
159   if (!addondatabase.DisableAddon(id, disabled))
160       return InvalidParams;
161
162   return ACK;
163 }
164
165 JSONRPC_STATUS CAddonsOperations::ExecuteAddon(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
166 {
167   string id = parameterObject["addonid"].asString();
168   AddonPtr addon;
169   if (!CAddonMgr::Get().GetAddon(id, addon) || addon.get() == NULL ||
170       addon->Type() < ADDON_VIZ || addon->Type() >= ADDON_VIZ_LIBRARY)
171     return InvalidParams;
172     
173   string argv;
174   CVariant params = parameterObject["params"];
175   if (params.isObject())
176   {
177     for (CVariant::const_iterator_map it = params.begin_map(); it != params.end_map(); it++)
178     {
179       if (it != params.begin_map())
180         argv += ",";
181       argv += it->first + "=" + it->second.asString();
182     }
183   }
184   else if (params.isArray())
185   {
186     for (CVariant::const_iterator_array it = params.begin_array(); it != params.end_array(); it++)
187     {
188       if (it != params.begin_array())
189         argv += ",";
190       argv += it->asString();
191     }
192   }
193   
194   CStdString cmd;
195   if (params.size() == 0)
196     cmd.Format("RunAddon(%s)", id.c_str());
197   else
198     cmd.Format("RunAddon(%s, %s)", id.c_str(), argv.c_str());
199   CApplicationMessenger::Get().ExecBuiltIn(cmd, parameterObject["wait"].asBoolean());
200   
201   return ACK;
202 }
203
204 void CAddonsOperations::FillDetails(AddonPtr addon, const CVariant& fields, CVariant &result, CAddonDatabase &addondb, bool append /* = false */)
205 {
206   if (addon.get() == NULL)
207     return;
208   
209   CVariant addonInfo;
210   addon->Props().Serialize(addonInfo);
211
212   CVariant object;
213   object["addonid"] = addonInfo["addonid"];
214   object["type"] = addonInfo["type"];
215   
216   for (unsigned int index = 0; index < fields.size(); index++)
217   {
218     string field = fields[index].asString();
219     
220     // we need to manually retrieve the enabled state of every addon
221     // from the addon database because it can't be read from addon.xml
222     if (field == "enabled")
223     {
224       if (!addondb.IsOpen() && !addondb.Open())
225         return;
226       object[field] = !addondb.IsAddonDisabled(addon->ID());
227     }
228     else if (field == "fanart" || field == "thumbnail")
229     {
230       CStdString url = addonInfo[field].asString();
231       // We need to check the existence of fanart and thumbnails as the addon simply
232       // holds where the art will be, not whether it exists.
233       bool needsRecaching;
234       CStdString image = CTextureCache::Get().CheckCachedImage(url, false, needsRecaching);
235       if (!image.empty() || CFile::Exists(url))
236         object[field] = CTextureCache::Get().GetWrappedImageURL(url);
237       else
238         object[field] = "";
239     }
240     else if (addonInfo.isMember(field))
241       object[field] = addonInfo[field];
242   }
243   
244   if (append)
245     result.append(object);
246   else
247     result = object;
248 }