[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / addons / AddonDatabase.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "AddonDatabase.h"
22 #include "addons/AddonManager.h"
23 #include "utils/log.h"
24 #include "utils/Variant.h"
25 #include "utils/StringUtils.h"
26 #include "XBDateTime.h"
27 #include "addons/Service.h"
28 #include "dbwrappers/dataset.h"
29 #include "pvr/PVRManager.h"
30
31 using namespace ADDON;
32 using namespace std;
33
34 CAddonDatabase::CAddonDatabase()
35 {
36 }
37
38 CAddonDatabase::~CAddonDatabase()
39 {
40 }
41
42 bool CAddonDatabase::Open()
43 {
44   return CDatabase::Open();
45 }
46
47 bool CAddonDatabase::CreateTables()
48 {
49   try
50   {
51     CDatabase::CreateTables();
52
53     CLog::Log(LOGINFO, "create addon table");
54     m_pDS->exec("CREATE TABLE addon (id integer primary key, type text,"
55                 "name text, summary text, description text, stars integer,"
56                 "path text, addonID text, icon text, version text, "
57                 "changelog text, fanart text, author text, disclaimer text,"
58                 "minversion text)\n");
59
60     CLog::Log(LOGINFO, "create addon index");
61     m_pDS->exec("CREATE INDEX idxAddon ON addon(addonID)");
62
63     CLog::Log(LOGINFO, "create addonextra table");
64     m_pDS->exec("CREATE TABLE addonextra (id integer, key text, value text)\n");
65
66     CLog::Log(LOGINFO, "create addonextra index");
67     m_pDS->exec("CREATE INDEX idxAddonExtra ON addonextra(id)");
68
69     CLog::Log(LOGINFO, "create dependencies table");
70     m_pDS->exec("CREATE TABLE dependencies (id integer, addon text, version text, optional boolean)\n");
71     m_pDS->exec("CREATE INDEX idxDependencies ON dependencies(id)");
72
73     CLog::Log(LOGINFO, "create repo table");
74     m_pDS->exec("CREATE TABLE repo (id integer primary key, addonID text,"
75                 "checksum text, lastcheck text)\n");
76
77     CLog::Log(LOGINFO, "create addonlinkrepo table");
78     m_pDS->exec("CREATE TABLE addonlinkrepo (idRepo integer, idAddon integer)\n");
79     m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_1 ON addonlinkrepo ( idAddon, idRepo )\n");
80     m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_2 ON addonlinkrepo ( idRepo, idAddon )\n");
81
82     CLog::Log(LOGINFO, "create disabled table");
83     m_pDS->exec("CREATE TABLE disabled (id integer primary key, addonID text)\n");
84     m_pDS->exec("CREATE UNIQUE INDEX idxDisabled ON disabled(addonID)");
85
86     CLog::Log(LOGINFO, "create broken table");
87     m_pDS->exec("CREATE TABLE broken (id integer primary key, addonID text, reason text)\n");
88     m_pDS->exec("CREATE UNIQUE INDEX idxBroken ON broken(addonID)");
89
90     CLog::Log(LOGINFO, "create blacklist table");
91     m_pDS->exec("CREATE TABLE blacklist (id integer primary key, addonID text, version text)\n");
92     m_pDS->exec("CREATE UNIQUE INDEX idxBlack ON blacklist(addonID)");
93   }
94   catch (...)
95   {
96     CLog::Log(LOGERROR, "%s unable to create tables", __FUNCTION__);
97     return false;
98   }
99
100   return true;
101 }
102
103 bool CAddonDatabase::UpdateOldVersion(int version)
104 {
105   if (version < 13)
106   {
107     m_pDS->exec("CREATE TABLE dependencies (id integer, addon text, version text, optional boolean)\n");
108     m_pDS->exec("CREATE INDEX idxDependencies ON dependencies(id)");
109   }
110   if (version < 14)
111   {
112     m_pDS->exec("ALTER TABLE addon add minversion text");
113   }
114   if (version < 15)
115   {
116     m_pDS->exec("CREATE TABLE blacklist (id integer primary key, addonID text, version text)\n");
117     m_pDS->exec("CREATE UNIQUE INDEX idxBlack ON blacklist(addonID)");
118   }
119   return true;
120 }
121
122 int CAddonDatabase::AddAddon(const AddonPtr& addon,
123                              int idRepo)
124 {
125   try
126   {
127     if (NULL == m_pDB.get()) return -1;
128     if (NULL == m_pDS.get()) return -1;
129
130     bool bDisablePVRAddon = addon->Type() == ADDON_PVRDLL && !HasAddon(addon->ID());
131
132     CStdString sql = PrepareSQL("insert into addon (id, type, name, summary,"
133                                "description, stars, path, icon, changelog, "
134                                "fanart, addonID, version, author, disclaimer, minversion)"
135                                " values(NULL, '%s', '%s', '%s', '%s', %i,"
136                                "'%s', '%s', '%s', '%s', '%s','%s','%s','%s','%s')",
137                                TranslateType(addon->Type(),false).c_str(),
138                                addon->Name().c_str(), addon->Summary().c_str(),
139                                addon->Description().c_str(),addon->Stars(),
140                                addon->Path().c_str(), addon->Props().icon.c_str(),
141                                addon->ChangeLog().c_str(),addon->FanArt().c_str(),
142                                addon->ID().c_str(), addon->Version().c_str(),
143                                addon->Author().c_str(),addon->Disclaimer().c_str(),
144                                addon->MinVersion().c_str());
145     m_pDS->exec(sql.c_str());
146     int idAddon = (int)m_pDS->lastinsertid();
147
148     sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon);
149     m_pDS->exec(sql.c_str());
150
151     const InfoMap &info = addon->ExtraInfo();
152     for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i)
153     {
154       sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str());
155       m_pDS->exec(sql.c_str());
156     }
157     const ADDONDEPS &deps = addon->GetDeps();
158     for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i)
159     {
160       sql = PrepareSQL("insert into dependencies(id, addon, version, optional) values (%i, '%s', '%s', %i)", idAddon, i->first.c_str(), i->second.first.c_str(), i->second.second ? 1 : 0);
161       m_pDS->exec(sql.c_str());
162     }
163     // these need to be configured
164     if (bDisablePVRAddon)
165       DisableAddon(addon->ID(), true);
166     return idAddon;
167   }
168   catch (...)
169   {
170     CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str());
171   }
172   return -1;
173 }
174
175 bool CAddonDatabase::GetAddon(const CStdString& id, AddonPtr& addon)
176 {
177   try
178   {
179     if (NULL == m_pDB.get()) return false;
180     if (NULL == m_pDS2.get()) return false;
181
182     // there may be multiple addons with this id (eg from different repositories) in the database,
183     // so we want to retrieve the latest version.  Order by version won't work as the database
184     // won't know that 1.10 > 1.2, so grab them all and order outside
185     CStdString sql = PrepareSQL("select id,version from addon where addonID='%s'",id.c_str());
186     m_pDS2->query(sql.c_str());
187
188     if (m_pDS2->eof())
189       return false;
190
191     AddonVersion maxversion("0.0.0");
192     int maxid = 0;
193     while (!m_pDS2->eof())
194     {
195       AddonVersion version(m_pDS2->fv(1).get_asString());
196       if (version > maxversion)
197       {
198         maxid = m_pDS2->fv(0).get_asInt();
199         maxversion = version;
200       }
201       m_pDS2->next();
202     }
203     return GetAddon(maxid,addon);
204   }
205   catch (...)
206   {
207     CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
208   }
209   addon.reset();
210   return false;
211 }
212
213 bool CAddonDatabase::GetRepoForAddon(const CStdString& addonID, CStdString& repo)
214 {
215   try
216   {
217     if (NULL == m_pDB.get()) return false;
218     if (NULL == m_pDS2.get()) return false;
219
220     CStdString sql = PrepareSQL("select repo.addonID from repo join addonlinkrepo on repo.id=addonlinkrepo.idRepo join addon on addonlinkrepo.idAddon=addon.id where addon.addonID like '%s'", addonID.c_str()); 
221     m_pDS2->query(sql.c_str());
222     if (!m_pDS2->eof())
223     {
224       repo = m_pDS2->fv(0).get_asString();
225       m_pDS2->close();
226       return true;
227     }
228   }
229   catch (...)
230   {
231     CLog::Log(LOGERROR, "%s failed for addon %s", __FUNCTION__, addonID.c_str());
232   }
233   return false;
234 }
235
236 bool CAddonDatabase::GetAddon(int id, AddonPtr& addon)
237 {
238   try
239   {
240     if (NULL == m_pDB.get()) return false;
241     if (NULL == m_pDS2.get()) return false;
242
243     CStdString sql = PrepareSQL("select * from addon where id=%i",id);
244     m_pDS2->query(sql.c_str());
245     if (!m_pDS2->eof())
246     {
247       AddonProps props(m_pDS2->fv("addonID" ).get_asString(),
248                        TranslateType(m_pDS2->fv("type").get_asString()),
249                        m_pDS2->fv("version").get_asString(),
250                        m_pDS2->fv("minversion").get_asString());
251       props.name = m_pDS2->fv("name").get_asString();
252       props.summary = m_pDS2->fv("summary").get_asString();
253       props.description = m_pDS2->fv("description").get_asString();
254       props.changelog = m_pDS2->fv("changelog").get_asString();
255       props.path = m_pDS2->fv("path").get_asString();
256       props.icon = m_pDS2->fv("icon").get_asString();
257       props.fanart = m_pDS2->fv("fanart").get_asString();
258       props.author = m_pDS2->fv("author").get_asString();
259       props.disclaimer = m_pDS2->fv("disclaimer").get_asString();
260       sql = PrepareSQL("select reason from broken where addonID='%s'",props.id.c_str());
261       m_pDS2->query(sql.c_str());
262       if (!m_pDS2->eof())
263         props.broken = m_pDS2->fv(0).get_asString();
264
265       sql = PrepareSQL("select key,value from addonextra where id=%i", id);
266       m_pDS2->query(sql.c_str());
267       while (!m_pDS2->eof())
268       {
269         props.extrainfo.insert(make_pair(m_pDS2->fv(0).get_asString(), m_pDS2->fv(1).get_asString()));
270         m_pDS2->next();
271       }
272
273       sql = PrepareSQL("select addon,version,optional from dependencies where id=%i", id);
274       m_pDS2->query(sql.c_str());
275       while (!m_pDS2->eof())
276       {
277         props.dependencies.insert(make_pair(m_pDS2->fv(0).get_asString(), make_pair(AddonVersion(m_pDS2->fv(1).get_asString()), m_pDS2->fv(2).get_asBool())));
278         m_pDS2->next();
279       }
280
281       addon = CAddonMgr::AddonFromProps(props);
282       return NULL != addon.get();
283     }
284   }
285   catch (...)
286   {
287     CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
288   }
289   addon.reset();
290   return false;
291 }
292
293 bool CAddonDatabase::GetAddons(VECADDONS& addons)
294 {
295   try
296   {
297     if (NULL == m_pDB.get()) return false;
298     if (NULL == m_pDS2.get()) return false;
299
300     CStdString sql = PrepareSQL("select distinct addonID from addon");
301     m_pDS->query(sql.c_str());
302     while (!m_pDS->eof())
303     {
304       sql = PrepareSQL("select id from addon where addonID='%s' order by version desc",m_pDS->fv(0).get_asString().c_str());
305       m_pDS2->query(sql.c_str());
306       AddonPtr addon;
307       if (GetAddon(m_pDS2->fv(0).get_asInt(),addon))
308         addons.push_back(addon);
309       m_pDS->next();
310     }
311     m_pDS->close();
312     return true;
313   }
314   catch (...)
315   {
316     CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
317   }
318   return false;
319 }
320
321 void CAddonDatabase::DeleteRepository(const CStdString& id)
322 {
323   try
324   {
325     if (NULL == m_pDB.get()) return;
326     if (NULL == m_pDS.get()) return;
327
328     CStdString sql = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
329     m_pDS->query(sql.c_str());
330     if (!m_pDS->eof())
331       DeleteRepository(m_pDS->fv(0).get_asInt());
332   }
333   catch (...)
334   {
335     CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
336   }
337 }
338
339 void CAddonDatabase::DeleteRepository(int idRepo)
340 {
341   try
342   {
343     if (NULL == m_pDB.get()) return;
344     if (NULL == m_pDS.get()) return;
345
346     CStdString sql = PrepareSQL("delete from repo where id=%i",idRepo);
347     m_pDS->exec(sql.c_str());
348     sql = PrepareSQL("delete from addon where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
349     m_pDS->exec(sql.c_str());
350     sql = PrepareSQL("delete from addonextra where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
351     m_pDS->exec(sql.c_str());
352     sql = PrepareSQL("delete from dependencies where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
353     m_pDS->exec(sql.c_str());
354     sql = PrepareSQL("delete from addonlinkrepo where idRepo=%i",idRepo);
355     m_pDS->exec(sql.c_str());
356
357   }
358   catch (...)
359   {
360     CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, idRepo);
361   }
362 }
363
364 int CAddonDatabase::AddRepository(const CStdString& id, const VECADDONS& addons, const CStdString& checksum)
365 {
366   try
367   {
368     if (NULL == m_pDB.get()) return -1;
369     if (NULL == m_pDS.get()) return -1;
370
371     CStdString sql;
372     int idRepo = GetRepoChecksum(id,sql);
373     if (idRepo > -1)
374       DeleteRepository(idRepo);
375
376     BeginTransaction();
377
378     CDateTime time = CDateTime::GetCurrentDateTime();
379     sql = PrepareSQL("insert into repo (id,addonID,checksum,lastcheck) values (NULL,'%s','%s','%s')",id.c_str(),checksum.c_str(),time.GetAsDBDateTime().c_str());
380     m_pDS->exec(sql.c_str());
381     idRepo = (int)m_pDS->lastinsertid();
382     for (unsigned int i=0;i<addons.size();++i)
383       AddAddon(addons[i],idRepo);
384
385     CommitTransaction();
386     return idRepo;
387   }
388   catch (...)
389   {
390     CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
391     RollbackTransaction();
392   }
393   return -1;
394 }
395
396 int CAddonDatabase::GetRepoChecksum(const std::string& id, std::string& checksum)
397 {
398   try
399   {
400     if (NULL == m_pDB.get()) return -1;
401     if (NULL == m_pDS.get()) return -1;
402
403     std::string strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
404     m_pDS->query(strSQL.c_str());
405     if (!m_pDS->eof())
406     {
407       checksum = m_pDS->fv("checksum").get_asString();
408       return m_pDS->fv("id").get_asInt();
409     }
410   }
411   catch (...)
412   {
413     CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
414   }
415   checksum.clear();
416   return -1;
417 }
418
419 CDateTime CAddonDatabase::GetRepoTimestamp(const CStdString& id)
420 {
421   CDateTime date;
422   try
423   {
424     if (NULL == m_pDB.get()) return date;
425     if (NULL == m_pDS.get()) return date;
426
427     CStdString strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
428     m_pDS->query(strSQL.c_str());
429     if (!m_pDS->eof())
430     {
431       date.SetFromDBDateTime(m_pDS->fv("lastcheck").get_asString());
432       return date;
433     }
434   }
435   catch (...)
436   {
437     CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
438   }
439   return date;
440 }
441
442 bool CAddonDatabase::SetRepoTimestamp(const CStdString& id, const CStdString& time)
443 {
444   try
445   {
446     if (NULL == m_pDB.get()) return false;
447     if (NULL == m_pDS.get()) return false;
448
449     CStdString sql = PrepareSQL("update repo set lastcheck='%s' where addonID='%s'",time.c_str(),id.c_str());
450     m_pDS->exec(sql.c_str());
451
452     return true;
453   }
454   catch (...)
455   {
456     CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
457   }
458   return false;
459 }
460
461 bool CAddonDatabase::GetRepository(int id, VECADDONS& addons)
462 {
463   try
464   {
465     if (NULL == m_pDB.get()) return false;
466     if (NULL == m_pDS.get()) return false;
467
468     CStdString strSQL = PrepareSQL("select * from addonlinkrepo where idRepo=%i",id);
469     m_pDS->query(strSQL.c_str());
470     while (!m_pDS->eof())
471     {
472       AddonPtr addon;
473       if (GetAddon(m_pDS->fv("idAddon").get_asInt(),addon))
474         addons.push_back(addon);
475       m_pDS->next();
476     }
477     return true;
478   }
479   catch (...)
480   {
481     CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, id);
482   }
483   return false;
484 }
485
486 bool CAddonDatabase::GetRepository(const CStdString& id, VECADDONS& addons)
487 {
488   try
489   {
490     if (NULL == m_pDB.get()) return false;
491     if (NULL == m_pDS.get()) return false;
492
493     CStdString strSQL = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
494     m_pDS->query(strSQL.c_str());
495     if (!m_pDS->eof())
496       return GetRepository(m_pDS->fv(0).get_asInt(),addons);
497   }
498   catch (...)
499   {
500     CLog::Log(LOGERROR, "%s failed on repo %s", __FUNCTION__, id.c_str());
501   }
502   return false;
503 }
504
505 bool CAddonDatabase::Search(const CStdString& search, VECADDONS& addons)
506 {
507   try
508   {
509     if (NULL == m_pDB.get()) return false;
510     if (NULL == m_pDS.get()) return false;
511
512     CStdString strSQL;
513     strSQL=PrepareSQL("SELECT id FROM addon WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%'", search.c_str(), search.c_str(), search.c_str());
514     CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
515
516     if (!m_pDS->query(strSQL.c_str())) return false;
517     if (m_pDS->num_rows() == 0) return false;
518
519     while (!m_pDS->eof())
520     {
521       AddonPtr addon;
522       GetAddon(m_pDS->fv(0).get_asInt(),addon);
523       if (addon->Type() >= ADDON_UNKNOWN+1 && addon->Type() < ADDON_SCRAPER_LIBRARY)
524         addons.push_back(addon);
525       m_pDS->next();
526     }
527     m_pDS->close();
528     return true;
529   }
530   catch (...)
531   {
532     CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
533   }
534   return false;
535 }
536
537 void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon,
538                                            CFileItemPtr& pItem)
539 {
540   pItem->SetProperty("Addon.ID", addon->ID());
541   pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true));
542   pItem->SetProperty("Addon.intType", TranslateType(addon->Type()));
543   pItem->SetProperty("Addon.Name", addon->Name());
544   pItem->SetProperty("Addon.Version", addon->Version().c_str());
545   pItem->SetProperty("Addon.Summary", addon->Summary());
546   pItem->SetProperty("Addon.Description", addon->Description());
547   pItem->SetProperty("Addon.Creator", addon->Author());
548   pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer());
549   pItem->SetProperty("Addon.Rating", addon->Stars());
550   CStdString starrating = StringUtils::Format("rating%d.png", addon->Stars());
551   pItem->SetProperty("Addon.StarRating",starrating);
552   pItem->SetProperty("Addon.Path", addon->Path());
553   if (addon->Props().broken == "DEPSNOTMET")
554     pItem->SetProperty("Addon.Broken", g_localizeStrings.Get(24044));
555   else
556     pItem->SetProperty("Addon.Broken", addon->Props().broken);
557   std::map<CStdString,CStdString>::iterator it = 
558                     addon->Props().extrainfo.find("language");
559   if (it != addon->Props().extrainfo.end())
560     pItem->SetProperty("Addon.Language", it->second);
561 }
562
563 bool CAddonDatabase::DisableAddon(const CStdString &addonID, bool disable /* = true */)
564 {
565   try
566   {
567     if (NULL == m_pDB.get()) return false;
568     if (NULL == m_pDS.get()) return false;
569
570     if (disable)
571     {
572       if (!IsAddonDisabled(addonID)) // Enabled
573       {
574         CStdString sql = PrepareSQL("insert into disabled(id, addonID) values(NULL, '%s')", addonID.c_str());
575         m_pDS->exec(sql);
576
577         AddonPtr addon;
578         // If the addon is a service, stop it
579         if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) && addon)
580         {
581           boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(addon);
582           if (service)
583             service->Stop();
584         }
585         // restart the pvr manager when disabling a pvr add-on with the pvr manager enabled
586         else if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) && addon &&
587             PVR::CPVRManager::Get().IsStarted())
588           PVR::CPVRManager::Get().Start(true);
589
590         return true;
591       }
592       return false; // already disabled or failed query
593     }
594     else
595     {
596       bool disabled = IsAddonDisabled(addonID); //we need to know if service addon is running
597       CStdString sql = PrepareSQL("delete from disabled where addonID='%s'", addonID.c_str());
598       m_pDS->exec(sql);
599
600       AddonPtr addon;
601       // If the addon is a service, start it
602       if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) && addon && disabled)
603       {
604         boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(addon);
605         if (service)
606           service->Start();
607       }
608       // (re)start the pvr manager when enabling a pvr add-on
609       else if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) && addon)
610         PVR::CPVRManager::Get().Start(true);
611     }
612     return true;
613   }
614   catch (...)
615   {
616     CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addonID.c_str());
617   }
618   return false;
619 }
620
621 bool CAddonDatabase::BreakAddon(const CStdString &addonID, const CStdString& reason)
622 {
623   try
624   {
625     if (NULL == m_pDB.get()) return false;
626     if (NULL == m_pDS.get()) return false;
627
628     CStdString sql = PrepareSQL("delete from broken where addonID='%s'", addonID.c_str());
629     m_pDS->exec(sql);
630
631     if (!reason.IsEmpty())
632     { // broken
633       sql = PrepareSQL("insert into broken(id, addonID, reason) values(NULL, '%s', '%s')", addonID.c_str(),reason.c_str());
634       m_pDS->exec(sql);
635     }
636     return true;
637   }
638   catch (...)
639   {
640     CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addonID.c_str());
641   }
642   return false;
643 }
644
645 bool CAddonDatabase::HasAddon(const CStdString &addonID)
646 {
647   CStdString strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
648   CStdString strHasAddon = GetSingleValue("addon", "id", strWhereClause);
649   
650   return !strHasAddon.IsEmpty();
651 }
652
653 bool CAddonDatabase::IsAddonDisabled(const CStdString &addonID)
654 {
655   try
656   {
657     if (NULL == m_pDB.get()) return false;
658     if (NULL == m_pDS.get()) return false;
659
660     CStdString sql = PrepareSQL("select id from disabled where addonID='%s'", addonID.c_str());
661     m_pDS->query(sql.c_str());
662     bool ret = !m_pDS->eof(); // in the disabled table -> disabled
663     m_pDS->close();
664     return ret;
665   }
666   catch (...)
667   {
668     CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonID.c_str());
669   }
670   return false;
671 }
672
673 bool CAddonDatabase::IsSystemPVRAddonEnabled(const CStdString &addonID)
674 {
675   CStdString strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
676   CStdString strEnabled = GetSingleValue("pvrenabled", "id", strWhereClause);
677
678   return !strEnabled.IsEmpty();
679 }
680
681 CStdString CAddonDatabase::IsAddonBroken(const CStdString &addonID)
682 {
683   try
684   {
685     if (NULL == m_pDB.get()) return "";
686     if (NULL == m_pDS.get()) return "";
687
688     CStdString sql = PrepareSQL("select reason from broken where addonID='%s'", addonID.c_str());
689     m_pDS->query(sql.c_str());
690     CStdString ret;
691     if (!m_pDS->eof())
692       ret = m_pDS->fv(0).get_asString();
693     m_pDS->close();
694     return ret;
695   }
696   catch (...)
697   {
698     CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonID.c_str());
699   }
700   return "";
701 }
702
703 bool CAddonDatabase::HasDisabledAddons()
704 {
705   try
706   {
707     if (NULL == m_pDB.get()) return false;
708     if (NULL == m_pDS.get()) return false;
709
710     m_pDS->query("select count(id) from disabled");
711     bool ret = !m_pDS->eof() && m_pDS->fv(0).get_asInt() > 0; // have rows -> have disabled addons
712     m_pDS->close();
713     return ret;
714   }
715   catch (...)
716   {
717     CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
718   }
719   return false;
720 }
721
722 bool CAddonDatabase::BlacklistAddon(const CStdString& addonID,
723                                     const CStdString& version)
724 {
725   try
726   {
727     if (NULL == m_pDB.get()) return false;
728     if (NULL == m_pDS.get()) return false;
729
730     CStdString sql = PrepareSQL("insert into blacklist(id, addonID, version) values(NULL, '%s', '%s')", addonID.c_str(),version.c_str());
731     m_pDS->exec(sql);
732
733     return true;
734   }
735   catch (...)
736   {
737     CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
738   }
739   return false;
740 }
741
742 bool CAddonDatabase::IsAddonBlacklisted(const CStdString& addonID,
743                                         const CStdString& version)
744 {
745   CStdString where = PrepareSQL("addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
746   return !GetSingleValue("blacklist","addonID",where).IsEmpty();
747 }
748
749 bool CAddonDatabase::RemoveAddonFromBlacklist(const CStdString& addonID,
750                                               const CStdString& version)
751 {
752   try
753   {
754     if (NULL == m_pDB.get()) return false;
755     if (NULL == m_pDS.get()) return false;
756
757     CStdString sql = PrepareSQL("delete from blacklist where addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
758     m_pDS->exec(sql);
759     return true;
760   }
761   catch (...)
762   {
763     CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
764   }
765   return false;
766 }