2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "DAVDirectory.h"
12 #include "DAVCommon.h"
16 #include "utils/StringUtils.h"
17 #include "utils/URIUtils.h"
18 #include "utils/log.h"
20 using namespace XFILE
;
22 CDAVDirectory::CDAVDirectory(void) = default;
23 CDAVDirectory::~CDAVDirectory(void) = default;
28 * <!ELEMENT response (href, ((href*, status)|(propstat+)), responsedescription?) >
29 * <!ELEMENT propstat (prop, status, responsedescription?) >
32 void CDAVDirectory::ParseResponse(const TiXmlElement
*pElement
, CFileItem
&item
)
34 const TiXmlElement
*pResponseChild
;
35 const TiXmlNode
*pPropstatChild
;
36 const TiXmlElement
*pPropChild
;
38 /* Iterate response children elements */
39 for (pResponseChild
= pElement
->FirstChildElement(); pResponseChild
!= 0; pResponseChild
= pResponseChild
->NextSiblingElement())
41 if (CDAVCommon::ValueWithoutNamespace(pResponseChild
, "href") && !pResponseChild
->NoChildren())
43 std::string
path(pResponseChild
->FirstChild()->ValueStr());
44 URIUtils::RemoveSlashAtEnd(path
);
48 if (CDAVCommon::ValueWithoutNamespace(pResponseChild
, "propstat"))
50 if (CDAVCommon::GetStatusTag(pResponseChild
->ToElement()).find("200 OK") != std::string::npos
)
52 /* Iterate propstat children elements */
53 for (pPropstatChild
= pResponseChild
->FirstChild(); pPropstatChild
!= 0; pPropstatChild
= pPropstatChild
->NextSibling())
55 if (CDAVCommon::ValueWithoutNamespace(pPropstatChild
, "prop"))
57 /* Iterate all properties available */
58 for (pPropChild
= pPropstatChild
->FirstChildElement(); pPropChild
!= 0; pPropChild
= pPropChild
->NextSiblingElement())
60 if (CDAVCommon::ValueWithoutNamespace(pPropChild
, "getcontentlength") && !pPropChild
->NoChildren())
62 item
.m_dwSize
= strtoll(pPropChild
->FirstChild()->Value(), NULL
, 10);
65 if (CDAVCommon::ValueWithoutNamespace(pPropChild
, "getlastmodified") && !pPropChild
->NoChildren())
67 struct tm timeDate
= {};
68 strptime(pPropChild
->FirstChild()->Value(), "%a, %d %b %Y %T", &timeDate
);
69 item
.m_dateTime
= mktime(&timeDate
);
72 if (CDAVCommon::ValueWithoutNamespace(pPropChild
, "displayname") && !pPropChild
->NoChildren())
74 item
.SetLabel(CURL::Decode(pPropChild
->FirstChild()->ValueStr()));
77 if (!item
.m_dateTime
.IsValid() && CDAVCommon::ValueWithoutNamespace(pPropChild
, "creationdate") && !pPropChild
->NoChildren())
79 struct tm timeDate
= {};
80 strptime(pPropChild
->FirstChild()->Value(), "%Y-%m-%dT%T", &timeDate
);
81 item
.m_dateTime
= mktime(&timeDate
);
84 if (CDAVCommon::ValueWithoutNamespace(pPropChild
, "resourcetype"))
86 if (CDAVCommon::ValueWithoutNamespace(pPropChild
->FirstChild(), "collection"))
88 item
.m_bIsFolder
= true;
99 bool CDAVDirectory::GetDirectory(const CURL
& url
, CFileItemList
&items
)
102 std::string strRequest
= "PROPFIND";
104 dav
.SetCustomRequest(strRequest
);
105 dav
.SetMimeType("text/xml; charset=\"utf-8\"");
106 dav
.SetRequestHeader("depth", 1);
108 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
109 " <D:propfind xmlns:D=\"DAV:\">"
112 " <D:getcontentlength/>"
113 " <D:getlastmodified/>"
121 CLog::Log(LOGERROR
, "{} - Unable to get dav directory ({})", __FUNCTION__
, url
.GetRedacted());
125 std::string strResponse
;
126 dav
.ReadData(strResponse
);
128 std::string
fileCharset(dav
.GetProperty(XFILE::FILE_PROPERTY_CONTENT_CHARSET
));
129 CXBMCTinyXML davResponse
;
130 davResponse
.Parse(strResponse
, fileCharset
);
132 if (!davResponse
.Parse(strResponse
))
134 CLog::Log(LOGERROR
, "{} - Unable to process dav directory ({})", __FUNCTION__
,
141 // Iterate over all responses
142 for (pChild
= davResponse
.RootElement()->FirstChild(); pChild
!= 0; pChild
= pChild
->NextSibling())
144 if (CDAVCommon::ValueWithoutNamespace(pChild
, "response"))
147 ParseResponse(pChild
->ToElement(), item
);
148 const CURL
& url2(url
);
149 CURL
url3(item
.GetPath());
151 std::string
itemPath(URIUtils::AddFileToFolder(url2
.GetWithoutFilename(), url3
.GetFileName()));
153 if (item
.GetLabel().empty())
155 std::string
name(itemPath
);
156 URIUtils::RemoveSlashAtEnd(name
);
157 item
.SetLabel(CURL::Decode(URIUtils::GetFileName(name
)));
160 if (item
.m_bIsFolder
)
161 URIUtils::AddSlashAtEnd(itemPath
);
163 // Add back protocol options
164 if (!url2
.GetProtocolOptions().empty())
165 itemPath
+= "|" + url2
.GetProtocolOptions();
166 item
.SetPath(itemPath
);
168 if (!item
.IsURL(url
))
170 CFileItemPtr
pItem(new CFileItem(item
));
181 bool CDAVDirectory::Create(const CURL
& url
)
184 std::string strRequest
= "MKCOL";
186 dav
.SetCustomRequest(strRequest
);
188 if (!dav
.Execute(url
))
190 CLog::Log(LOGERROR
, "{} - Unable to create dav directory ({}) - {}", __FUNCTION__
,
191 url
.GetRedacted(), dav
.GetLastResponseCode());
200 bool CDAVDirectory::Exists(const CURL
& url
)
204 // Set the PROPFIND custom request else we may not find folders, depending
205 // on the server's configuration
206 std::string strRequest
= "PROPFIND";
207 dav
.SetCustomRequest(strRequest
);
208 dav
.SetRequestHeader("depth", 0);
210 return dav
.Exists(url
);
213 bool CDAVDirectory::Remove(const CURL
& url
)
216 std::string strRequest
= "DELETE";
218 dav
.SetCustomRequest(strRequest
);
220 if (!dav
.Execute(url
))
222 CLog::Log(LOGERROR
, "{} - Unable to delete dav directory ({}) - {}", __FUNCTION__
,
223 url
.GetRedacted(), dav
.GetLastResponseCode());