Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 1107 lines (981 sloc) 30.433 kb
074db86 merged: addons-fw branch
elupus authored
1 /*
2 * Copyright (C) 2005-2009 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 #include "AddonManager.h"
22 #include "Addon.h"
23 #include "Application.h"
24 #include "utils/log.h"
25 #include "StringUtils.h"
26 #include "RegExp.h"
27 #include "XMLUtils.h"
28 #include "GUIDialogYesNo.h"
29 #include "GUIDialogOK.h"
30 #include "GUIDialogAddonSettings.h"
31 #include "GUIWindowManager.h"
32 #include "FileItem.h"
33 #include "Settings.h"
34 #include "GUISettings.h"
35 #include "SingleLock.h"
36 #include "DownloadQueueManager.h"
37
38 #ifdef HAS_VISUALISATION
055f806 cosmetic/tidyup move all addon classes to /xbmc/addons/
alcoheca authored
39 #include "DllVisualisation.h"
40 #include "Visualisation.h"
074db86 merged: addons-fw branch
elupus authored
41 #endif
42 #ifdef HAS_SCREENSAVER
055f806 cosmetic/tidyup move all addon classes to /xbmc/addons/
alcoheca authored
43 #include "DllScreenSaver.h"
44 #include "ScreenSaver.h"
074db86 merged: addons-fw branch
elupus authored
45 #endif
46 //#ifdef HAS_SCRAPERS
055f806 cosmetic/tidyup move all addon classes to /xbmc/addons/
alcoheca authored
47 #include "Scraper.h"
074db86 merged: addons-fw branch
elupus authored
48 //#endif
49
50
51 namespace ADDON
52 {
53
54 /**********************************************************
55 * CAddonStatusHandler - AddOn Status Report Class
56 *
57 * Used to informate the user about occurred errors and
58 * changes inside Add-on's, and ask him what to do.
59 *
60 */
61
62 CCriticalSection CAddonStatusHandler::m_critSection;
63
64 CAddonStatusHandler::CAddonStatusHandler(IAddon* addon, ADDON_STATUS status, CStdString message, bool sameThread)
65 : m_addon(addon)
66 {
67 if (m_addon == NULL)
68 return;
69
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
70 CLog::Log(LOGINFO, "Called Add-on status handler for '%u' of clientName:%s, clientID:%s (same Thread=%s)", status, m_addon->Name().c_str(), m_addon->ID().c_str(), sameThread ? "yes" : "no");
074db86 merged: addons-fw branch
elupus authored
71
72 m_status = status;
73 m_message = message;
74
75 if (sameThread)
76 {
77 Process();
78 }
79 else
80 {
81 CStdString ThreadName;
82 ThreadName.Format("Addon Status: %s", m_addon->Name().c_str());
83
84 Create(true, THREAD_MINSTACKSIZE);
85 SetName(ThreadName.c_str());
86 SetPriority(-15);
87 }
88 }
89
90 CAddonStatusHandler::~CAddonStatusHandler()
91 {
92 StopThread();
93 }
94
95 void CAddonStatusHandler::OnStartup()
96 {
97 }
98
99 void CAddonStatusHandler::OnExit()
100 {
101 }
102
103 void CAddonStatusHandler::Process()
104 {
105 CSingleLock lock(m_critSection);
106
107 CStdString heading;
108 heading.Format("%s: %s", TranslateType(m_addon->Type(), true).c_str(), m_addon->Name().c_str());
109
110 /* AddOn lost connection to his backend (for ones that use Network) */
111 if (m_status == STATUS_LOST_CONNECTION)
112 {
113 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
114 if (!pDialog) return;
115
116 pDialog->SetHeading(heading);
117 pDialog->SetLine(1, 24070);
118 pDialog->SetLine(2, 24073);
119
120 //send message and wait for user input
121 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_YES_NO, g_windowManager.GetActiveWindow()};
122 g_application.getApplicationMessenger().SendMessage(tMsg, true);
123
124 if (pDialog->IsConfirmed())
125 CAddonMgr::Get()->GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, false);
126 }
127 /* Request to restart the AddOn and data structures need updated */
128 else if (m_status == STATUS_NEED_RESTART)
129 {
130 CGUIDialogOK* pDialog = (CGUIDialogOK*)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
131 if (!pDialog) return;
132
133 pDialog->SetHeading(heading);
134 pDialog->SetLine(1, 24074);
135
136 //send message and wait for user input
137 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_OK, g_windowManager.GetActiveWindow()};
138 g_application.getApplicationMessenger().SendMessage(tMsg, true);
139
140 CAddonMgr::Get()->GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, true);
141 }
142 /* Some required settings are missing/invalid */
143 else if (m_status == STATUS_NEED_SETTINGS)
144 {
145 CGUIDialogYesNo* pDialogYesNo = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
146 if (!pDialogYesNo) return;
147
148 pDialogYesNo->SetHeading(heading);
149 pDialogYesNo->SetLine(1, 24070);
150 pDialogYesNo->SetLine(2, 24072);
151 pDialogYesNo->SetLine(3, m_message);
152
153 //send message and wait for user input
154 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_YES_NO, g_windowManager.GetActiveWindow()};
155 g_application.getApplicationMessenger().SendMessage(tMsg, true);
156
157 if (!pDialogYesNo->IsConfirmed()) return;
158
159 if (!m_addon->HasSettings())
160 return;
161
162 const AddonPtr addon(m_addon);
163 if (CGUIDialogAddonSettings::ShowAndGetInput(addon))
164 {
165 //todo doesn't dialogaddonsettings save these automatically? should do
166 m_addon->SaveSettings();
167 CAddonMgr::Get()->GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, true);
168 }
169 else
170 m_addon->LoadSettings();
171 }
172 /* A unknown event has occurred */
173 else if (m_status == STATUS_UNKNOWN)
174 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
175 CAddonMgr::Get()->DisableAddon(m_addon->ID());
074db86 merged: addons-fw branch
elupus authored
176 CGUIDialogOK* pDialog = (CGUIDialogOK*)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
177 if (!pDialog) return;
178
179 pDialog->SetHeading(heading);
180 pDialog->SetLine(1, 24070);
181 pDialog->SetLine(2, 24071);
182 pDialog->SetLine(3, m_message);
183
184 //send message and wait for user input
185 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_OK, g_windowManager.GetActiveWindow()};
186 g_application.getApplicationMessenger().SendMessage(tMsg, true);
187 }
188 }
189
190
191 /**********************************************************
192 * CAddonMgr
193 *
194 */
195
196 CAddonMgr* CAddonMgr::m_pInstance = NULL;
197 std::map<TYPE, IAddonMgrCallback*> CAddonMgr::m_managers;
198
199 CAddonMgr::CAddonMgr()
200 {
201 }
202
203 CAddonMgr::~CAddonMgr()
204 {
205 }
206
207 CAddonMgr* CAddonMgr::Get()
208 {
209 if (!m_pInstance)
210 {
211 m_pInstance = new CAddonMgr();
212 }
213 return m_pInstance;
214 }
215
216 IAddonMgrCallback* CAddonMgr::GetCallbackForType(TYPE type)
217 {
218 if (m_managers.find(type) == m_managers.end())
219 return NULL;
220 else
221 return m_managers[type];
222 }
223
224 bool CAddonMgr::RegisterAddonMgrCallback(const TYPE type, IAddonMgrCallback* cb)
225 {
226 if (cb == NULL)
227 return false;
228
229 m_managers.erase(type);
230 m_managers[type] = cb;
231
232 return true;
233 }
234
235 void CAddonMgr::UnregisterAddonMgrCallback(TYPE type)
236 {
237 m_managers.erase(type);
238 }
239
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
240 bool CAddonMgr::HasAddons(const TYPE &type, const CONTENT_TYPE &content/*= CONTENT_NONE*/, bool enabledOnly/*= true*/)
074db86 merged: addons-fw branch
elupus authored
241 {
0553457 changed: CAddonDll::Remove is not required
alcoheca authored
242 if (m_addons.empty())
243 {
244 VECADDONS add;
245 GetAllAddons(add,false);
246 }
247
074db86 merged: addons-fw branch
elupus authored
248 if (content == CONTENT_NONE)
249 return (m_addons.find(type) != m_addons.end());
250
251 VECADDONS addons;
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
252 return GetAddons(type, addons, content, enabledOnly);
074db86 merged: addons-fw branch
elupus authored
253 }
254
255 void CAddonMgr::UpdateRepos()
256 {
257 m_downloads.push_back(g_DownloadManager.RequestFile(ADDON_XBMC_REPO_URL, this));
258 }
259
260 bool CAddonMgr::ParseRepoXML(const CStdString &path)
261 {
262 //TODO
263 //check file exists, for each addoninfo, create an AddonProps struct, store in m_remoteAddons
264 return false;
265 }
266
267 void CAddonMgr::OnFileComplete(TICKET aTicket, CStdString& aFilePath, INT aByteRxCount, Result aResult)
268 {
269 for (unsigned i=0; i < m_downloads.size(); i++)
270 {
271 if (m_downloads[i].wQueueId == aTicket.wQueueId
272 && m_downloads[i].dwItemId == aTicket.dwItemId)
273 {
274 CLog::Log(LOGINFO, "ADDONS: Downloaded addons.xml");
275 ParseRepoXML(aFilePath);
276 }
277 }
278 }
279
280 bool CAddonMgr::GetAllAddons(VECADDONS &addons, bool enabledOnly/*= true*/)
281 {
282 VECADDONS temp;
283 if (CAddonMgr::Get()->GetAddons(ADDON_PLUGIN, temp, CONTENT_NONE, enabledOnly))
284 addons.insert(addons.end(), temp.begin(), temp.end());
285 if (CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, temp, CONTENT_NONE, enabledOnly))
286 addons.insert(addons.end(), temp.begin(), temp.end());
287 if (CAddonMgr::Get()->GetAddons(ADDON_SCREENSAVER, temp, CONTENT_NONE, enabledOnly))
288 addons.insert(addons.end(), temp.begin(), temp.end());
289 if (CAddonMgr::Get()->GetAddons(ADDON_SCRIPT, temp, CONTENT_NONE, enabledOnly))
290 addons.insert(addons.end(), temp.begin(), temp.end());
291 if (CAddonMgr::Get()->GetAddons(ADDON_VIZ, temp, CONTENT_NONE, enabledOnly))
292 addons.insert(addons.end(), temp.begin(), temp.end());
293 return !addons.empty();
294 }
295
296 bool CAddonMgr::GetAddons(const TYPE &type, VECADDONS &addons, const CONTENT_TYPE &content/*= CONTENT_NONE*/, bool enabledOnly/*= true*/)
297 {
298 // recheck addons.xml & each addontype's directories no more than once every ADDON_DIRSCAN_FREQ seconds
299 CDateTimeSpan span;
300 span.SetDateTimeSpan(0, 0, 0, ADDON_DIRSCAN_FREQ);
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
301 if(!m_lastDirScan.IsValid() || (m_lastDirScan + span) < CDateTime::GetCurrentDateTime())
074db86 merged: addons-fw branch
elupus authored
302 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
303 m_lastDirScan = CDateTime::GetCurrentDateTime();
304 LoadAddonsXML();
074db86 merged: addons-fw branch
elupus authored
305 }
306
307 addons.clear();
308 if (m_addons.find(type) != m_addons.end())
309 {
310 IVECADDONS itr = m_addons[type].begin();
311 while (itr != m_addons[type].end())
312 { // filter out what we're not looking for
313 if ((enabledOnly && (*itr)->Disabled())
314 || (content != CONTENT_NONE && !(*itr)->Supports(content)))
315 {
316 ++itr;
317 continue;
318 }
319 addons.push_back(*itr);
320 ++itr;
321 }
322 }
323 return !addons.empty();
324 }
325
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
326 bool CAddonMgr::GetAddon(const CStdString &str, AddonPtr &addon, const TYPE &type/*=ADDON_UNKNOWN*/, bool enabledOnly/*= true*/)
074db86 merged: addons-fw branch
elupus authored
327 {
328 CDateTimeSpan span;
329 span.SetDateTimeSpan(0, 0, 0, ADDON_DIRSCAN_FREQ);
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
330 if(!m_lastDirScan.IsValid() || (m_lastDirScan + span) < CDateTime::GetCurrentDateTime())
074db86 merged: addons-fw branch
elupus authored
331 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
332 m_lastDirScan = CDateTime::GetCurrentDateTime();
333 LoadAddonsXML();
074db86 merged: addons-fw branch
elupus authored
334 }
335
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
336 if (type != ADDON_UNKNOWN && m_addons.find(type) == m_addons.end())
074db86 merged: addons-fw branch
elupus authored
337 return false;
338
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
339 if (m_idMap[str])
340 {
341 addon = m_idMap[str];
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
342 if(enabledOnly)
343 return !addon->Disabled();
344 else
345 return true;
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
346 }
074db86 merged: addons-fw branch
elupus authored
347
348 VECADDONS &addons = m_addons[type];
349 IVECADDONS adnItr = addons.begin();
350 while (adnItr != addons.end())
351 {
352 //FIXME scrapers were previously registered by filename
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
353 if ((*adnItr)->Name() == str || (type == ADDON_SCRAPER && (*adnItr)->LibName() == str))
074db86 merged: addons-fw branch
elupus authored
354 {
355 addon = (*adnItr);
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
356 if(enabledOnly)
357 return !addon->Disabled();
358 else
359 return true;
074db86 merged: addons-fw branch
elupus authored
360 }
361 adnItr++;
362 }
363
364 return false;
365 }
366
367 //TODO handle all 'default' cases here, not just scrapers & vizs
368 bool CAddonMgr::GetDefault(const TYPE &type, AddonPtr &addon, const CONTENT_TYPE &content)
369 {
370 if (type != ADDON_SCRAPER && type != ADDON_VIZ)
371 return false;
372
373 CStdString setting;
374 if (type == ADDON_VIZ)
375 setting = g_guiSettings.GetString("musicplayer.visualisation");
376 else
377 {
378 switch (content)
379 {
380 case CONTENT_MOVIES:
381 {
382 setting = g_guiSettings.GetString("scrapers.moviedefault");
383 break;
384 }
385 case CONTENT_TVSHOWS:
386 {
387 setting = g_guiSettings.GetString("scrapers.tvshowdefault");
388 break;
389 }
390 case CONTENT_MUSICVIDEOS:
391 {
392 setting = g_guiSettings.GetString("scrapers.musicvideodefault");
393 break;
394 }
395 case CONTENT_ALBUMS:
396 case CONTENT_ARTISTS:
397 {
398 setting = g_guiSettings.GetString("musiclibrary.scraper");
399 break;
400 }
401 default:
402 return false;
403 }
404 }
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
405 return GetAddon(setting, addon, type);
074db86 merged: addons-fw branch
elupus authored
406 }
407
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
408 CStdString CAddonMgr::GetString(const CStdString &id, const int number)
074db86 merged: addons-fw branch
elupus authored
409 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
410 AddonPtr addon = m_idMap[id];
074db86 merged: addons-fw branch
elupus authored
411 if (addon)
412 return addon->GetString(number);
413
414 return "";
415 }
416
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
417 bool CAddonMgr::EnableAddon(const CStdString &id)
074db86 merged: addons-fw branch
elupus authored
418 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
419 AddonPtr addon = m_idMap[id];
074db86 merged: addons-fw branch
elupus authored
420 if (!addon)
421 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
422 CLog::Log(LOGINFO,"ADDON: Couldn't find Add-on to Enable: %s", id.c_str());
074db86 merged: addons-fw branch
elupus authored
423 return false;
424 }
425
426 return EnableAddon(addon);
427 }
428
429 bool CAddonMgr::EnableAddon(AddonPtr &addon)
430 {
431 CUtil::CreateDirectoryEx(addon->Profile());
432 addon->Enable();
433 CLog::Log(LOGINFO,"ADDON: Enabled %s: %s : %s", TranslateType(addon->Type()).c_str(), addon->Name().c_str(), addon->Version().Print().c_str());
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
434 SaveAddonsXML();
074db86 merged: addons-fw branch
elupus authored
435 return true;
436 }
437
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
438 bool CAddonMgr::DisableAddon(const CStdString &id)
074db86 merged: addons-fw branch
elupus authored
439 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
440 AddonPtr addon = m_idMap[id];
074db86 merged: addons-fw branch
elupus authored
441 if (!addon)
442 return false;
443 return DisableAddon(addon);
444 }
445
446 bool CAddonMgr::DisableAddon(AddonPtr &addon)
447 {
448 const TYPE type = addon->Type();
449
450 if (m_addons.find(type) == m_addons.end())
451 return false;
452
453 for (IVECADDONS itr = m_addons[type].begin(); itr != m_addons[type].end(); itr++)
454 {
455 if (addon == (*itr))
456 {
457 addon->Disable();
458
459 if (addon->Parent())
460 { // we can delete this cloned addon
461 m_addons[type].erase(itr);
462 }
463
464 CLog::Log(LOGINFO,"ADDON: Disabled %s: %s", TranslateType(addon->Type()).c_str(), addon->Name().c_str());
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
465 SaveAddonsXML();
074db86 merged: addons-fw branch
elupus authored
466 return true;
467 }
468 }
469 CLog::Log(LOGINFO,"ADDON: Couldn't find Add-on to Disable: %s", addon->Name().c_str());
470 return false;
471 }
472
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
473 bool CAddonMgr::LoadAddonsXML()
074db86 merged: addons-fw branch
elupus authored
474 {
475 VECADDONPROPS props;
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
476 if (!LoadAddonsXML(props))
074db86 merged: addons-fw branch
elupus authored
477 return false;
478
479 // refresh addon dirs if neccesary/forced
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
480 FindAddons();
074db86 merged: addons-fw branch
elupus authored
481
482 // now enable accordingly
483 VECADDONPROPS::const_iterator itr = props.begin();
484 while (itr != props.end())
485 {
486 AddonPtr addon;
eb3f010 fixed: ::LoadAddonsXML was broken
alcoheca authored
487 if (itr->parent.empty() && GetAddon(itr->id, addon, itr->type, false))
074db86 merged: addons-fw branch
elupus authored
488 {
489 EnableAddon(addon);
490 }
eb3f010 fixed: ::LoadAddonsXML was broken
alcoheca authored
491 else if (GetAddon(itr->parent, addon, itr->type, false))
074db86 merged: addons-fw branch
elupus authored
492 { // multiple addon configurations
493 AddonPtr clone = addon->Clone(addon);
494 if (clone)
495 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
496 m_addons[addon->Type()].push_back(clone);
074db86 merged: addons-fw branch
elupus authored
497 }
498 }
499 else
500 { // addon not found
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
501 CLog::Log(LOGERROR, "ADDON: Couldn't find addon requested with ID: %s", itr->id.c_str());
074db86 merged: addons-fw branch
elupus authored
502 //TODO we should really add but mark unavailable, to prompt user
503 }
504 ++itr;
505 }
506 return true;
507 }
508
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
509 void CAddonMgr::FindAddons()
074db86 merged: addons-fw branch
elupus authored
510 {
511 // parse the user & system dirs for addons of the requested type
512 CFileItemList items;
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
513 if (!CSpecialProtocol::XBMCIsHome())
514 CDirectory::GetDirectory("special://home/addons", items);
515 CDirectory::GetDirectory("special://xbmc/addons", items);
074db86 merged: addons-fw branch
elupus authored
516
517 // store any addons with unresolved deps, then recheck at the end
518 VECADDONS unresolved;
519
520 // for all folders found
521 for (int i = 0; i < items.Size(); ++i)
522 {
523 CFileItemPtr item = items[i];
524
bc837a1 changed: no need to log errors about addon dirs without description.xml ...
elupus authored
525 if(!item->m_bIsFolder)
526 continue;
527
074db86 merged: addons-fw branch
elupus authored
528 // read description.xml and populate the addon
529 AddonPtr addon;
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
530 if (!AddonFromInfoXML(item->m_strPath, addon))
074db86 merged: addons-fw branch
elupus authored
531 continue;
532
1a6409b changed: refuse to allow addons with missing library files (script, dll,
alcoheca authored
533 // refuse to store addons with missing library
bc837a1 changed: no need to log errors about addon dirs without description.xml ...
elupus authored
534 CStdString library(CUtil::AddFileToFolder(addon->Path(), addon->LibName()));
1a6409b changed: refuse to allow addons with missing library files (script, dll,
alcoheca authored
535 if (!CFile::Exists(library))
536 {
537 CLog::Log(LOGDEBUG, "ADDON: Missing library file %s, bypassing package", library.c_str());
538 continue;
539 }
540
074db86 merged: addons-fw branch
elupus authored
541 // check for/cache icon thumbnail
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
542 //TODO cache one thumb per addon id instead
bc837a1 changed: no need to log errors about addon dirs without description.xml ...
elupus authored
543 CFileItem item2(CUtil::AddFileToFolder(addon->Path(), addon->LibName()), false);
074db86 merged: addons-fw branch
elupus authored
544 item2.SetCachedProgramThumb();
545 if (!item2.HasThumbnail())
546 item2.SetUserProgramThumb();
547 if (!item2.HasThumbnail())
548 item2.SetThumbnailImage(addon->Icon());
549 if (item2.HasThumbnail())
550 {
551 XFILE::CFile::Cache(item2.GetThumbnailImage(),item->GetCachedProgramThumb());
552 }
553
554 if (!DependenciesMet(addon))
555 {
556 unresolved.push_back(addon);
557 continue;
558 }
559 else
560 { // everything ok, add to available addons if new
561 if (UpdateIfKnown(addon))
562 continue;
563 else
564 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
565 m_addons[addon->Type()].push_back(addon);
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
566 m_idMap.insert(std::make_pair(addon->ID(), addon));
074db86 merged: addons-fw branch
elupus authored
567 }
568 }
569 }
570
571 for (unsigned i = 0; i < unresolved.size(); i++)
572 {
573 AddonPtr& addon = unresolved[i];
574 if (DependenciesMet(addon))
575 {
576 if (!UpdateIfKnown(addon))
577 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
578 m_addons[addon->Type()].push_back(addon);
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
579 m_idMap.insert(std::make_pair(addon->ID(), addon));
074db86 merged: addons-fw branch
elupus authored
580 }
581 }
582 }
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
583 // CLog::Log(LOGINFO, "ADDON: Found %"PRIuS" addons", m_addons.find(type) == m_addons.end() ? 0: m_addons[type].size(), TranslateType(type).c_str());
074db86 merged: addons-fw branch
elupus authored
584 }
585
586 bool CAddonMgr::UpdateIfKnown(AddonPtr &addon)
587 {
588 if (m_addons.find(addon->Type()) != m_addons.end())
589 {
590 for (unsigned i = 0; i < m_addons[addon->Type()].size(); i++)
591 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
592 if (m_addons[addon->Type()][i]->ID() == addon->ID())
074db86 merged: addons-fw branch
elupus authored
593 {
594 //TODO inform any manager first, and request removal
595 //TODO choose most recent version if varying
596 m_addons[addon->Type()][i] = addon;
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
597 CStdString id = addon->ID();
598 m_idMap.erase(id);
599 m_idMap.insert(std::make_pair(addon->ID(), addon));
074db86 merged: addons-fw branch
elupus authored
600 return true;
601 }
602 }
603 }
604 return false;
605 }
606
607 bool CAddonMgr::DependenciesMet(AddonPtr &addon)
608 {
609 // As remote repos are not functioning,
610 // this will fail if a dependency is not found locally
611 if (!addon)
612 return false;
613
614 ADDONDEPS deps = addon->GetDeps();
615 ADDONDEPS::iterator itr = deps.begin();
616 while (itr != deps.end())
617 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
618 CStdString id;
619 id = (*itr).first;
074db86 merged: addons-fw branch
elupus authored
620 AddonVersion min = (*itr).second.first;
621 AddonVersion max = (*itr).second.second;
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
622 if (m_idMap.count(id))
074db86 merged: addons-fw branch
elupus authored
623 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
624 AddonPtr dep = m_idMap[id];
074db86 merged: addons-fw branch
elupus authored
625 // we're guaranteed to have at least max OR min here
626 if (!min.str.IsEmpty() && !max.str.IsEmpty())
627 return (dep->Version() >= min && dep->Version() <= max);
628 else if (!min.str.IsEmpty())
629 return (dep->Version() >= min);
630 else
631 return (dep->Version() <= max);
632 }
633 for (unsigned i=0; i < m_remoteAddons.size(); i++)
634 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
635 if (m_remoteAddons[i].id == id)
074db86 merged: addons-fw branch
elupus authored
636 {
637 if(m_remoteAddons[i].version >= min && m_remoteAddons[i].version <= max)
638 {
639 //TODO line up download
640 return false;
641 }
642 }
643 }
644 itr++;
645 }
646 return deps.empty();
647 }
648
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
649 bool CAddonMgr::AddonFromInfoXML(const CStdString &path, AddonPtr &addon)
074db86 merged: addons-fw branch
elupus authored
650 {
651 // First check that we can load description.xml
bc837a1 changed: no need to log errors about addon dirs without description.xml ...
elupus authored
652 CStdString strPath(CUtil::AddFileToFolder(path, ADDON_METAFILE));
653 if(!CFile::Exists(strPath))
654 return false;
074db86 merged: addons-fw branch
elupus authored
655
656 TiXmlDocument xmlDoc;
657 if (!xmlDoc.LoadFile(strPath))
658 {
659 CLog::Log(LOGERROR, "Unable to load: %s, Line %d\n%s", strPath.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
660 return false;
661 }
662
663 TiXmlElement *element = xmlDoc.RootElement();
664 if (!element || strcmpi(element->Value(), "addoninfo") != 0)
665 {
666 CLog::Log(LOGERROR, "ADDON: Error loading %s: cannot find <addon> root element", strPath.c_str());
667 return false;
668 }
669
670 /* Steps required to meet package requirements
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
671 * 1. id exists and is valid
074db86 merged: addons-fw branch
elupus authored
672 * 2. type exists and is valid
673 * 3. version exists
674 * 4. a license is specified
675 * 5. operating system matches ours
676 * 6. summary exists
677 * 7. for scrapers & plugins, support at least one type of content
678 *
679 * NOTE: addon dependencies are handled in ::FindAddons()
680 */
681
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
682 /* Validate id */
683 CStdString id;
684 element = NULL;
685 element = xmlDoc.RootElement()->FirstChildElement("id");
074db86 merged: addons-fw branch
elupus authored
686 if (!element)
687 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
688 CLog::Log(LOGERROR, "ADDON: %s missing <id> element, ignoring", strPath.c_str());
689 return false;
690 }
691 id = element->GetText();
93399a5 changed: ditched uuids for most addons in svn
alcoheca authored
692 //FIXME since we no longer required uuids, should we bother validating anything?
693 if (id.IsEmpty())
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
694 {
695 CLog::Log(LOGERROR, "ADDON: %s has invalid <id> element, ignoring", strPath.c_str());
074db86 merged: addons-fw branch
elupus authored
696 return false;
697 }
698
699 /* Validate type */
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
700 TYPE type;
701 element = NULL;
074db86 merged: addons-fw branch
elupus authored
702 element = xmlDoc.RootElement()->FirstChildElement("type");
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
703 if (!element)
074db86 merged: addons-fw branch
elupus authored
704 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
705 CLog::Log(LOGERROR, "ADDON: %s missing <id> element, ignoring", strPath.c_str());
074db86 merged: addons-fw branch
elupus authored
706 return false;
707 }
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
708 type = TranslateType(element->GetText());
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
709 if (type == ADDON_UNKNOWN)
074db86 merged: addons-fw branch
elupus authored
710 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
711 CLog::Log(LOGERROR, "ADDON: %s has invalid type identifier: '%d'", strPath.c_str(), type);
074db86 merged: addons-fw branch
elupus authored
712 return false;
713 }
714
715 /* Retrieve Name */
716 CStdString name;
717 element = NULL;
718 element = xmlDoc.RootElement()->FirstChildElement("title");
719 if (!element)
720 {
721 CLog::Log(LOGERROR, "ADDON: %s missing <title> element, ignoring", strPath.c_str());
722 return false;
723 }
724 name = element->GetText();
725
726 /* Retrieve version */
727 CStdString version;
728 element = NULL;
729 element = xmlDoc.RootElement()->FirstChildElement("version");
730 if (!element)
731 {
732 CLog::Log(LOGERROR, "ADDON: %s missing <version> element, ignoring", strPath.c_str());
733 return false;
734 }
735 /* Validate version */
736 version = element->GetText();
737 CRegExp versionRE;
738 versionRE.RegComp(ADDON_VERSION_RE.c_str());
739 if (versionRE.RegFind(version.c_str()) != 0)
740 {
741 CLog::Log(LOGERROR, "ADDON: %s has invalid <version> element, ignoring", strPath.c_str());
742 return false;
743 }
744
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
745 /* Path, ID & Version are valid */
746 AddonProps addonProps(id, type, version);
074db86 merged: addons-fw branch
elupus authored
747 addonProps.name = name;
748 addonProps.path = path;
749 addonProps.icon = CUtil::AddFileToFolder(path, "default.tbn");
750
751 /* Retrieve license */
752 element = NULL;
753 element = xmlDoc.RootElement()->FirstChildElement("license");
754 /* if (!element)
755 {
756 CLog::Log(LOGERROR, "ADDON: %s missing <license> element, ignoring", strPath.c_str());
757 return false;
758 }
759 addonProps.license = element->GetText();*/
760
761 /* Retrieve platforms which this addon supports */
762 CStdString platform;
763 element = NULL;
764 element = xmlDoc.RootElement()->FirstChildElement("platforms")->FirstChildElement("platform");
765 if (!element)
766 {
767 CLog::Log(LOGERROR, "ADDON: %s missing <platforms> element, ignoring", strPath.c_str());
768 return false;
769 }
770
771 bool all(false);
772 std::set<CStdString> platforms;
773 do
774 {
775 CStdString platform = element->GetText();
776 if (platform == "all")
777 {
778 all = true;
779 break;
780 }
781 platforms.insert(platform);
782 element = element->NextSiblingElement("platform");
783 } while (element != NULL);
784
785 if (!all)
786 {
787 #if defined(_LINUX) && !defined(__APPLE__)
788 if (!platforms.count("linux"))
789 {
790 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under Linux, ignoring", strPath.c_str());
791 return false;
792 }
793 #elif defined(_WIN32)
794 if (!platforms.count("windows"))
795 {
796 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under Windows, ignoring", strPath.c_str());
797 return false;
798 }
799 #elif defined(__APPLE__)
800 if (!platforms.count("osx"))
801 {
802 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under OSX, ignoring", strPath.c_str());
803 return false;
804 }
805 #elif defined(_XBOX)
806 if (!platforms.count("xbox"))
807 {
808 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under XBOX, ignoring", strPath.c_str());
809 return false;
810 }
811 #endif
812 }
813
814 /* Retrieve summary */
815 CStdString summary;
816 element = NULL;
817 element = xmlDoc.RootElement()->FirstChildElement("summary");
818 if (!element)
819 {
820 CLog::Log(LOGERROR, "ADDON: %s missing <summary> element, ignoring", strPath.c_str());
821 return false;
822 }
823 addonProps.summary = element->GetText();
824
825 if (addonProps.type == ADDON_SCRAPER || addonProps.type == ADDON_PLUGIN)
826 {
827 /* Retrieve content types that this addon supports */
828 CStdString platform;
829 element = NULL;
830 if (xmlDoc.RootElement()->FirstChildElement("supportedcontent"))
831 {
832 element = xmlDoc.RootElement()->FirstChildElement("supportedcontent")->FirstChildElement("content");
833 }
834 if (!element)
835 {
836 CLog::Log(LOGERROR, "ADDON: %s missing <supportedcontent> element, ignoring", strPath.c_str());
837 return false;
838 }
839
840 std::set<CONTENT_TYPE> contents;
841 do
842 {
843 CONTENT_TYPE content = TranslateContent(element->GetText());
844 if (content != CONTENT_NONE)
845 {
846 contents.insert(content);
847 }
848 element = element->NextSiblingElement("content");
849 } while (element != NULL);
850
851 if (contents.empty())
852 {
853 CLog::Log(LOGERROR, "ADDON: %s %s supports no available content-types, ignoring", TranslateType(addonProps.type).c_str(), addonProps.name.c_str());
854 return false;
855 }
856 else
857 {
858 addonProps.contents = contents;
859 }
860 }
861
862 /*** Beginning of optional fields ***/
863 /* Retrieve description */
864 element = NULL;
865 element = xmlDoc.RootElement()->FirstChildElement("description");
866 if (element)
867 addonProps.description = element->GetText();
868
869 /* Retrieve author */
870 element = NULL;
871 element = xmlDoc.RootElement()->FirstChildElement("author");
872 if (element)
873 addonProps.author = element->GetText();
874
875 /* Retrieve disclaimer */
876 element = NULL;
877 element = xmlDoc.RootElement()->FirstChildElement("disclaimer");
878 if (element)
879 addonProps.disclaimer = element->GetText();
880
881 /* Retrieve library file name */
882 // will be replaced with default library name if unspecified
883 element = NULL;
884 element = xmlDoc.RootElement()->FirstChildElement("library");
885 if (element)
886 addonProps.libname = element->GetText();
887
888 //TODO move this to addon specific class, if it's needed at all..
889 #ifdef _WIN32
890 /* Retrieve WIN32 library file name in case it is present
891 * This is required for no overwrite to the fixed WIN32 add-on's
892 * during compile time
893 */
894 element = NULL;
895 element = xmlDoc.RootElement()->FirstChildElement("librarywin32");
896 if (element) // If it is found overwrite standard library name
897 addonProps.libname = element->GetText();
898 #endif
899
900 /* Retrieve dependencies that this addon requires */
901 std::map<CStdString, std::pair<const AddonVersion, const AddonVersion> > deps;
902 element = NULL;
903 element = xmlDoc.RootElement()->FirstChildElement("dependencies");
904 if (element)
905 {
906 element = element->FirstChildElement("dependency");
907 if (!element)
908 CLog::Log(LOGDEBUG, "ADDON: %s missing at least one <dependency> element, will ignore this dependency", strPath.c_str());
909 else
910 {
911 do
912 {
913 CStdString min = element->Attribute("minversion");
914 CStdString max = element->Attribute("maxversion");
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
915 CStdString id = element->GetText();
916 if (!id || (!min && ! max))
074db86 merged: addons-fw branch
elupus authored
917 {
918 CLog::Log(LOGDEBUG, "ADDON: %s malformed <dependency> element, will ignore this dependency", strPath.c_str());
919 continue;
920 }
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
921 deps.insert(std::make_pair(id, std::make_pair(AddonVersion(min), AddonVersion(max))));
074db86 merged: addons-fw branch
elupus authored
922 element = element->NextSiblingElement("dependency");
923 } while (element != NULL);
b1eb335 changed: moved addon dependencies into the addon properties
vdrfan authored
924 addonProps.dependencies = deps;
074db86 merged: addons-fw branch
elupus authored
925 }
926 }
927
928 /*** end of optional fields ***/
929
930 /* Create an addon object and store in a shared_ptr */
931 addon.reset();
932 switch (type)
933 {
934 case ADDON_PLUGIN:
935 case ADDON_SCRIPT:
936 {
937 AddonPtr temp(new CAddon(addonProps));
938 addon = temp;
939 break;
940 }
941 case ADDON_SCRAPER:
942 {
943 AddonPtr temp(new CScraper(addonProps));
944 addon = temp;
945 break;
946 }
947 case ADDON_VIZ:
948 {
949 AddonPtr temp(new CVisualisation(addonProps));
950 addon = temp;
951 break;
952 }
953 case ADDON_SCREENSAVER:
954 {
955 AddonPtr temp(new CScreenSaver(addonProps));
956 addon = temp;
957 break;
958 }
959 case ADDON_SCRAPER_LIBRARY:
960 case ADDON_VIZ_LIBRARY:
961 {
962 AddonPtr temp(new CAddonLibrary(addonProps));
963 addon = temp;
964 break;
965 }
966 default:
967 return false;
968 }
969
970 return true;
971 }
972
973 CStdString CAddonMgr::GetAddonsXMLFile() const
974 {
975 CStdString folder;
4c490a7 changed: Don't allow access to m_vecProfiles outside of CSettings. Inste...
jmarshallnz authored
976 if (g_settings.GetCurrentProfile().hasAddons())
074db86 merged: addons-fw branch
elupus authored
977 CUtil::AddFileToFolder(g_settings.GetProfileUserDataFolder(),"addons.xml",folder);
978 else
979 CUtil::AddFileToFolder(g_settings.GetUserDataFolder(),"addons.xml",folder);
980
981 return folder;
982 }
983
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
984 bool CAddonMgr::SaveAddonsXML()
074db86 merged: addons-fw branch
elupus authored
985 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
986 //TODO lock
987 if (m_idMap.empty())
988 return true;
074db86 merged: addons-fw branch
elupus authored
989
990 TiXmlDocument doc;
991 TiXmlNode *pRoot = NULL;
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
992 TiXmlElement xmlRootElement("addons");
993 pRoot = doc.InsertEndChild(xmlRootElement);
074db86 merged: addons-fw branch
elupus authored
994
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
995 std::map<CStdString, AddonPtr>::iterator itr = m_idMap.begin();
996 while (itr != m_idMap.end())
997 {
998 AddonPtr addon = (*itr).second;
999 if (addon && !addon->Disabled())
074db86 merged: addons-fw branch
elupus authored
1000 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1001 TYPE type = addon->Type();
1002 CStdString strType = TranslateType(type);
1003 TiXmlElement sectionElement(strType);
1004 TiXmlNode *node = pRoot->FirstChild(strType);
1005 if (!node)
1006 node = pRoot->InsertEndChild(sectionElement);
1007
074db86 merged: addons-fw branch
elupus authored
1008 TiXmlElement element("addon");
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1009 XMLUtils::SetString(&element, "id", addon->ID());
1010 if (addon->Parent())
1011 XMLUtils::SetString(&element, "parentid", addon->Parent()->ID());
1012 //XMLUtils::SetString(&element, "repo", addon->Repo()->ID());
1013 node->InsertEndChild(element);
074db86 merged: addons-fw branch
elupus authored
1014 }
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1015 itr++;
074db86 merged: addons-fw branch
elupus authored
1016 }
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1017 return doc.SaveFile(GetAddonsXMLFile());
074db86 merged: addons-fw branch
elupus authored
1018 }
1019
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1020 bool CAddonMgr::LoadAddonsXML(VECADDONPROPS &addons)
074db86 merged: addons-fw branch
elupus authored
1021 {
1022 CStdString strXMLFile;
1023 TiXmlDocument xmlDoc;
1024 TiXmlElement *pRootElement = NULL;
1025 strXMLFile = GetAddonsXMLFile();
1026 if ( xmlDoc.LoadFile( strXMLFile ) )
1027 {
1028 pRootElement = xmlDoc.RootElement();
1029 CStdString strValue;
1030 if (pRootElement)
1031 strValue = pRootElement->Value();
1032 if ( strValue != "addons")
1033 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1034 CLog::Log(LOGDEBUG, "ADDONS: %s does not contain <addons> element", strXMLFile.c_str());
074db86 merged: addons-fw branch
elupus authored
1035 return false;
1036 }
1037 }
1038 else if (CFile::Exists(strXMLFile))
1039 {
1040 CLog::Log(LOGERROR, "ADDONS: Error loading %s: Line %d, %s", strXMLFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
1041 return false;
1042 }
1043 else
1044 {
1045 CLog::Log(LOGINFO, "ADDONS: No addons.xml found");
1046 return true; // no addons enabled for this profile yet
1047 }
1048
1049 if (pRootElement)
1050 { // parse addons...
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1051 GetAddons(pRootElement, addons);
074db86 merged: addons-fw branch
elupus authored
1052 return true;
1053 }
1054
1055 return false;
1056 }
1057
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1058 void CAddonMgr::GetAddons(const TiXmlElement* pAddons, VECADDONPROPS &addons)
074db86 merged: addons-fw branch
elupus authored
1059 {
1060
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1061 const TiXmlNode *pType = 0;
b1b8601 changed: cosmetics
vdrfan authored
1062 while( ( pType = pAddons->IterateChildren( pType ) ) )
074db86 merged: addons-fw branch
elupus authored
1063 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1064 TYPE type = TranslateType(pType->Value());
1065 const TiXmlNode *pAddon = pType->FirstChild();
1066 while (pAddon > 0)
074db86 merged: addons-fw branch
elupus authored
1067 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1068 CStdString strValue = pAddon->Value();
074db86 merged: addons-fw branch
elupus authored
1069 if (strValue == "addon")
1070 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1071 GetAddon(type, pAddon, addons);
074db86 merged: addons-fw branch
elupus authored
1072 }
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1073 pAddon = pAddon->NextSibling();
074db86 merged: addons-fw branch
elupus authored
1074 }
1075 }
1076 }
1077
1078 bool CAddonMgr::GetAddon(const TYPE &type, const TiXmlNode *node, VECADDONPROPS &addons)
1079 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
1080 // id
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1081 const TiXmlNode *pNodeID = node->FirstChild("id");
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
1082 CStdString id;
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1083 if (pNodeID && pNodeID->FirstChild())
074db86 merged: addons-fw branch
elupus authored
1084 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1085 id = pNodeID->FirstChild()->Value();
074db86 merged: addons-fw branch
elupus authored
1086 }
1087 else
1088 return false;
1089
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1090 // will grab the version from description.xml
074db86 merged: addons-fw branch
elupus authored
1091 CStdString version;
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
1092 AddonProps props(id, type, version);
074db86 merged: addons-fw branch
elupus authored
1093
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
1094 // parent id if present
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1095 const TiXmlNode *pNodeParent = node->FirstChild("parentid");
1096 if (pNodeParent && pNodeParent->FirstChild())
074db86 merged: addons-fw branch
elupus authored
1097 {
2ca76f9 changed: all addons should be store below either special://home/addons o...
alcoheca authored
1098 props.parent = pNodeParent->FirstChild()->Value();
074db86 merged: addons-fw branch
elupus authored
1099 }
1100
1101 addons.insert(addons.end(), props);
1102 return true;
1103 }
1104
1105 } /* namespace ADDON */
1106
Something went wrong with that request. Please try again.