1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "FTPDirectory.h"
10 
11 #include "CurlFile.h"
12 #include "FTPParse.h"
13 #include "FileItem.h"
14 #include "URL.h"
15 #include "utils/CharsetConverter.h"
16 #include "utils/StringUtils.h"
17 #include "utils/URIUtils.h"
18 
19 #include <climits>
20 
21 using namespace XFILE;
22 
23 CFTPDirectory::CFTPDirectory(void) = default;
24 CFTPDirectory::~CFTPDirectory(void) = default;
25 
GetDirectory(const CURL & url2,CFileItemList & items)26 bool CFTPDirectory::GetDirectory(const CURL& url2, CFileItemList &items)
27 {
28   CCurlFile reader;
29 
30   CURL url(url2);
31 
32   std::string path = url.GetFileName();
33   if( !path.empty() && !StringUtils::EndsWith(path, "/") )
34   {
35     path += "/";
36     url.SetFileName(path);
37   }
38 
39   if (!reader.Open(url))
40     return false;
41 
42   bool serverNotUseUTF8 = url.GetProtocolOption("utf8") == "0";
43 
44   char buffer[MAX_PATH + 1024];
45   while( reader.ReadString(buffer, sizeof(buffer)) )
46   {
47     std::string strBuffer = buffer;
48 
49     StringUtils::RemoveCRLF(strBuffer);
50 
51     CFTPParse parse;
52     if (parse.FTPParse(strBuffer))
53     {
54       if( parse.getName().length() == 0 )
55         continue;
56 
57       if( parse.getFlagtrycwd() == 0 && parse.getFlagtryretr() == 0 )
58         continue;
59 
60       /* buffer name */
61       std::string name;
62       name.assign(parse.getName());
63 
64       if( name == ".." || name == "." )
65         continue;
66 
67       // server returned filename could in utf8 or non-utf8 encoding
68       // we need utf8, so convert it to utf8 anyway
69       g_charsetConverter.unknownToUTF8(name);
70 
71       // convert got empty result, ignore it
72       if (name.empty())
73         continue;
74 
75       if (serverNotUseUTF8 || name != parse.getName())
76         // non-utf8 name path, tag it with protocol option.
77         // then we can talk to server with the same encoding in CurlFile according to this tag.
78         url.SetProtocolOption("utf8", "0");
79       else
80         url.RemoveProtocolOption("utf8");
81 
82       CFileItemPtr pItem(new CFileItem(name));
83 
84       pItem->m_bIsFolder = parse.getFlagtrycwd() != 0;
85       std::string filePath = path + name;
86       if (pItem->m_bIsFolder)
87         URIUtils::AddSlashAtEnd(filePath);
88 
89       /* qualify the url with host and all */
90       url.SetFileName(filePath);
91       pItem->SetPath(url.Get());
92 
93       pItem->m_dwSize = parse.getSize();
94       pItem->m_dateTime=parse.getTime();
95 
96       items.Add(pItem);
97     }
98   }
99 
100   return true;
101 }
102 
Exists(const CURL & url)103 bool CFTPDirectory::Exists(const CURL& url)
104 {
105   // make sure ftp dir ends with slash,
106   // curl need to known it's a dir to check ftp directory existence.
107   std::string file = url.Get();
108   URIUtils::AddSlashAtEnd(file);
109 
110   CCurlFile ftp;
111   CURL url2(file);
112   return ftp.Exists(url2);
113 }
114