Пример #1
0
CRepository::ResolveResult CRepository::ResolvePathAndHash(const AddonPtr& addon) const
{
  std::string const& path = addon->Path();

  auto dirIt = std::find_if(m_dirs.begin(), m_dirs.end(), [&path](DirInfo const& dir)
  {
    return URIUtils::PathHasParent(path, dir.datadir, true);
  });
  if (dirIt == m_dirs.end())
  {
    CLog::Log(LOGERROR, "Requested path {} not found in known repository directories", path);
    return {};
  }

  if (dirIt->hashType == CDigest::Type::INVALID)
  {
    // We have a path, but need no hash
    return {path, {}};
  }

  // Do not follow mirror redirect, we want the headers of the redirect response
  CURL url{path};
  url.SetProtocolOption("redirect-limit", "0");
  CCurlFile file;
  if (!file.Open(url))
  {
    CLog::Log(LOGERROR, "Could not fetch addon location and hash from {}", path);
    return {};
  }

  std::string hashTypeStr = CDigest::TypeToString(dirIt->hashType);

  // Return the location from the header so we don't have to look it up again
  // (saves one request per addon install)
  std::string location = file.GetRedirectURL();
  // content-* headers are base64, convert to base16
  TypedDigest hash{dirIt->hashType, StringUtils::ToHexadecimal(Base64::Decode(file.GetHttpHeader().GetValue(std::string("content-") + hashTypeStr)))};

  if (hash.Empty())
  {
    // Expected hash, but none found -> fall back to old method
    if (!FetchChecksum(path + "." + hashTypeStr, hash.value) || hash.Empty())
    {
      CLog::Log(LOGERROR, "Failed to find hash for {} from HTTP header and in separate file", path);
      return {};
    }
  }
  if (location.empty())
  {
    // Fall back to original URL if we do not get a redirect
    location = path;
  }

  CLog::Log(LOGDEBUG, "Resolved addon path {} to {} hash {}", path, location, hash.value);

  return {location, hash};
}
Пример #2
0
bool CDAVDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
{
  CCurlFile dav;
  CURL url(strPath);
  CStdString strRequest = "PROPFIND";

  dav.SetCustomRequest(strRequest);
  dav.SetMimeType("text/xml; charset=\"utf-8\"");
  dav.SetRequestHeader("depth", 1);
  dav.SetPostData(
    "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
    " <D:propfind xmlns:D=\"DAV:\">"
    "   <D:prop>"
    "     <D:resourcetype/>"
    "     <D:getcontentlength/>"
    "     <D:getlastmodified/>"
    "     <D:creationdate/>"
    "     <D:displayname/>"
    "    </D:prop>"
    "  </D:propfind>");

  if (!dav.Open(url))
  {
    CLog::Log(LOGERROR, "%s - Unable to get dav directory (%s)", __FUNCTION__, strPath.c_str());
    return false;
  }

  CStdString strResponse;
  dav.ReadData(strResponse);

  CXBMCTinyXML davResponse;
  davResponse.Parse(strResponse.c_str());

  if (!davResponse.Parse(strResponse))
  {
    CLog::Log(LOGERROR, "%s - Unable to process dav directory (%s)", __FUNCTION__, strPath.c_str());
    dav.Close();
    return false;
  }

  TiXmlNode *pChild;
  // Iterate over all responses
  for (pChild = davResponse.RootElement()->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
  {
    if (CDAVCommon::ValueWithoutNamespace(pChild, "response"))
    {
      CFileItem item;
      ParseResponse(pChild->ToElement(), item);
      CURL url2(strPath);
      CURL url3(item.GetPath());

      CStdString itemPath(URIUtils::AddFileToFolder(url2.GetWithoutFilename(), url3.GetFileName()));

      if (item.GetLabel().IsEmpty())
      {
        CStdString name(itemPath);
        URIUtils::RemoveSlashAtEnd(name);
        CURL::Decode(name);
        item.SetLabel(URIUtils::GetFileName(name));
      }

      if (item.m_bIsFolder)
        URIUtils::AddSlashAtEnd(itemPath);

      // Add back protocol options
      if (!url2.GetProtocolOptions().IsEmpty())
        itemPath += "|" + url2.GetProtocolOptions();
      item.SetPath(itemPath);

      if (!item.GetPath().Equals(strPath))
      {
        CFileItemPtr pItem(new CFileItem(item));
        items.Add(pItem);
      }
    }
  }

  dav.Close();

  return true;
}
Пример #3
0
bool CFTPDirectory::GetDirectory(const CURL& url2, CFileItemList &items)
{
  CCurlFile reader;

  CURL url(url2);

  std::string path = url.GetFileName();
  if( !path.empty() && !StringUtils::EndsWith(path, "/") )
  {
    path += "/";
    url.SetFileName(path);
  }

  if (!reader.Open(url))
    return false;

  bool serverNotUseUTF8 = url.GetProtocolOption("utf8") == "0";

  char buffer[MAX_PATH + 1024];
  while( reader.ReadString(buffer, sizeof(buffer)) )
  {
    std::string strBuffer = buffer;

    StringUtils::RemoveCRLF(strBuffer);

    CFTPParse parse;
    if (parse.FTPParse(strBuffer))
    {
      if( parse.getName().length() == 0 )
        continue;

      if( parse.getFlagtrycwd() == 0 && parse.getFlagtryretr() == 0 )
        continue;

      /* buffer name */
      std::string name;
      name.assign(parse.getName());

      if( name == ".." || name == "." )
        continue;

      // server returned filename could in utf8 or non-utf8 encoding
      // we need utf8, so convert it to utf8 anyway
      g_charsetConverter.unknownToUTF8(name);

      // convert got empty result, ignore it
      if (name.empty())
        continue;

      if (serverNotUseUTF8 || name != parse.getName())
        // non-utf8 name path, tag it with protocol option.
        // then we can talk to server with the same encoding in CurlFile according to this tag.
        url.SetProtocolOption("utf8", "0");
      else
        url.RemoveProtocolOption("utf8");

      CFileItemPtr pItem(new CFileItem(name));

      pItem->m_bIsFolder = parse.getFlagtrycwd() != 0;
      std::string filePath = path + name;
      if (pItem->m_bIsFolder)
        URIUtils::AddSlashAtEnd(filePath);

      /* qualify the url with host and all */
      url.SetFileName(filePath);
      pItem->SetPath(url.Get());

      pItem->m_dwSize = parse.getSize();
      pItem->m_dateTime=parse.getTime();

      items.Add(pItem);
    }
  }

  return true;
}
Пример #4
0
bool CTuxBoxDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
{
  // so we know that we have enigma2
  static bool enigma2 = false;
  // Detect and delete slash at end
  CStdString strRoot = strPath;
  URIUtils::RemoveSlashAtEnd(strRoot);

  //Get the request strings
  CStdString strBQRequest;
  CStdString strXMLRootString;
  CStdString strXMLChildString;
  if(!GetRootAndChildString(strRoot, strBQRequest, strXMLRootString, strXMLChildString))
    return false;

  //Set url Protocol
  CURL url(strRoot);
  CStdString strFilter;
  CStdString protocol = url.GetProtocol();
  url.SetProtocol("http");
  bool bIsBouquet=false;

  if (url.HasOption("path"))
  {
    // send Zap!
    return g_tuxbox.ZapToUrl(url, url.GetOption("path"));
  }
  else
  {
    if (url.HasOption("reference") || enigma2)
    {
      //List reference
      strFilter = url.GetOption("reference");
      bIsBouquet = false; //On Empty is Bouquet
      if (enigma2)
      {
        CStdString strPort;
        strPort.Format(":%i",url.GetPort());
        if (strRoot.Right(strPort.GetLength()) != strPort) // If not root dir, enable Channels
          strFilter = "e2"; // Disable Bouquets for Enigma2

        GetRootAndChildStringEnigma2(strBQRequest, strXMLRootString, strXMLChildString);
      }
      url.SetOptions("");
      url.SetFileName(strBQRequest);
    }
  }
  if(strFilter.IsEmpty())
  {
    url.SetOptions("");
    url.SetFileName(strBQRequest);
    bIsBouquet = true;
  }
  //Open
  CCurlFile http;
  int iTryConnect = 0;
  int iWaitTimer = 20;
  bool result = false;

  while (iTryConnect < 4)
  {
    http.SetTimeout(iWaitTimer);
    if(http.Open(url))
    {
      //We are connected!
      iTryConnect = 4;

      // restore protocol
      url.SetProtocol(protocol);

      int size_read = 0;
      int size_total = (int)http.GetLength();
      int data_size = 0;
      CStdString data;
      data.reserve(size_total);

      // read response from server into string buffer
      char buffer[16384];
      while ((size_read = http.Read(buffer, sizeof(buffer)-1)) > 0)
      {
        buffer[size_read] = 0;
        data += buffer;
        data_size += size_read;
      }
      http.Close();

      // parse returned xml
      CXBMCTinyXML doc;
      data.Replace("></",">-</"); //FILL EMPTY ELEMENTS WITH "-"!
      doc.Parse(data.c_str());
      TiXmlElement *root = doc.RootElement();
      if(root == NULL)
      {
        CLog::Log(LOGERROR, "%s - Unable to parse xml", __FUNCTION__);
        CLog::Log(LOGERROR, "%s - Sample follows...\n%s", __FUNCTION__, data.c_str());
        return false;
      }
      if( strXMLRootString.Equals(root->Value()) && bIsBouquet)
      {
        data.Empty();
        if (enigma2)
          result = g_tuxbox.ParseBouquetsEnigma2(root, items, url, strFilter, strXMLChildString);
        else
          result = g_tuxbox.ParseBouquets(root, items, url, strFilter, strXMLChildString);
      }
      else if( strXMLRootString.Equals(root->Value()) && !strFilter.IsEmpty() )
      {
        data.Empty();
        if (enigma2)
          result = g_tuxbox.ParseChannelsEnigma2(root, items, url, strFilter, strXMLChildString);
        else
          result = g_tuxbox.ParseChannels(root, items, url, strFilter, strXMLChildString);
      }
      else
      {
        CLog::Log(LOGERROR, "%s - Invalid root xml element for TuxBox", __FUNCTION__);
        CLog::Log(LOGERROR, "%s - Sample follows...\n%s", __FUNCTION__, data.c_str());
        data.Empty();
        result = false;
      }
    }
    else
    {
      CLog::Log(LOGERROR, "%s - Unable to get XML structure! Try count:%i, Wait Timer:%is",__FUNCTION__, iTryConnect, iWaitTimer);
      iTryConnect++;
      if (iTryConnect == 2) //try enigma2 instead of enigma1, best entrypoint here i thought
      {	
        enigma2 = true;
        GetRootAndChildStringEnigma2(strBQRequest, strXMLRootString, strXMLChildString);
        url.SetOptions("");
        url.SetFileName(strBQRequest);
//        iTryConnect = 0;
        iWaitTimer = 20;
      }
      else
        iWaitTimer = iWaitTimer+10;

      result = false;
      http.Close(); // Close old connections
    }
  }
  items.SetContent("movies");
  return result;
}
Пример #5
0
CURL CDVDInputStreamFFmpeg::GetM3UBestBandwidthStream(const CURL &url, size_t bandwidth)
{
  typedef CPlayListM3U M3U;
  using std::string;
  using std::map;

  // we may be passed a playlist that does not contain playlists of different
  // bitrates (eg: this playlist is really the HLS video). So, default the
  // return to the filename so it can be played
  char szLine[4096];
  string strLine;
  size_t maxBandwidth = 0;

  CCurlFile file;

  // set the proxy configuration
  const string host = GetProxyHost();
  if (!host.empty())
    file.SetProxy(GetProxyType(), host, GetProxyPort(),
                  GetProxyUser(), GetProxyPassword());

  // open the file, and if it fails, return
  if (!file.Open(url))
  {
    file.Close();
    return url;
  }

  // and set the fallback value
  CURL subStreamUrl(url);

  // determine the base
  CURL basePlaylistUrl(URIUtils::GetParentPath(url.Get()));
  basePlaylistUrl.SetOptions("");
  basePlaylistUrl.SetProtocolOptions("");
  const string basePart = basePlaylistUrl.Get();

  // convert bandwidth specified in kbps to bps used by the m3u8
  bandwidth *= 1000;

  while (file.ReadString(szLine, 1024))
  {
    // read and trim a line
    strLine = szLine;
    StringUtils::Trim(strLine);

    // skip the first line
    if (strLine == M3U::StartMarker)
        continue;
    else if (StringUtils::StartsWith(strLine, M3U::StreamMarker))
    {
      // parse the line so we can pull out the bandwidth
      const map< string, string > params = M3U::ParseStreamLine(strLine);
      const map< string, string >::const_iterator it = params.find(M3U::BandwidthMarker);

      if (it != params.end())
      {
        const size_t streamBandwidth = atoi(it->second.c_str());
        if ((maxBandwidth < streamBandwidth) && (streamBandwidth <= bandwidth))
        {
          // read the next line
          if (!file.ReadString(szLine, 1024))
            continue;

          strLine = szLine;
          StringUtils::Trim(strLine);

          // this line was empty
          if (strLine.empty())
            continue;

          // store the max bandwidth
          maxBandwidth = streamBandwidth;

          // if the path is absolute just use it
          if (CURL::IsFullPath(strLine))
            subStreamUrl = CURL(strLine);
          else
            subStreamUrl = CURL(basePart + strLine);
        }
      }
    }
  }

  // if any protocol options were set, restore them
  subStreamUrl.SetProtocolOptions(url.GetProtocolOptions());
  return subStreamUrl;
}
Пример #6
0
bool CFTPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
{
  CCurlFile reader;

  CURL url(strPath);

  CStdString path = url.GetFileName();
  if( !path.IsEmpty() && !path.Right(1).Equals("/") )
  {
    path += "/";
    url.SetFileName(path);
  }

  if (!reader.Open(url))
    return false;


  char buffer[MAX_PATH + 1024];
  while( reader.ReadString(buffer, sizeof(buffer)) )
  {
    CStdString strBuffer = buffer;

    StringUtils::RemoveCRLF(strBuffer);

    CFTPParse parse;
    if (parse.FTPParse(strBuffer))
    {
      if( parse.getName().length() == 0 )
        continue;

      if( parse.getFlagtrycwd() == 0 && parse.getFlagtryretr() == 0 )
        continue;

      /* buffer name */
      CStdString name;
      name.assign(parse.getName());

      if( name.Equals("..") || name.Equals(".") )
        continue;

      /* this should be conditional if we ever add    */
      /* support for the utf8 extension in ftp client */
      g_charsetConverter.unknownToUTF8(name);

      CFileItemPtr pItem(new CFileItem(name));

      pItem->m_bIsFolder = (bool)(parse.getFlagtrycwd() != 0);
      CStdString filePath = path + name;
      if (pItem->m_bIsFolder)
        URIUtils::AddSlashAtEnd(filePath);

      /* qualify the url with host and all */
      url.SetFileName(filePath);
      pItem->SetPath(url.Get());

      pItem->m_dwSize = parse.getSize();
      pItem->m_dateTime=parse.getTime();

      items.Add(pItem);
    }
  }

  return true;
}
Пример #7
0
bool CHTTPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
{
    CCurlFile http;
    CURL url(strPath);

    CStdString strName, strLink;
    CStdString strBasePath = url.GetFileName();

    if(!http.Open(url))
    {
        CLog::Log(LOGERROR, "%s - Unable to get http directory", __FUNCTION__);
        return false;
    }

    CRegExp reItem(true); // HTML is case-insensitive
    reItem.RegComp("<a href=\"(.*)\">(.*)</a>");

    CRegExp reDateTime(true);
    reDateTime.RegComp("<td align=\"right\">([0-9]{2})-([A-Z]{3})-([0-9]{4}) ([0-9]{2}):([0-9]{2}) +</td>");

    CRegExp reDateTimeNginx(true);
    reDateTimeNginx.RegComp("</a> +([0-9]{2})-([A-Z]{3})-([0-9]{4}) ([0-9]{2}):([0-9]{2}) ");

    CRegExp reSize(true);
    reSize.RegComp(">*([0-9.]+)(B|K|M|G| )</td>");

    CRegExp reSizeNginx;
    reSizeNginx.RegComp("([0-9]+)$");

    /* read response from server into string buffer */
    char buffer[MAX_PATH + 1024];
    while(http.ReadString(buffer, sizeof(buffer)-1))
    {
        CStdString strBuffer = buffer;
        StringUtils::RemoveCRLF(strBuffer);

        if (reItem.RegFind(strBuffer.c_str()) >= 0)
        {
            strLink = reItem.GetReplaceString("\\1");
            strName = reItem.GetReplaceString("\\2");

            if(strLink[0] == '/')
                strLink = strLink.Mid(1);

            CStdString strNameTemp = strName.Trim();
            CStdString strLinkTemp = strLink;
            URIUtils::RemoveSlashAtEnd(strLinkTemp);
            URIUtils::RemoveSlashAtEnd(strNameTemp);
            CURL::Decode(strLinkTemp);

            if (strNameTemp == strLinkTemp && strLinkTemp != "..")
            {
                CStdStringW wName, wLink, wConverted;

                g_charsetConverter.unknownToUTF8(strName);
                g_charsetConverter.utf8ToW(strName, wName, false);
                HTML::CHTMLUtil::ConvertHTMLToW(wName, wConverted);
                g_charsetConverter.wToUTF8(wConverted, strName);
                URIUtils::RemoveSlashAtEnd(strName);

                g_charsetConverter.unknownToUTF8(strLink);
                g_charsetConverter.utf8ToW(strLink, wLink, false);
                HTML::CHTMLUtil::ConvertHTMLToW(wLink, wConverted);
                g_charsetConverter.wToUTF8(wConverted, strLink);

                CFileItemPtr pItem(new CFileItem(strName));
                pItem->SetProperty("IsHTTPDirectory", true);
                url.SetFileName(strBasePath + strLink);
                pItem->SetPath(url.Get());

                if(URIUtils::HasSlashAtEnd(pItem->GetPath()))
                    pItem->m_bIsFolder = true;

                CStdString day, month, year, hour, minute;

                if (reDateTime.RegFind(strBuffer.c_str()) >= 0)
                {
                    day = reDateTime.GetReplaceString("\\1");
                    month = reDateTime.GetReplaceString("\\2");
                    year = reDateTime.GetReplaceString("\\3");
                    hour = reDateTime.GetReplaceString("\\4");
                    minute = reDateTime.GetReplaceString("\\5");
                }
                else if (reDateTimeNginx.RegFind(strBuffer.c_str()) >= 0)
                {
                    day = reDateTimeNginx.GetReplaceString("\\1");
                    month = reDateTimeNginx.GetReplaceString("\\2");
                    year = reDateTimeNginx.GetReplaceString("\\3");
                    hour = reDateTimeNginx.GetReplaceString("\\4");
                    minute = reDateTimeNginx.GetReplaceString("\\5");
                }

                if (day.length() > 0 && month.length() > 0 && year.length() > 0)
                {
                    pItem->m_dateTime = CDateTime(atoi(year.c_str()), CDateTime::MonthStringToMonthNum(month), atoi(day.c_str()), atoi(hour.c_str()), atoi(minute.c_str()), 0);
                }

                if (!pItem->m_bIsFolder)
                {
                    if (reSize.RegFind(strBuffer.c_str()) >= 0)
                    {
                        double Size = atof(reSize.GetReplaceString("\\1"));
                        CStdString strUnit = reSize.GetReplaceString("\\2");

                        if (strUnit == "K")
                            Size = Size * 1024;
                        else if (strUnit == "M")
                            Size = Size * 1024 * 1024;
                        else if (strUnit == "G")
                            Size = Size * 1000 * 1024 * 1024;

                        pItem->m_dwSize = (int64_t)Size;
                    }
                    else if (reSizeNginx.RegFind(strBuffer.c_str()) >= 0)
                    {
                        double Size = atof(reSizeNginx.GetReplaceString("\\1"));
                        pItem->m_dwSize = (int64_t)Size;
                    }
                    else if (g_advancedSettings.m_bHTTPDirectoryStatFilesize) // As a fallback get the size by stat-ing the file (slow)
                    {
                        CCurlFile file;
                        file.Open(url);
                        pItem->m_dwSize=file.GetLength();
                        file.Close();
                    }
                }
                items.Add(pItem);
            }
        }
    }
    http.Close();

    items.SetProperty("IsHTTPDirectory", true);

    return true;
}
Пример #8
0
	CStdString *ThumbStore::getFanart(const char *artistName) {

		if (!Settings::getInstance()->getUseHTFanarts())
			return m_stdFanart;

		//Logger::printOut("Looking for fanart");

		//check if we got the fanart
		string artistNameString = artistName;
		stringMap::iterator it = m_fanarts.find(artistNameString);
		if (it == m_fanarts.end()) {
			//we dont have it so we need to to a search for it

			CCurlFile http;
			CStdString artistString = artistName;
			artistString.Replace(' ', '+');
			CStdString urlString;
			urlString.Format(
					"http://htbackdrops.org/api/afb0f6cdbd412a7888005de34f86e4a5/searchXML?keywords=%s&default_operator=and&aid=1&fields=title,keywords,caption,mb_name,mb_alias&inc=keywords,caption,mb_name,mb_aliases&limit=1",
					artistString);

			CURL url(urlString);

			if (http.Open(url)) {
				Logger::printOut("Looking for fanart, need to fetch a new address");
				Logger::printOut(artistNameString);
				//try to parse the resulting file for a fanart image
				CStdString data;
				http.ReadData(data);

				TiXmlDocument xmlDoc;
				xmlDoc.Parse(data);
				TiXmlNode* element = xmlDoc.RootElement();
				//get the images child
				element = element->FirstChild("images");
				if (element) {

					//get the first image child, (should only be one)
					element = element->FirstChild();
					if (element) {
						//get the id
						TiXmlNode* idElement = element->FirstChild("id");
						CStdString id = idElement->ToElement()->GetText();
						//get the filename
						TiXmlNode* fileNameElement = element->FirstChild("filename");
						CStdString name = fileNameElement->ToElement()->GetText();

						CStdString *fanartUrl = new CStdString();
						fanartUrl->Format(
								"http://htbackdrops.org/api/afb0f6cdbd412a7888005de34f86e4a5/download/%s/fullsize/%s",
								id, name);
						//Logger::printOut("Adding online fanart");

						m_fanarts.insert(
								stringMap::value_type(artistNameString, fanartUrl));

						//save the fanart url to the cachefile
						string path = Settings::getInstance()->getCachePath() + "fanarts.txt";
						Logger::printOut("saving fanart list");
						ofstream file(path.c_str(), ios::app);
						if (file.is_open()) {
							file << artistNameString << "\n" << *fanartUrl << "\n";
						}

						file.close();

						return fanartUrl;
					}
				}
			}
			//Logger::printOut("Adding standard fanart");
			m_fanarts.insert(stringMap::value_type(artistNameString, m_stdFanart));

			//save the fanart url to the cachefile
			string path = Settings::getInstance()->getCachePath() + "fanarts.txt";
			Logger::printOut("saving fanart list");
			ofstream file(path.c_str(), ios::app);
			if (file.is_open()) {
				file << artistNameString << "\n" << *m_stdFanart << "\n";
			}

			file.close();

			return m_stdFanart;
		}
		//Logger::printOut("Returning cached fanart");
		return it->second;
	}