Merge pull request #5095 from koying/fixdroidappcrash
[vuplus_xbmc] / xbmc / filesystem / DAVDirectory.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "DAVDirectory.h"
22
23 #include "DAVCommon.h"
24 #include "DAVFile.h"
25 #include "URL.h"
26 #include "CurlFile.h"
27 #include "FileItem.h"
28 #include "utils/RegExp.h"
29 #include "utils/StringUtils.h"
30 #include "utils/log.h"
31 #include "utils/URIUtils.h"
32
33 using namespace XFILE;
34
35 CDAVDirectory::CDAVDirectory(void) {}
36 CDAVDirectory::~CDAVDirectory(void) {}
37
38 /*
39  * Parses a <response>
40  *
41  * <!ELEMENT response (href, ((href*, status)|(propstat+)), responsedescription?) >
42  * <!ELEMENT propstat (prop, status, responsedescription?) >
43  *
44  */
45 void CDAVDirectory::ParseResponse(const TiXmlElement *pElement, CFileItem &item)
46 {
47   const TiXmlNode *pResponseChild;
48   const TiXmlNode *pPropstatChild;
49   const TiXmlNode *pPropChild;
50
51   /* Iterate response children elements */
52   for (pResponseChild = pElement->FirstChild(); pResponseChild != 0; pResponseChild = pResponseChild->NextSibling())
53   {
54     if (CDAVCommon::ValueWithoutNamespace(pResponseChild, "href"))
55     {
56       CStdString path(pResponseChild->ToElement()->GetText());
57       URIUtils::RemoveSlashAtEnd(path);
58       item.SetPath(path);
59     }
60     else 
61     if (CDAVCommon::ValueWithoutNamespace(pResponseChild, "propstat"))
62     {
63       if (CDAVCommon::GetStatusTag(pResponseChild->ToElement()) == "HTTP/1.1 200 OK")
64       {
65         /* Iterate propstat children elements */
66         for (pPropstatChild = pResponseChild->FirstChild(); pPropstatChild != 0; pPropstatChild = pPropstatChild->NextSibling())
67         {
68           if (CDAVCommon::ValueWithoutNamespace(pPropstatChild, "prop"))
69           {
70             /* Iterate all properties available */
71             for (pPropChild = pPropstatChild->FirstChild(); pPropChild != 0; pPropChild = pPropChild->NextSibling())
72             {
73               if (CDAVCommon::ValueWithoutNamespace(pPropChild, "getcontentlength"))
74               {
75                 item.m_dwSize = strtoll(pPropChild->ToElement()->GetText(), NULL, 10);
76               }
77               else
78               if (CDAVCommon::ValueWithoutNamespace(pPropChild, "getlastmodified"))
79               {
80                 struct tm timeDate = {0};
81                 strptime(pPropChild->ToElement()->GetText(), "%a, %d %b %Y %T", &timeDate);
82                 item.m_dateTime = mktime(&timeDate);
83               }
84               else
85               if (CDAVCommon::ValueWithoutNamespace(pPropChild, "displayname"))
86               {
87                 item.SetLabel(pPropChild->ToElement()->GetText());
88               }
89               else
90               if (!item.m_dateTime.IsValid() && CDAVCommon::ValueWithoutNamespace(pPropChild, "creationdate"))
91               {
92                 struct tm timeDate = {0};
93                 strptime(pPropChild->ToElement()->GetText(), "%Y-%m-%dT%T", &timeDate);
94                 item.m_dateTime = mktime(&timeDate);
95               }
96               else 
97               if (CDAVCommon::ValueWithoutNamespace(pPropChild, "resourcetype"))
98               {
99                 if (CDAVCommon::ValueWithoutNamespace(pPropChild->FirstChild(), "collection"))
100                 {
101                   item.m_bIsFolder = true;
102                 }
103               }
104             }
105           }
106         }
107       }
108     }
109   }
110 }
111
112 bool CDAVDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
113 {
114   CCurlFile dav;
115   CURL url(strPath);
116   CStdString strRequest = "PROPFIND";
117
118   dav.SetCustomRequest(strRequest);
119   dav.SetMimeType("text/xml; charset=\"utf-8\"");
120   dav.SetRequestHeader("depth", 1);
121   dav.SetPostData(
122     "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
123     " <D:propfind xmlns:D=\"DAV:\">"
124     "   <D:prop>"
125     "     <D:resourcetype/>"
126     "     <D:getcontentlength/>"
127     "     <D:getlastmodified/>"
128     "     <D:creationdate/>"
129     "     <D:displayname/>"
130     "    </D:prop>"
131     "  </D:propfind>");
132
133   if (!dav.Open(url))
134   {
135     CLog::Log(LOGERROR, "%s - Unable to get dav directory (%s)", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
136     return false;
137   }
138
139   CStdString strResponse;
140   dav.ReadData(strResponse);
141
142   std::string fileCharset(dav.GetServerReportedCharset());
143   CXBMCTinyXML davResponse;
144   davResponse.Parse(strResponse, fileCharset);
145
146   if (!davResponse.Parse(strResponse))
147   {
148     CLog::Log(LOGERROR, "%s - Unable to process dav directory (%s)", __FUNCTION__, CURL::GetRedacted(strPath).c_str());
149     dav.Close();
150     return false;
151   }
152
153   TiXmlNode *pChild;
154   // Iterate over all responses
155   for (pChild = davResponse.RootElement()->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
156   {
157     if (CDAVCommon::ValueWithoutNamespace(pChild, "response"))
158     {
159       CFileItem item;
160       ParseResponse(pChild->ToElement(), item);
161       CURL url2(strPath);
162       CURL url3(item.GetPath());
163
164       CStdString itemPath(URIUtils::AddFileToFolder(url2.GetWithoutFilename(), url3.GetFileName()));
165
166       if (item.GetLabel().empty())
167       {
168         CStdString name(itemPath);
169         URIUtils::RemoveSlashAtEnd(name);
170         item.SetLabel(URIUtils::GetFileName(CURL::Decode(name)));
171       }
172
173       if (item.m_bIsFolder)
174         URIUtils::AddSlashAtEnd(itemPath);
175
176       // Add back protocol options
177       if (!url2.GetProtocolOptions().empty())
178         itemPath += "|" + url2.GetProtocolOptions();
179       item.SetPath(itemPath);
180
181       if (!item.GetPath().Equals(strPath))
182       {
183         CFileItemPtr pItem(new CFileItem(item));
184         items.Add(pItem);
185       }
186     }
187   }
188
189   dav.Close();
190
191   return true;
192 }
193
194 bool CDAVDirectory::Create(const char* strPath)
195 {
196   CDAVFile dav;
197   CURL url(strPath);
198   CStdString strRequest = "MKCOL";
199
200   dav.SetCustomRequest(strRequest);
201  
202   if (!dav.Execute(url))
203   {
204     CLog::Log(LOGERROR, "%s - Unable to create dav directory (%s) - %d", __FUNCTION__, url.GetRedacted().c_str(), dav.GetLastResponseCode());
205     return false;
206   }
207
208   dav.Close();
209
210   return true;
211 }
212
213 bool CDAVDirectory::Exists(const char* strPath)
214 {
215   CCurlFile dav;
216
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);
222
223   CURL url(strPath);
224   return dav.Exists(url);
225 }
226
227 bool CDAVDirectory::Remove(const char* strPath)
228 {
229   CDAVFile dav;
230   CURL url(strPath);
231   CStdString strRequest = "DELETE";
232
233   dav.SetCustomRequest(strRequest);
234  
235   if (!dav.Execute(url))
236   {
237     CLog::Log(LOGERROR, "%s - Unable to delete dav directory (%s) - %d", __FUNCTION__, url.GetRedacted().c_str(), dav.GetLastResponseCode());
238     return false;
239   }
240
241   dav.Close();
242
243   return true;
244 }