Пример #1
0
bool CAddonDatabase::GetAddon(const std::string& id, AddonPtr& addon)
{
    try
    {
        if (NULL == m_pDB.get()) return false;
        if (NULL == m_pDS2.get()) return false;

        // there may be multiple addons with this id (eg from different repositories) in the database,
        // so we want to retrieve the latest version.  Order by version won't work as the database
        // won't know that 1.10 > 1.2, so grab them all and order outside
        std::string sql = PrepareSQL("select id,version from addon where addonID='%s'",id.c_str());
        m_pDS2->query(sql.c_str());

        if (m_pDS2->eof())
            return false;

        AddonVersion maxversion("0.0.0");
        int maxid = 0;
        while (!m_pDS2->eof())
        {
            AddonVersion version(m_pDS2->fv(1).get_asString());
            if (version > maxversion)
            {
                maxid = m_pDS2->fv(0).get_asInt();
                maxversion = version;
            }
            m_pDS2->next();
        }
        return GetAddon(maxid,addon);
    }
    catch (...)
    {
        CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
    }
    addon.reset();
    return false;
}
Пример #2
0
bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
{
  try
  {
    if (NULL == m_pDB.get()) return false;
    if (NULL == m_pDS2.get()) return false;

    std::string sql = "SELECT addon.*,"
                      "       broken.reason,"
                      "       addonextra.key, addonextra.value,"
                      "       dependencies.addon, dependencies.version, dependencies.optional"
                      "  FROM addon"
                      "    LEFT JOIN broken"
                      "      ON broken.addonID = addon.addonID"
                      "    LEFT JOIN addonextra"
                      "      ON addonextra.id = addon.id"
                      "    LEFT JOIN dependencies"
                      "      ON dependencies.id = addon.id";

    sql += PrepareSQL(" WHERE addon.id=%i", id);

    m_pDS2->query(sql.c_str());
    if (!m_pDS2->eof())
    {
      const dbiplus::query_data &data = m_pDS2->get_result_set().records;
      const dbiplus::sql_record* const record = data[0];
      AddonProps props(record->at(addon_addonID).get_asString(),
                       TranslateType(record->at(addon_type).get_asString()),
                       record->at(addon_version).get_asString(),
                       record->at(addon_minversion).get_asString());
      props.name = record->at(addon_name).get_asString();
      props.summary = record->at(addon_summary).get_asString();
      props.description = record->at(addon_description).get_asString();
      props.changelog = record->at(addon_changelog).get_asString();
      props.path = record->at(addon_path).get_asString();
      props.icon = record->at(addon_icon).get_asString();
      props.fanart = record->at(addon_fanart).get_asString();
      props.author = record->at(addon_author).get_asString();
      props.disclaimer = record->at(addon_disclaimer).get_asString();
      props.broken = record->at(broken_reason).get_asString();

      /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
         extrainfo and dependencies are maps, so insert() will insert the first instance only */
      for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
      {
        const dbiplus::sql_record* const record = *i;
        if (!record->at(addonextra_key).get_asString().empty())
          props.extrainfo.insert(make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
        if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
          props.dependencies.insert(make_pair(record->at(dependencies_addon).get_asString(), make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool())));
      }

      addon = CAddonMgr::AddonFromProps(props);
      return NULL != addon.get();
    }
  }
  catch (...)
  {
    CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
  }
  addon.reset();
  return false;
}
Пример #3
0
bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
{
  try
  {
    if (NULL == m_pDB.get()) return false;
    if (NULL == m_pDS2.get()) return false;

    std::string sql = "SELECT addon.*,"
                      "       broken.reason,"
                      "       addonextra.key, addonextra.value,"
                      "       dependencies.addon, dependencies.version, dependencies.optional"
                      "  FROM addon"
                      "    LEFT JOIN broken"
                      "      ON broken.addonID = addon.addonID"
                      "    LEFT JOIN addonextra"
                      "      ON addonextra.id = addon.id"
                      "    LEFT JOIN dependencies"
                      "      ON dependencies.id = addon.id";

    sql += PrepareSQL(" WHERE addon.id=%i", id);

    m_pDS2->query(sql);
    if (!m_pDS2->eof())
    {
      const dbiplus::query_data &data = m_pDS2->get_result_set().records;
      const dbiplus::sql_record* const record = data[0];

      CAddonBuilder builder;
      builder.SetId(record->at(addon_addonID).get_asString());
      builder.SetType(TranslateType(record->at(addon_type).get_asString()));
      builder.SetVersion(AddonVersion(record->at(addon_version).get_asString()));
      builder.SetMinVersion(AddonVersion(record->at(addon_minversion).get_asString()));
      builder.SetName(record->at(addon_name).get_asString());
      builder.SetSummary(record->at(addon_summary).get_asString());
      builder.SetDescription(record->at(addon_description).get_asString());
      builder.SetChangelog(record->at(addon_changelog).get_asString());
      builder.SetDisclaimer(record->at(addon_disclaimer).get_asString());
      builder.SetAuthor(record->at(addon_author).get_asString());
      builder.SetBroken(record->at(broken_reason).get_asString());
      builder.SetPath(record->at(addon_path).get_asString());
      builder.SetIcon(record->at(addon_icon).get_asString());
      builder.SetFanart(record->at(addon_fanart).get_asString());

      InfoMap extrainfo;
      ADDONDEPS dependencies;
      /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
         extrainfo and dependencies are maps, so insert() will insert the first instance only */
      for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
      {
        const dbiplus::sql_record* const record = *i;
        if (!record->at(addonextra_key).get_asString().empty())
          extrainfo.insert(std::make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
        if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
          dependencies.insert(std::make_pair(record->at(dependencies_addon).get_asString(), std::make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool())));
      }
      builder.SetExtrainfo(std::move(extrainfo));
      builder.SetDependencies(std::move(dependencies));

      addon = builder.Build();
      return NULL != addon.get();
    }
  }
  catch (...)
  {
    CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
  }
  addon.reset();
  return false;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}