2 * Copyright (C) 2005-2010 Team XBMC
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)
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.
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
22 #include "Repository.h"
23 #include "tinyXML/tinyxml.h"
24 #include "filesystem/File.h"
25 #include "AddonDatabase.h"
26 #include "settings/Settings.h"
28 #include "utils/JobManager.h"
29 #include "addons/AddonInstaller.h"
30 #include "utils/log.h"
31 #include "utils/URIUtils.h"
32 #include "dialogs/GUIDialogYesNo.h"
33 #include "dialogs/GUIDialogKaiToast.h"
35 using namespace XFILE;
36 using namespace ADDON;
38 AddonPtr CRepository::Clone(const AddonPtr &self) const
40 CRepository* result = new CRepository(*this, self);
41 result->m_info = m_info;
42 result->m_checksum = m_checksum;
43 result->m_datadir = m_datadir;
44 result->m_compressed = m_compressed;
45 result->m_zipped = m_zipped;
46 return AddonPtr(result);
49 CRepository::CRepository(const AddonProps& props) :
56 CRepository::CRepository(const cp_extension_t *ext)
61 // read in the other props that we need
64 m_checksum = CAddonMgr::Get().GetExtValue(ext->configuration, "checksum");
65 m_compressed = CAddonMgr::Get().GetExtValue(ext->configuration, "info@compressed").Equals("true");
66 m_info = CAddonMgr::Get().GetExtValue(ext->configuration, "info");
67 m_datadir = CAddonMgr::Get().GetExtValue(ext->configuration, "datadir");
68 m_zipped = CAddonMgr::Get().GetExtValue(ext->configuration, "datadir@zip").Equals("true");
69 m_hashes = CAddonMgr::Get().GetExtValue(ext->configuration, "hashes").Equals("true");
73 CRepository::CRepository(const CRepository &rhs, const AddonPtr &self)
78 CRepository::~CRepository()
82 CStdString CRepository::Checksum()
84 if (!m_checksum.IsEmpty())
85 return FetchChecksum(m_checksum);
89 CStdString CRepository::FetchChecksum(const CStdString& url)
91 CSingleLock lock(m_critSection);
97 char* temp = new char[(size_t)file.GetLength()+1];
98 file.Read(temp,file.GetLength());
99 temp[file.GetLength()] = 0;
109 CStdString CRepository::GetAddonHash(const AddonPtr& addon)
114 checksum = FetchChecksum(addon->Path()+".md5");
115 size_t pos = checksum.find_first_of(" \n");
116 if (pos != CStdString::npos)
117 return checksum.Left(pos);
122 #define SET_IF_NOT_EMPTY(x,y) \
128 VECADDONS CRepository::Parse()
130 CSingleLock lock(m_critSection);
135 CStdString file = m_info;
139 CStdString opts = url.GetProtocolOptions();
142 url.SetProtocolOptions(opts+"Encoding=gzip");
147 if (doc.RootElement())
149 CAddonMgr::Get().AddonsFromRepoXML(doc.RootElement(), result);
150 for (IVECADDONS i = result.begin(); i != result.end(); ++i)
156 file.Format("%s/%s-%s.zip", addon->ID().c_str(), addon->ID().c_str(), addon->Version().c_str());
157 addon->Props().path = URIUtils::AddFileToFolder(m_datadir,file);
158 SET_IF_NOT_EMPTY(addon->Props().icon,URIUtils::AddFileToFolder(m_datadir,addon->ID()+"/icon.png"))
159 file.Format("%s/changelog-%s.txt", addon->ID().c_str(), addon->Version().c_str());
160 SET_IF_NOT_EMPTY(addon->Props().changelog,URIUtils::AddFileToFolder(m_datadir,file))
161 SET_IF_NOT_EMPTY(addon->Props().fanart,URIUtils::AddFileToFolder(m_datadir,addon->ID()+"/fanart.jpg"))
165 addon->Props().path = URIUtils::AddFileToFolder(m_datadir,addon->ID()+"/");
166 SET_IF_NOT_EMPTY(addon->Props().icon,URIUtils::AddFileToFolder(m_datadir,addon->ID()+"/icon.png"))
167 SET_IF_NOT_EMPTY(addon->Props().changelog,URIUtils::AddFileToFolder(m_datadir,addon->ID()+"/changelog.txt"))
168 SET_IF_NOT_EMPTY(addon->Props().fanart,URIUtils::AddFileToFolder(m_datadir,addon->ID()+"/fanart.jpg"))
176 CRepositoryUpdateJob::CRepositoryUpdateJob(const VECADDONS &repos)
181 bool CRepositoryUpdateJob::DoWork()
184 for (VECADDONS::const_iterator i = m_repos.begin(); i != m_repos.end(); ++i)
186 RepositoryPtr repo = boost::dynamic_pointer_cast<CRepository>(*i);
187 VECADDONS newAddons = GrabAddons(repo);
188 addons.insert(addons.end(), newAddons.begin(), newAddons.end());
194 CAddonDatabase database;
196 for (unsigned int i=0;i<addons.size();++i)
198 if (!CAddonInstaller::Get().CheckDependencies(addons[i]))
199 addons[i]->Props().broken = g_localizeStrings.Get(24044);
202 CAddonMgr::Get().GetAddon(addons[i]->ID(),addon);
203 if (addon && addons[i]->Version() > addon->Version() &&
204 !database.IsAddonBlacklisted(addons[i]->ID(),addons[i]->Version().c_str()))
206 if (g_settings.m_bAddonAutoUpdate || addon->Type() >= ADDON_VIZ_LIBRARY)
209 if (URIUtils::IsInternetStream(addons[i]->Path()))
210 referer.Format("Referer=%s-%s.zip",addon->ID().c_str(),addon->Version().c_str());
212 CAddonInstaller::Get().Install(addon->ID(), true, referer);
214 else if (g_settings.m_bAddonNotifications)
216 CGUIDialogKaiToast::QueueNotification(addon->Icon(),
217 g_localizeStrings.Get(24061),
218 addon->Name(),TOAST_DISPLAY_TIME,false,TOAST_DISPLAY_TIME);
221 if (!addons[i]->Props().broken.IsEmpty())
223 if (database.IsAddonBroken(addons[i]->ID()).IsEmpty())
225 if (addon && CGUIDialogYesNo::ShowAndGetInput(addons[i]->Name(),
226 g_localizeStrings.Get(24096),
227 g_localizeStrings.Get(24097),
229 database.DisableAddon(addons[i]->ID());
232 database.BreakAddon(addons[i]->ID(), addons[i]->Props().broken);
238 VECADDONS CRepositoryUpdateJob::GrabAddons(RepositoryPtr& repo)
240 CAddonDatabase database;
243 int idRepo = database.GetRepoChecksum(repo->ID(),checksum);
244 CStdString reposum = repo->Checksum();
246 if (idRepo == -1 || !checksum.Equals(reposum))
248 addons = repo->Parse();
250 database.AddRepository(repo->ID(),addons,reposum);
252 CLog::Log(LOGERROR,"Repository %s returned no add-ons, listing may have failed",repo->Name().c_str());
256 database.GetRepository(repo->ID(),addons);
257 database.SetRepoTimestamp(repo->ID(),CDateTime::GetCurrentDateTime().GetAsDBDateTime());