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"
25 #include "utils/RegExp.h"
26 #include "utils/StringUtils.h"
27 #include "utils/CharsetConverter.h"
28 #include "utils/log.h"
29 #include "utils/URIUtils.h"
31 using namespace XFILE;
33 CDAVDirectory::CDAVDirectory(void) {}
34 CDAVDirectory::~CDAVDirectory(void) {}
37 * Return true if pElement value is equal value without namespace.
39 * if pElement is <DAV:foo> and value is foo then ValueWithoutNamespace is true
41 bool CDAVDirectory::ValueWithoutNamespace(const TiXmlNode *pNode, CStdString value)
43 CStdStringArray result;
44 const TiXmlElement *pElement;
51 pElement = pNode->ToElement();
58 StringUtils::SplitString(pElement->Value(), ":", result, 2);
60 if (result.size() == 1 && result[0] == value)
64 else if (result.size() == 2 && result[1] == value)
68 else if (result.size() > 2)
70 CLog::Log(LOGERROR, "%s - Splitting %s failed, size(): %lu, value: %s", __FUNCTION__, pElement->Value(), (unsigned long int)result.size(), value.c_str());
77 * Search for <status> and return its content
79 CStdString CDAVDirectory::GetStatusTag(const TiXmlElement *pElement)
81 const TiXmlElement *pChild;
83 for (pChild = pElement->FirstChild()->ToElement(); pChild != 0; pChild = pChild->NextSibling()->ToElement())
85 if (ValueWithoutNamespace(pChild, "status"))
87 return CStdString(pChild->GetText());
91 return CStdString("");
97 * <!ELEMENT response (href, ((href*, status)|(propstat+)), responsedescription?) >
98 * <!ELEMENT propstat (prop, status, responsedescription?) >
101 void CDAVDirectory::ParseResponse(const TiXmlElement *pElement, CFileItem &item)
103 const TiXmlNode *pResponseChild;
104 const TiXmlNode *pPropstatChild;
105 const TiXmlNode *pPropChild;
107 /* Iterate response children elements */
108 for (pResponseChild = pElement->FirstChild(); pResponseChild != 0; pResponseChild = pResponseChild->NextSibling())
110 if (ValueWithoutNamespace(pResponseChild, "href"))
112 CStdString path(pResponseChild->ToElement()->GetText());
113 URIUtils::RemoveSlashAtEnd(path);
117 if (ValueWithoutNamespace(pResponseChild, "propstat"))
119 if (GetStatusTag(pResponseChild->ToElement()) == "HTTP/1.1 200 OK")
121 /* Iterate propstat children elements */
122 for (pPropstatChild = pResponseChild->FirstChild(); pPropstatChild != 0; pPropstatChild = pPropstatChild->NextSibling())
124 if (ValueWithoutNamespace(pPropstatChild, "prop"))
126 /* Iterate all properties available */
127 for (pPropChild = pPropstatChild->FirstChild(); pPropChild != 0; pPropChild = pPropChild->NextSibling())
129 if (ValueWithoutNamespace(pPropChild, "getcontentlength"))
131 item.m_dwSize = strtoll(pPropChild->ToElement()->GetText(), NULL, 10);
134 if (ValueWithoutNamespace(pPropChild, "getlastmodified"))
136 struct tm timeDate = {0};
137 strptime(pPropChild->ToElement()->GetText(), "%a, %d %b %Y %T", &timeDate);
138 item.m_dateTime = mktime(&timeDate);
141 if (ValueWithoutNamespace(pPropChild, "displayname"))
143 item.SetLabel(pPropChild->ToElement()->GetText());
146 if (!item.m_dateTime.IsValid() && ValueWithoutNamespace(pPropChild, "creationdate"))
148 struct tm timeDate = {0};
149 strptime(pPropChild->ToElement()->GetText(), "%Y-%m-%dT%T", &timeDate);
150 item.m_dateTime = mktime(&timeDate);
153 if (ValueWithoutNamespace(pPropChild, "resourcetype"))
155 if (ValueWithoutNamespace(pPropChild->FirstChild(), "collection"))
157 item.m_bIsFolder = true;
168 bool CDAVDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
172 CStdString strRequest = "PROPFIND";
174 dav.SetCustomRequest(strRequest);
175 dav.SetMimeType("text/xml; charset=\"utf-8\"");
176 dav.SetRequestHeader("depth", 1);
178 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
179 " <D:propfind xmlns:D=\"DAV:\">"
182 " <D:getcontentlength/>"
183 " <D:getlastmodified/>"
191 CLog::Log(LOGERROR, "%s - Unable to get dav directory (%s)", __FUNCTION__, strPath.c_str());
195 CStdString strResponse;
196 dav.ReadData(strResponse);
198 CXBMCTinyXML davResponse;
199 davResponse.Parse(strResponse.c_str());
201 if (!davResponse.Parse(strResponse))
203 CLog::Log(LOGERROR, "%s - Unable to process dav directory (%s)", __FUNCTION__, strPath.c_str());
209 // Iterate over all responses
210 for (pChild = davResponse.RootElement()->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
212 if (ValueWithoutNamespace(pChild, "response"))
215 ParseResponse(pChild->ToElement(), item);
217 CURL url3(item.GetPath());
219 CStdString itemPath(URIUtils::AddFileToFolder(url2.GetWithoutFilename(), url3.GetFileName()));
221 if (item.GetLabel().IsEmpty())
223 CStdString name(itemPath);
224 URIUtils::RemoveSlashAtEnd(name);
226 item.SetLabel(URIUtils::GetFileName(name));
229 if (item.m_bIsFolder)
230 URIUtils::AddSlashAtEnd(itemPath);
232 // Add back protocol options
233 if (!url2.GetProtocolOptions().IsEmpty())
234 itemPath += "|" + url2.GetProtocolOptions();
235 item.SetPath(itemPath);
237 if (!item.GetPath().Equals(strPath))
239 CFileItemPtr pItem(new CFileItem(item));
250 bool CDAVDirectory::Exists(const char* strPath)
254 // Set the PROPFIND custom request else we may not find folders, depending
255 // on the server's configuration
256 CStdString strRequest = "PROPFIND";
257 dav.SetCustomRequest(strRequest);
260 return dav.Exists(url);