diff options
Diffstat (limited to 'xbmc/filesystem/DAVDirectory.cpp')
-rw-r--r-- | xbmc/filesystem/DAVDirectory.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/xbmc/filesystem/DAVDirectory.cpp b/xbmc/filesystem/DAVDirectory.cpp new file mode 100644 index 0000000..48d4865 --- /dev/null +++ b/xbmc/filesystem/DAVDirectory.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "DAVDirectory.h" + +#include "CurlFile.h" +#include "DAVCommon.h" +#include "DAVFile.h" +#include "FileItem.h" +#include "URL.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +using namespace XFILE; + +CDAVDirectory::CDAVDirectory(void) = default; +CDAVDirectory::~CDAVDirectory(void) = default; + +/* + * Parses a <response> + * + * <!ELEMENT response (href, ((href*, status)|(propstat+)), responsedescription?) > + * <!ELEMENT propstat (prop, status, responsedescription?) > + * + */ +void CDAVDirectory::ParseResponse(const TiXmlElement *pElement, CFileItem &item) +{ + const TiXmlElement *pResponseChild; + const TiXmlNode *pPropstatChild; + const TiXmlElement *pPropChild; + + /* Iterate response children elements */ + for (pResponseChild = pElement->FirstChildElement(); pResponseChild != 0; pResponseChild = pResponseChild->NextSiblingElement()) + { + if (CDAVCommon::ValueWithoutNamespace(pResponseChild, "href") && !pResponseChild->NoChildren()) + { + std::string path(pResponseChild->FirstChild()->ValueStr()); + URIUtils::RemoveSlashAtEnd(path); + item.SetPath(path); + } + else + if (CDAVCommon::ValueWithoutNamespace(pResponseChild, "propstat")) + { + if (CDAVCommon::GetStatusTag(pResponseChild->ToElement()).find("200 OK") != std::string::npos) + { + /* Iterate propstat children elements */ + for (pPropstatChild = pResponseChild->FirstChild(); pPropstatChild != 0; pPropstatChild = pPropstatChild->NextSibling()) + { + if (CDAVCommon::ValueWithoutNamespace(pPropstatChild, "prop")) + { + /* Iterate all properties available */ + for (pPropChild = pPropstatChild->FirstChildElement(); pPropChild != 0; pPropChild = pPropChild->NextSiblingElement()) + { + if (CDAVCommon::ValueWithoutNamespace(pPropChild, "getcontentlength") && !pPropChild->NoChildren()) + { + item.m_dwSize = strtoll(pPropChild->FirstChild()->Value(), NULL, 10); + } + else + if (CDAVCommon::ValueWithoutNamespace(pPropChild, "getlastmodified") && !pPropChild->NoChildren()) + { + struct tm timeDate = {}; + strptime(pPropChild->FirstChild()->Value(), "%a, %d %b %Y %T", &timeDate); + item.m_dateTime = mktime(&timeDate); + } + else + if (CDAVCommon::ValueWithoutNamespace(pPropChild, "displayname") && !pPropChild->NoChildren()) + { + item.SetLabel(CURL::Decode(pPropChild->FirstChild()->ValueStr())); + } + else + if (!item.m_dateTime.IsValid() && CDAVCommon::ValueWithoutNamespace(pPropChild, "creationdate") && !pPropChild->NoChildren()) + { + struct tm timeDate = {}; + strptime(pPropChild->FirstChild()->Value(), "%Y-%m-%dT%T", &timeDate); + item.m_dateTime = mktime(&timeDate); + } + else + if (CDAVCommon::ValueWithoutNamespace(pPropChild, "resourcetype")) + { + if (CDAVCommon::ValueWithoutNamespace(pPropChild->FirstChild(), "collection")) + { + item.m_bIsFolder = true; + } + } + } + } + } + } + } + } +} + +bool CDAVDirectory::GetDirectory(const CURL& url, CFileItemList &items) +{ + CCurlFile dav; + std::string 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, "{} - Unable to get dav directory ({})", __FUNCTION__, url.GetRedacted()); + return false; + } + + std::string strResponse; + dav.ReadData(strResponse); + + std::string fileCharset(dav.GetProperty(XFILE::FILE_PROPERTY_CONTENT_CHARSET)); + CXBMCTinyXML davResponse; + davResponse.Parse(strResponse, fileCharset); + + if (!davResponse.Parse(strResponse)) + { + CLog::Log(LOGERROR, "{} - Unable to process dav directory ({})", __FUNCTION__, + url.GetRedacted()); + 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); + const CURL& url2(url); + CURL url3(item.GetPath()); + + std::string itemPath(URIUtils::AddFileToFolder(url2.GetWithoutFilename(), url3.GetFileName())); + + if (item.GetLabel().empty()) + { + std::string name(itemPath); + URIUtils::RemoveSlashAtEnd(name); + item.SetLabel(CURL::Decode(URIUtils::GetFileName(name))); + } + + if (item.m_bIsFolder) + URIUtils::AddSlashAtEnd(itemPath); + + // Add back protocol options + if (!url2.GetProtocolOptions().empty()) + itemPath += "|" + url2.GetProtocolOptions(); + item.SetPath(itemPath); + + if (!item.IsURL(url)) + { + CFileItemPtr pItem(new CFileItem(item)); + items.Add(pItem); + } + } + } + + dav.Close(); + + return true; +} + +bool CDAVDirectory::Create(const CURL& url) +{ + CDAVFile dav; + std::string strRequest = "MKCOL"; + + dav.SetCustomRequest(strRequest); + + if (!dav.Execute(url)) + { + CLog::Log(LOGERROR, "{} - Unable to create dav directory ({}) - {}", __FUNCTION__, + url.GetRedacted(), dav.GetLastResponseCode()); + return false; + } + + dav.Close(); + + return true; +} + +bool CDAVDirectory::Exists(const CURL& url) +{ + CCurlFile dav; + + // Set the PROPFIND custom request else we may not find folders, depending + // on the server's configuration + std::string strRequest = "PROPFIND"; + dav.SetCustomRequest(strRequest); + dav.SetRequestHeader("depth", 0); + + return dav.Exists(url); +} + +bool CDAVDirectory::Remove(const CURL& url) +{ + CDAVFile dav; + std::string strRequest = "DELETE"; + + dav.SetCustomRequest(strRequest); + + if (!dav.Execute(url)) + { + CLog::Log(LOGERROR, "{} - Unable to delete dav directory ({}) - {}", __FUNCTION__, + url.GetRedacted(), dav.GetLastResponseCode()); + return false; + } + + dav.Close(); + + return true; +} |