2 * Copyright (C) 2010-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.
13 CFTPParse::CFTPParse()
20 int CFTPParse::getFlagtrycwd()
25 int CFTPParse::getFlagtryretr()
30 uint64_t CFTPParse::getSize()
35 time_t CFTPParse::getTime()
42 const std::string months
= "janfebmaraprmayjunjulaugsepoctnovdec";
44 // set time_struct.tm_mon from the 3-letter "abbreviated month name"
45 void setMonFromName(struct tm
& time_struct
, const std::string
& name
)
48 if (std::regex_search(months
, match
, std::regex(name
, std::regex_constants::icase
)))
50 int pos
= match
.position();
51 if (name
.size() == 3 && pos
% 3 == 0)
52 time_struct
.tm_mon
= pos
/ 3;
57 void CFTPParse::setTime(const std::string
& str
)
59 /* time struct used to set the time_t variable */
60 struct tm time_struct
= {};
62 // sub matches from regex_match() calls below
65 // Regex to read Unix, NetWare and NetPresenz time format
66 if (std::regex_match(str
, match
,
67 std::regex("^([A-Za-z]{3})" // month
68 "\\s+(\\d{1,2})" // day of month
69 "\\s+([:\\d]{4,5})$"))) // time of day or year
71 auto month
= match
[1].str();
72 auto day
= match
[2].str();
73 auto year
= match
[3].str();
76 setMonFromName(time_struct
, month
);
78 /* set the day of the month */
79 time_struct
.tm_mday
= std::stol(day
);
81 time_t t
= time(NULL
);
82 struct tm
*current_time
;
84 struct tm result
= {};
85 current_time
= localtime_r(&t
, &result
);
87 current_time
= localtime(&t
);
89 if (std::regex_match(year
, match
, std::regex("(\\d{2}):(\\d{2})")))
91 /* set the hour and minute */
92 time_struct
.tm_hour
= std::stol(match
[1].str());
93 time_struct
.tm_min
= std::stol(match
[2].str());
96 if ((current_time
->tm_mon
- time_struct
.tm_mon
< 0) ||
97 ((current_time
->tm_mon
- time_struct
.tm_mon
== 0) &&
98 (current_time
->tm_mday
- time_struct
.tm_mday
< 0)))
99 time_struct
.tm_year
= current_time
->tm_year
- 1;
101 time_struct
.tm_year
= current_time
->tm_year
;
106 time_struct
.tm_year
= std::stol(year
) - 1900;
109 // Regex to read MultiNet time format
110 else if (std::regex_match(str
, match
,
111 std::regex("^(\\d{1,2})" // day of month
112 "-([A-Za-z]{3})" // month
114 "\\s+(\\d{2})" // hour
115 ":(\\d{2})" // minute
116 "(:(\\d{2}))?$"))) // second
118 auto day
= match
[1].str();
119 auto month
= match
[2].str();
120 auto year
= match
[3].str();
121 auto hour
= match
[4].str();
122 auto minute
= match
[5].str();
124 auto second
= match
[7].str();
127 setMonFromName(time_struct
, month
);
129 /* set the day of the month and year */
130 time_struct
.tm_mday
= std::stol(day
);
131 time_struct
.tm_year
= std::stol(year
) - 1900;
133 /* set the hour and minute */
134 time_struct
.tm_hour
= std::stol(hour
);
135 time_struct
.tm_min
= std::stol(minute
);
137 /* set the second if given*/
138 if (second
.length() > 0)
139 time_struct
.tm_sec
= std::stol(second
);
141 // Regex to read MSDOS time format
142 else if (std::regex_match(str
, match
,
143 std::regex("^(\\d{2})" // month
144 "-(\\d{2})" // day of month
146 "\\s+(\\d{2})" // hour
147 ":(\\d{2})" // minute
148 "([AP]M)$"))) // AM or PM
150 auto month
= match
[1].str();
151 auto day
= match
[2].str();
152 auto year
= match
[3].str();
153 auto hour
= match
[4].str();
154 auto minute
= match
[5].str();
155 auto am_or_pm
= match
[6].str();
157 /* set the month and the day of the month */
158 time_struct
.tm_mon
= std::stol(month
) - 1;
159 time_struct
.tm_mday
= std::stol(day
);
162 time_struct
.tm_year
= std::stoi(year
);
163 if (time_struct
.tm_year
< 70)
164 time_struct
.tm_year
+= 100;
167 time_struct
.tm_hour
= std::stoi(hour
);
168 if (time_struct
.tm_hour
== 12)
169 time_struct
.tm_hour
-= 12;
170 if (am_or_pm
== "PM")
171 time_struct
.tm_hour
+= 12;
174 time_struct
.tm_min
= std::stoi(minute
);
178 m_time
= mktime(&time_struct
);
181 int CFTPParse::FTPParse(const std::string
& str
)
183 // sub matches from regex_match() calls below
186 // Regex for standard Unix listing formats
187 if (std::regex_match(
189 std::regex("^([-bcdlps])" // type
190 "([-rwxXsStT]{9})" // permissions
191 "\\s+(\\d+)" // hard link count
192 "\\s+(\\w+)" // owner
193 "\\s+(\\w+)" // group
195 "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // modification date
196 "\\s+(.+)$"))) // name
198 auto type
= match
[1].str();
199 auto permissions
= match
[2].str();
200 auto link_count
= match
[3].str();
201 auto owner
= match
[4].str();
202 auto group
= match
[5].str();
203 auto size
= match
[6].str();
204 auto date
= match
[7].str();
205 m_name
= match
[8].str();
207 m_size
= std::stoull(size
);
214 m_flagtrycwd
= m_flagtryretr
= 1;
216 size_t found
= m_name
.find(" -> ");
217 if (found
!= std::string::npos
)
218 m_name
.resize(found
);
224 // Regex for NetWare listing formats
225 // See http://www.novell.com/documentation/oes/ftp_enu/data/a3ep22p.html#fbhbaijf
226 if (std::regex_match(str
, match
,
227 std::regex("^([-d])" // type
228 "\\s+(\\[[-SRWCIEMFA]{8}\\])" // rights
229 "\\s+(\\w+)" // owner
231 "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // time
232 "\\s+(.+)$"))) // name
234 auto type
= match
[1].str();
235 auto permissions
= match
[2].str();
236 auto owner
= match
[3].str();
237 auto size
= match
[4].str();
238 auto date
= match
[5].str();
239 m_name
= match
[6].str();
241 m_size
= std::stoull(size
);
250 // Regex for NetPresenz
251 // See http://files.stairways.com/other/ftp-list-specs-info.txt
252 // Here we will capture permissions and size if given
253 if (std::regex_match(
255 std::regex("^([-dl])" // type
256 "([-rwx]{9}|)" // permissions
258 "\\s+(\\d+|)" // size
259 "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // modification date
260 "\\s+(.+)$"))) // name
262 auto type
= match
[1].str();
263 auto permissions
= match
[2].str();
264 auto stuff
= match
[3].str();
265 auto size
= match
[4].str();
266 auto date
= match
[5].str();
267 m_name
= match
[6].str();
269 m_size
= std::stoull(size
);
276 m_flagtrycwd
= m_flagtryretr
= 1;
278 size_t found
= m_name
.find(" -> ");
279 if (found
!= std::string::npos
)
280 m_name
.resize(found
);
287 // See http://cr.yp.to/ftp/list/eplf.html
288 // SAVE: "(/,|r,|s\\d+,|m\\d+,|i[\\d!#@$%^&*()]+(\\.[\\d!#@$%^&*()]+|),)+"
289 if (std::regex_match(str
, match
,
290 std::regex("^\\+" // initial "plus" sign
292 "\\s(.+)$"))) // name
294 auto facts
= match
[1].str();
295 m_name
= match
[2].str();
297 /* Get the type, size, and date from the facts */
298 std::regex_search(facts
, match
, std::regex("(?:\\+|,)(r|/),"));
299 auto type
= match
[1].str();
300 std::regex_search(facts
, match
, std::regex("(?:\\+|,)s(\\d+),"));
301 auto size
= match
[1].str();
302 std::regex_search(facts
, match
, std::regex("(?:\\+|,)m(\\d+),"));
303 auto date
= match
[1].str();
305 m_size
= std::stoull(size
);
310 /* eplf stores the date in time_t format already */
311 m_time
= std::stoi(date
);
315 // Regex for MultiNet
316 // Best documentation found was
317 // http://www-sld.slac.stanford.edu/SLDWWW/workbook/vms_files.html
318 if (std::regex_match(
320 std::regex("^([^;]+)" // name
322 "\\s+([\\d/]+)" // file id
323 "\\s+(\\d{1,2}-[A-Za-z]{3}-\\d{4}\\s+\\d{2}:\\d{2}(:\\d{2})?)" // date
324 "\\s+\\[([^\\]]+)\\]" // owner,group
325 "\\s+\\(([^\\)]+)\\)$"))) // permissions
327 auto name
= match
[1].str();
328 auto version
= match
[2].str();
329 auto file_id
= match
[3].str();
330 auto date
= match
[4].str();
332 auto owner
= match
[6].str();
333 auto permissions
= match
[7].str();
335 if (std::regex_search(name
, std::regex("\\.DIR$")))
337 name
.resize(name
.size() - 4);
344 /* Multinet doesn't provide a size */
350 if (std::regex_match(str
, match
,
351 std::regex("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date
352 "\\s+(<DIR>|[\\d]+)" // dir or size
353 "\\s+(.+)$"))) // name
355 auto date
= match
[1].str();
356 auto size
= match
[2].str();
357 m_name
= match
[3].str();
366 m_size
= std::stoull(size
);