2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "DAVDirectory.h"
23 #include "DAVCommon.h"
28 #include "utils/RegExp.h"
29 #include "utils/StringUtils.h"
30 #include "utils/log.h"
31 #include "utils/URIUtils.h"
33 using namespace XFILE;
35 CDAVDirectory::CDAVDirectory(void) {}
36 CDAVDirectory::~CDAVDirectory(void) {}
41 * <!ELEMENT response (href, ((href*, status)|(propstat+)), responsedescription?) >
42 * <!ELEMENT propstat (prop, status, responsedescription?) >
45 void CDAVDirectory::ParseResponse(const TiXmlElement *pElement, CFileItem &item)
47 const TiXmlNode *pResponseChild;
48 const TiXmlNode *pPropstatChild;
49 const TiXmlNode *pPropChild;
51 /* Iterate response children elements */
52 for (pResponseChild = pElement->FirstChild(); pResponseChild != 0; pResponseChild = pResponseChild->NextSibling())
54 if (CDAVCommon::ValueWithoutNamespace(pResponseChild, "href"))
56 CStdString path(pResponseChild->ToElement()->GetText());
57 URIUtils::RemoveSlashAtEnd(path);
61 if (CDAVCommon::ValueWithoutNamespace(pResponseChild, "propstat"))
63 if (CDAVCommon::GetStatusTag(pResponseChild->ToElement()) == "HTTP/1.1 200 OK")
65 /* Iterate propstat children elements */
66 for (pPropstatChild = pResponseChild->FirstChild(); pPropstatChild != 0; pPropstatChild = pPropstatChild->NextSibling())
68 if (CDAVCommon::ValueWithoutNamespace(pPropstatChild, "prop"))
70 /* Iterate all properties available */
71 for (pPropChild = pPropstatChild->FirstChild(); pPropChild != 0; pPropChild = pPropChild->NextSibling())
73 if (CDAVCommon::ValueWithoutNamespace(pPropChild, "getcontentlength"))
75 item.m_dwSize = strtoll(pPropChild->ToElement()->GetText(), NULL, 10);
78 if (CDAVCommon::ValueWithoutNamespace(pPropChild, "getlastmodified"))
80 struct tm timeDate = {0};
81 strptime(pPropChild->ToElement()->GetText(), "%a, %d %b %Y %T", &timeDate);
82 item.m_dateTime = mktime(&timeDate);
85 if (CDAVCommon::ValueWithoutNamespace(pPropChild, "displayname"))
87 item.SetLabel(pPropChild->ToElement()->GetText());
90 if (!item.m_dateTime.IsValid() && CDAVCommon::ValueWithoutNamespace(pPropChild, "creationdate"))
92 struct tm timeDate = {0};
93 strptime(pPropChild->ToElement()->GetText(), "%Y-%m-%dT%T", &timeDate);
94 item.m_dateTime = mktime(&timeDate);
97 if (CDAVCommon::ValueWithoutNamespace(pPropChild, "resourcetype"))
99 if (CDAVCommon::ValueWithoutNamespace(pPropChild->FirstChild(), "collection"))
101 item.m_bIsFolder = true;
112 bool CDAVDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
116 CStdString strRequest = "PROPFIND";
118 dav.SetCustomRequest(strRequest);
119 dav.SetMimeType("text/xml; charset=\"utf-8\"");
120 dav.SetRequestHeader("depth", 1);
122 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
123 " <D:propfind xmlns:D=\"DAV:\">"
126 " <D:getcontentlength/>"
127 " <D:getlastmodified/>"
135 CLog::Log(LOGERROR, "%s - Unable to get dav directory (%s)", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
139 CStdString strResponse;
140 dav.ReadData(strResponse);
142 std::string fileCharset(dav.GetServerReportedCharset());
143 CXBMCTinyXML davResponse;
144 davResponse.Parse(strResponse, fileCharset);
146 if (!davResponse.Parse(strResponse))
148 CLog::Log(LOGERROR, "%s - Unable to process dav directory (%s)", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
154 // Iterate over all responses
155 for (pChild = davResponse.RootElement()->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
157 if (CDAVCommon::ValueWithoutNamespace(pChild, "response"))
160 ParseResponse(pChild->ToElement(), item);
162 CURL url3(item.GetPath());
164 CStdString itemPath(URIUtils::AddFileToFolder(url2.GetWithoutFilename(), url3.GetFileName()));
166 if (item.GetLabel().empty())
168 CStdString name(itemPath);
169 URIUtils::RemoveSlashAtEnd(name);
170 item.SetLabel(URIUtils::GetFileName(CURL::Decode(name)));
173 if (item.m_bIsFolder)
174 URIUtils::AddSlashAtEnd(itemPath);
176 // Add back protocol options
177 if (!url2.GetProtocolOptions().empty())
178 itemPath += "|" + url2.GetProtocolOptions();
179 item.SetPath(itemPath);
181 if (!item.GetPath().Equals(strPath))
183 CFileItemPtr pItem(new CFileItem(item));
194 bool CDAVDirectory::Create(const char* strPath)
198 CStdString strRequest = "MKCOL";
200 dav.SetCustomRequest(strRequest);
202 if (!dav.Execute(url))
204 CLog::Log(LOGERROR, "%s - Unable to create dav directory (%s) - %d", __FUNCTION__, url.GetRedacted().c_str(), dav.GetLastResponseCode());
213 bool CDAVDirectory::Exists(const char* strPath)
217 // Set the PROPFIND custom request else we may not find folders, depending
218 // on the server's configuration
219 CStdString strRequest = "PROPFIND";
220 dav.SetCustomRequest(strRequest);
221 dav.SetRequestHeader("depth", 0);
224 return dav.Exists(url);
227 bool CDAVDirectory::Remove(const char* strPath)
231 CStdString strRequest = "DELETE";
233 dav.SetCustomRequest(strRequest);
235 if (!dav.Execute(url))
237 CLog::Log(LOGERROR, "%s - Unable to delete dav directory (%s) - %d", __FUNCTION__, url.GetRedacted().c_str(), dav.GetLastResponseCode());