void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items, bool reposAsFolders) { items.ClearItems(); for (unsigned i=0; i < addons.size(); i++) { AddonPtr addon = addons[i]; CFileItemPtr pItem; if (reposAsFolders && addon->Type() == ADDON_REPOSITORY) pItem = FileItemFromAddon(addon, "addons://", true); else pItem = FileItemFromAddon(addon, path.Get(), false); AddonPtr addon2; if (CAddonMgr::Get().GetAddon(addon->ID(),addon2)) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(305)); else if (CAddonMgr::Get().IsAddonDisabled(addon->ID())) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24023)); if (addon->Props().broken == "DEPSNOTMET") pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24049)); else if (!addon->Props().broken.empty()) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24098)); if (addon2 && addon2->Version() < addon->Version()) { pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); pItem->SetProperty("Addon.UpdateAvail", true); } CAddonDatabase::SetPropertiesFromAddon(addon,pItem); items.Add(pItem); } }
void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon, CFileItemPtr& pItem) { pItem->SetProperty("Addon.ID", addon->ID()); pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true)); pItem->SetProperty("Addon.intType", TranslateType(addon->Type())); pItem->SetProperty("Addon.Name", addon->Name()); pItem->SetProperty("Addon.Version", addon->Version().asString()); pItem->SetProperty("Addon.Summary", addon->Summary()); pItem->SetProperty("Addon.Description", addon->Description()); pItem->SetProperty("Addon.Creator", addon->Author()); pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); pItem->SetProperty("Addon.Rating", addon->Stars()); std::string starrating = StringUtils::Format("rating%d.png", addon->Stars()); pItem->SetProperty("Addon.StarRating",starrating); pItem->SetProperty("Addon.Path", addon->Path()); if (addon->Props().broken == "DEPSNOTMET") pItem->SetProperty("Addon.Broken", g_localizeStrings.Get(24044)); else pItem->SetProperty("Addon.Broken", addon->Props().broken); std::map<std::string,std::string>::iterator it = addon->Props().extrainfo.find("language"); if (it != addon->Props().extrainfo.end()) pItem->SetProperty("Addon.Language", it->second); }
bool CAddonMgr::GetAllOutdatedAddons(VECADDONS &addons, bool getLocalVersion /*= false*/) { CSingleLock lock(m_critSection); for (int i = ADDON_UNKNOWN+1; i < ADDON_MAX; ++i) { VECADDONS temp; if (CAddonMgr::Get().GetAddons((TYPE)i, temp, true)) { AddonPtr repoAddon; for (unsigned int j = 0; j < temp.size(); j++) { // Ignore duplicates due to add-ons with multiple extension points bool found = false; for (VECADDONS::const_iterator addonIt = addons.begin(); addonIt != addons.end(); ++addonIt) { if ((*addonIt)->ID() == temp[j]->ID()) found = true; } if (found || !m_database.GetAddon(temp[j]->ID(), repoAddon)) continue; if (temp[j]->Version() < repoAddon->Version() && !m_database.IsAddonBlacklisted(temp[j]->ID(), repoAddon->Version().asString().c_str())) { if (getLocalVersion) repoAddon->Props().version = temp[j]->Version(); addons.push_back(repoAddon); } } } } return !addons.empty(); }
bool CAddonInstaller::InstallFromZip(const std::string &path) { if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER)) return false; // grab the descriptive XML document from the zip, and read it in CFileItemList items; // BUG: some zip files return a single item (root folder) that we think is stored, so we don't use the zip:// protocol CURL pathToUrl(path); CURL zipDir = URIUtils::CreateArchivePath("zip", pathToUrl, ""); if (!CDirectory::GetDirectory(zipDir, items) || items.Size() != 1 || !items[0]->m_bIsFolder) { CGUIDialogKaiToast::QueueNotification("", path, g_localizeStrings.Get(24045), TOAST_DISPLAY_TIME, false); return false; } // TODO: possibly add support for github generated zips here? std::string archive = URIUtils::AddFileToFolder(items[0]->GetPath(), "addon.xml"); CXBMCTinyXML xml; AddonPtr addon; if (xml.LoadFile(archive) && CAddonMgr::Get().LoadAddonDescriptionFromMemory(xml.RootElement(), addon)) { // set the correct path addon->Props().path = items[0]->GetPath(); addon->Props().icon = URIUtils::AddFileToFolder(items[0]->GetPath(), "icon.png"); // install the addon return DoInstall(addon); } CGUIDialogKaiToast::QueueNotification("", path, g_localizeStrings.Get(24045), TOAST_DISPLAY_TIME, false); return false; }
void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items, bool reposAsFolders) { CStdString xbmcPath = _P("special://xbmc/addons"); items.ClearItems(); for (unsigned i=0; i < addons.size(); i++) { AddonPtr addon = addons[i]; CFileItemPtr pItem; if (reposAsFolders && addon->Type() == ADDON_REPOSITORY) pItem = FileItemFromAddon(addon, "addons://", true); else pItem = FileItemFromAddon(addon, path.Get(), false); AddonPtr addon2; if (CAddonMgr::Get().GetAddon(addon->ID(),addon2)) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(305)); else if ((addon->Type() == ADDON_PVRDLL) && (CStdString(pItem->GetProperty("Addon.Path").asString()).Left(xbmcPath.size()).Equals(xbmcPath))) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24023)); if (!addon->Props().broken.IsEmpty()) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24098)); if (addon2 && addon2->Version() < addon->Version()) { pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); pItem->SetProperty("Addon.UpdateAvail", true); } CAddonDatabase::SetPropertiesFromAddon(addon,pItem); items.Add(pItem); } }
void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items, bool reposAsFolders) { CStdString xbmcPath = CSpecialProtocol::TranslatePath("special://xbmc/addons"); items.ClearItems(); CAddonDatabase db; db.Open(); for (unsigned i=0; i < addons.size(); i++) { AddonPtr addon = addons[i]; CFileItemPtr pItem; if (reposAsFolders && addon->Type() == ADDON_REPOSITORY) pItem = FileItemFromAddon(addon, "addons://", true); else pItem = FileItemFromAddon(addon, path.Get(), false); AddonPtr addon2; if (CAddonMgr::Get().GetAddon(addon->ID(),addon2)) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(305)); else if (db.IsOpen() && db.IsAddonDisabled(addon->ID())) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24023)); if (!addon->Props().broken.IsEmpty()) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24098)); if (addon2 && addon2->Version() < addon->Version()) { pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); pItem->SetProperty("Addon.UpdateAvail", true); } CAddonDatabase::SetPropertiesFromAddon(addon,pItem); items.Add(pItem); } db.Close(); }
bool CAddonInstaller::InstallFromZip(const CStdString &path) { // grab the descriptive XML document from the zip, and read it in CFileItemList items; // BUG: some zip files return a single item (root folder) that we think is stored, so we don't use the zip:// protocol CStdString zipDir; URIUtils::CreateArchivePath(zipDir, "zip", path, ""); if (!CDirectory::GetDirectory(zipDir, items) || items.Size() != 1 || !items[0]->m_bIsFolder) { CGUIDialogKaiToast::QueueNotification("", path, g_localizeStrings.Get(24045), TOAST_DISPLAY_TIME, false); return false; } // TODO: possibly add support for github generated zips here? CStdString archive = URIUtils::AddFileToFolder(items[0]->GetPath(), "addon.xml"); TiXmlDocument xml; AddonPtr addon; if (xml.LoadFile(archive) && CAddonMgr::Get().LoadAddonDescriptionFromMemory(xml.RootElement(), addon)) { // set the correct path addon->Props().path = path; // install the addon return DoInstall(addon); } CGUIDialogKaiToast::QueueNotification("", path, g_localizeStrings.Get(24045), TOAST_DISPLAY_TIME, false); return false; }
bool CAddonInstaller::InstallFromZip(const CStdString &path) { // grab the descriptive XML document from the zip, and read it in CFileItemList items; // BUG: some zip files return a single item (root folder) that we think is stored, so we don't use the zip:// protocol CStdString zipDir; URIUtils::CreateArchivePath(zipDir, "zip", path, ""); if (!CDirectory::GetDirectory(zipDir, items) || items.Size() != 1 || !items[0]->m_bIsFolder) return false; // TODO: possibly add support for github generated zips here? CStdString archive = URIUtils::AddFileToFolder(items[0]->m_strPath, "addon.xml"); TiXmlDocument xml; AddonPtr addon; if (xml.LoadFile(archive) && CAddonMgr::Get().LoadAddonDescriptionFromMemory(xml.RootElement(), addon)) { // set the correct path addon->Props().path = path; // install the addon CSingleLock lock(m_critSection); if (m_downloadJobs.find(addon->ID()) != m_downloadJobs.end()) return false; unsigned int jobID = CJobManager::GetInstance().AddJob(new CAddonInstallJob(addon), this); m_downloadJobs.insert(make_pair(addon->ID(), CDownloadJob(jobID))); return true; } return false; }
int CAddonDatabase::AddAddon(const AddonPtr& addon, int idRepo) { try { if (NULL == m_pDB.get()) return -1; if (NULL == m_pDS.get()) return -1; bool bDisablePVRAddon = addon->Type() == ADDON_PVRDLL && !HasAddon(addon->ID()); CStdString sql = PrepareSQL("insert into addon (id, type, name, summary," "description, stars, path, icon, changelog, " "fanart, addonID, version, author, disclaimer, minversion)" " values(NULL, '%s', '%s', '%s', '%s', %i," "'%s', '%s', '%s', '%s', '%s','%s','%s','%s','%s')", TranslateType(addon->Type(),false).c_str(), addon->Name().c_str(), addon->Summary().c_str(), addon->Description().c_str(),addon->Stars(), addon->Path().c_str(), addon->Props().icon.c_str(), addon->ChangeLog().c_str(),addon->FanArt().c_str(), addon->ID().c_str(), addon->Version().c_str(), addon->Author().c_str(),addon->Disclaimer().c_str(), addon->MinVersion().c_str()); m_pDS->exec(sql.c_str()); int idAddon = (int)m_pDS->lastinsertid(); sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon); m_pDS->exec(sql.c_str()); const InfoMap &info = addon->ExtraInfo(); for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i) { sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str()); m_pDS->exec(sql.c_str()); } const ADDONDEPS &deps = addon->GetDeps(); for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i) { 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); m_pDS->exec(sql.c_str()); } // these need to be configured if (bDisablePVRAddon) DisableAddon(addon->ID(), true); return idAddon; } catch (...) { CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str()); } return -1; }
void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon, CFileItemPtr& pItem) { pItem->SetProperty("Addon.ID", addon->ID()); pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true)); pItem->SetProperty("Addon.intType", TranslateType(addon->Type())); pItem->SetProperty("Addon.Name", addon->Name()); pItem->SetProperty("Addon.Version", addon->Version().c_str()); pItem->SetProperty("Addon.Summary", addon->Summary()); pItem->SetProperty("Addon.Description", addon->Description()); pItem->SetProperty("Addon.Creator", addon->Author()); pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); pItem->SetProperty("Addon.Rating", addon->Stars()); CStdString starrating; starrating.Format("rating%d.png", addon->Stars()); pItem->SetProperty("Addon.StarRating",starrating); pItem->SetProperty("Addon.Path", addon->Path()); pItem->SetProperty("Addon.Broken", addon->Props().broken); std::map<CStdString,CStdString>::iterator it = addon->Props().extrainfo.find("language"); if (it != addon->Props().extrainfo.end()) pItem->SetProperty("Addon.Language", it->second); }
bool CAddonMgr::CanAddonBeInstalled(const AddonPtr& addon) { if (addon == NULL) return false; CSingleLock lock(m_critSection); // can't install already installed addon if (IsAddonInstalled(addon->ID())) return false; // can't install broken addons if (!addon->Props().broken.empty()) return false; return true; }
void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon, CFileItemPtr& pItem) { pItem->SetProperty("Addon.ID", addon->ID()); pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true)); pItem->SetProperty("Addon.intType", TranslateType(addon->Type())); pItem->SetProperty("Addon.Name", addon->Name()); pItem->SetProperty("Addon.Version", addon->Version().c_str()); pItem->SetProperty("Addon.Summary", addon->Summary()); pItem->SetProperty("Addon.Description", addon->Description()); pItem->SetProperty("Addon.Creator", addon->Author()); pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); pItem->SetProperty("Addon.Rating", addon->Stars()); CStdString starrating; starrating.Format("rating%d.png", addon->Stars()); pItem->SetProperty("Addon.StarRating",starrating); pItem->SetProperty("Addon.Path", addon->Path()); pItem->SetProperty("Addon.Broken", addon->Props().broken); }
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::GetInstance().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::GetInstance().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; }
bool CAddonInstaller::InstallFromZip(const std::string &path) { if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER)) return false; CLog::Log(LOGDEBUG, "CAddonInstaller: installing from zip '%s'", CURL::GetRedacted(path).c_str()); // grab the descriptive XML document from the zip, and read it in CFileItemList items; // BUG: some zip files return a single item (root folder) that we think is stored, so we don't use the zip:// protocol CURL pathToUrl(path); CURL zipDir = URIUtils::CreateArchivePath("zip", pathToUrl, ""); if (!CDirectory::GetDirectory(zipDir, items) || items.Size() != 1 || !items[0]->m_bIsFolder) { CEventLog::GetInstance().AddWithNotification( EventPtr(new CNotificationEvent(EventLevelError, 24045, StringUtils::Format(g_localizeStrings.Get(24143).c_str(), path.c_str()))), false); return false; } // TODO: possibly add support for github generated zips here? std::string archive = URIUtils::AddFileToFolder(items[0]->GetPath(), "addon.xml"); CXBMCTinyXML xml; AddonPtr addon; if (xml.LoadFile(archive) && CAddonMgr::GetInstance().LoadAddonDescriptionFromMemory(xml.RootElement(), addon)) { // set the correct path addon->Props().path = items[0]->GetPath(); addon->Props().icon = URIUtils::AddFileToFolder(items[0]->GetPath(), "icon.png"); // install the addon return DoInstall(addon, RepositoryPtr()); } CEventLog::GetInstance().AddWithNotification( EventPtr(new CNotificationEvent(EventLevelError, 24045, StringUtils::Format(g_localizeStrings.Get(24143).c_str(), path.c_str()))), false); return false; }
int CAddonDatabase::AddAddon(const AddonPtr& addon, int idRepo) { try { if (NULL == m_pDB.get()) return -1; if (NULL == m_pDS.get()) return -1; CStdString sql = PrepareSQL("insert into addon (id, type, name, summary," "description, stars, path, icon, changelog, " "fanart, addonID, version, author, disclaimer)" " values(NULL, '%s', '%s', '%s', '%s', %i," "'%s', '%s', '%s', '%s', '%s','%s','%s','%s')", TranslateType(addon->Type(),false).c_str(), addon->Name().c_str(), addon->Summary().c_str(), addon->Description().c_str(),addon->Stars(), addon->Path().c_str(), addon->Props().icon.c_str(), addon->ChangeLog().c_str(),addon->FanArt().c_str(), addon->ID().c_str(), addon->Version().str.c_str(), addon->Author().c_str(),addon->Disclaimer().c_str()); m_pDS->exec(sql.c_str()); int idAddon = (int)m_pDS->lastinsertid(); sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon); m_pDS->exec(sql.c_str()); const InfoMap &info = addon->ExtraInfo(); for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i) { sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str()); m_pDS->exec(sql.c_str()); } return idAddon; } catch (...) { CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str()); } return -1; }
bool CAddonInstallJob::DoWork() { SetTitle(StringUtils::Format(g_localizeStrings.Get(24057).c_str(), m_addon->Name().c_str())); SetProgress(0); // check whether all the dependencies are available or not SetText(g_localizeStrings.Get(24058)); std::pair<std::string, std::string> failedDep; if (!CAddonInstaller::GetInstance().CheckDependencies(m_addon, failedDep)) { std::string details = StringUtils::Format(g_localizeStrings.Get(24142).c_str(), failedDep.first.c_str(), failedDep.second.c_str()); CLog::Log(LOGERROR, "CAddonInstallJob[%s]: %s", m_addon->ID().c_str(), details.c_str()); ReportInstallError(m_addon->ID(), m_addon->ID(), details); return false; } AddonPtr repoPtr = GetRepoForAddon(m_addon); std::string installFrom; if (!repoPtr || repoPtr->Props().libname.empty()) { // Addons are installed by downloading the .zip package on the server to the local // packages folder, then extracting from the local .zip package into the addons folder // Both these functions are achieved by "copying" using the vfs. std::string dest = "special://home/addons/packages/"; std::string package = URIUtils::AddFileToFolder("special://home/addons/packages/", URIUtils::GetFileName(m_addon->Path())); if (URIUtils::HasSlashAtEnd(m_addon->Path())) { // passed in a folder - all we need do is copy it across installFrom = m_addon->Path(); } else { CAddonDatabase db; if (!db.Open()) { CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to open database", m_addon->ID().c_str()); ReportInstallError(m_addon->ID(), m_addon->ID()); return false; } std::string md5; // check that we don't already have a valid copy if (!m_hash.empty() && CFile::Exists(package)) { if (db.GetPackageHash(m_addon->ID(), package, md5) && m_hash != md5) { db.RemovePackage(package); CFile::Delete(package); } } // zip passed in - download + extract if (!CFile::Exists(package)) { std::string path(m_addon->Path()); if (!m_referer.empty() && URIUtils::IsInternetStream(path)) { CURL url(path); url.SetProtocolOptions(m_referer); path = url.Get(); } if (!DownloadPackage(path, dest)) { CFile::Delete(package); CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to download %s", m_addon->ID().c_str(), package.c_str()); ReportInstallError(m_addon->ID(), URIUtils::GetFileName(package)); return false; } } // at this point we have the package - check that it is valid SetText(g_localizeStrings.Get(24077)); if (!m_hash.empty()) { md5 = CUtil::GetFileMD5(package); if (!StringUtils::EqualsNoCase(md5, m_hash)) { CFile::Delete(package); CLog::Log(LOGERROR, "CAddonInstallJob[%s]: MD5 mismatch after download %s", m_addon->ID().c_str(), package.c_str()); ReportInstallError(m_addon->ID(), URIUtils::GetFileName(package)); return false; } db.AddPackage(m_addon->ID(), package, md5); } // check the archive as well - should have just a single folder in the root CURL archive = URIUtils::CreateArchivePath("zip", CURL(package), ""); CFileItemList archivedFiles; CDirectory::GetDirectory(archive, archivedFiles); if (archivedFiles.Size() != 1 || !archivedFiles[0]->m_bIsFolder) { // invalid package db.RemovePackage(package); CFile::Delete(package); CLog::Log(LOGERROR, "CAddonInstallJob[%s]: invalid package %s", m_addon->ID().c_str(), package.c_str()); ReportInstallError(m_addon->ID(), URIUtils::GetFileName(package)); return false; } installFrom = archivedFiles[0]->GetPath(); } repoPtr.reset(); } // run any pre-install functions ADDON::OnPreInstall(m_addon); // perform install if (!Install(installFrom, repoPtr)) return false; // run any post-install guff CEventLog::GetInstance().Add( EventPtr(new CAddonManagementEvent(m_addon, m_update ? 24065 : 24064)), !IsModal() && CSettings::GetInstance().GetBool(CSettings::SETTING_GENERAL_ADDONNOTIFICATIONS), false); ADDON::OnPostInstall(m_addon, m_update, IsModal()); //Clear addon from the disabled table CAddonDatabase database; database.Open(); database.DisableAddon(m_addon->ID(), false); // and we're done! MarkFinished(); return true; }
bool CAddonInstallJob::DoWork() { AddonPtr repoPtr = GetRepoForAddon(m_addon); CStdString installFrom; if (!repoPtr || repoPtr->Props().libname.empty()) { // Addons are installed by downloading the .zip package on the server to the local // packages folder, then extracting from the local .zip package into the addons folder // Both these functions are achieved by "copying" using the vfs. CStdString dest="special://home/addons/packages/"; CStdString package = URIUtils::AddFileToFolder("special://home/addons/packages/", URIUtils::GetFileName(m_addon->Path())); if (URIUtils::HasSlashAtEnd(m_addon->Path())) { // passed in a folder - all we need do is copy it across installFrom = m_addon->Path(); } else { // zip passed in - download + extract CStdString path(m_addon->Path()); if (!m_referer.empty() && URIUtils::IsInternetStream(path)) { CURL url(path); url.SetProtocolOptions(m_referer); path = url.Get(); } if (!CFile::Exists(package) && !DownloadPackage(path, dest)) { CFile::Delete(package); return false; } // at this point we have the package - check that it is valid if (!CFile::Exists(package) || !CheckHash(package)) { CFile::Delete(package); return false; } // check the archive as well - should have just a single folder in the root CStdString archive; URIUtils::CreateArchivePath(archive,"zip",package,""); CFileItemList archivedFiles; CDirectory::GetDirectory(archive, archivedFiles); if (archivedFiles.Size() != 1 || !archivedFiles[0]->m_bIsFolder) { // invalid package CFile::Delete(package); return false; } installFrom = archivedFiles[0]->GetPath(); } repoPtr.reset(); } // run any pre-install functions bool reloadAddon = OnPreInstall(); // perform install if (!Install(installFrom, repoPtr)) return false; // something went wrong // run any post-install guff OnPostInstall(reloadAddon); // and we're done! return true; }
bool CAddonInstallJob::DoWork() { AddonPtr repoPtr = GetRepoForAddon(m_addon); std::string installFrom; if (!repoPtr || repoPtr->Props().libname.empty()) { // Addons are installed by downloading the .zip package on the server to the local // packages folder, then extracting from the local .zip package into the addons folder // Both these functions are achieved by "copying" using the vfs. std::string dest="special://home/addons/packages/"; std::string package = URIUtils::AddFileToFolder("special://home/addons/packages/", URIUtils::GetFileName(m_addon->Path())); if (URIUtils::HasSlashAtEnd(m_addon->Path())) { // passed in a folder - all we need do is copy it across installFrom = m_addon->Path(); } else { std::string md5; CAddonDatabase db; db.Open(); // check that we don't already have a valid copy if (!m_hash.empty() && CFile::Exists(package)) { if (db.GetPackageHash(m_addon->ID(), package, md5) && m_hash != md5) { db.RemovePackage(package); CFile::Delete(package); } } // zip passed in - download + extract if (!CFile::Exists(package)) { std::string path(m_addon->Path()); if (!m_referer.empty() && URIUtils::IsInternetStream(path)) { CURL url(path); url.SetProtocolOptions(m_referer); path = url.Get(); } if (!DownloadPackage(path, dest)) { CFile::Delete(package); return false; } } // at this point we have the package - check that it is valid if (!m_hash.empty()) { md5 = CUtil::GetFileMD5(package); if (!StringUtils::EqualsNoCase(md5, m_hash)) { CFile::Delete(package); ReportInstallError(m_addon->ID(), URIUtils::GetFileName(package)); CLog::Log(LOGERROR, "MD5 mismatch after download %s", package.c_str()); return false; } db.AddPackage(m_addon->ID(), package, md5); } // check the archive as well - should have just a single folder in the root CURL archive = URIUtils::CreateArchivePath("zip",CURL(package),""); CFileItemList archivedFiles; CDirectory::GetDirectory(archive, archivedFiles); if (archivedFiles.Size() != 1 || !archivedFiles[0]->m_bIsFolder) { // invalid package db.RemovePackage(package); CFile::Delete(package); return false; } installFrom = archivedFiles[0]->GetPath(); } repoPtr.reset(); } // run any pre-install functions bool reloadAddon = OnPreInstall(); // perform install if (!Install(installFrom, repoPtr)) return false; // something went wrong // run any post-install guff OnPostInstall(reloadAddon); // and we're done! return true; }