1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be 33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/ftp/ftp_directory_listing_parser_windows.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <vector> 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h" 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/time.h" 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/ftp/ftp_directory_listing_parser.h" 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/ftp/ftp_util.h" 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace { 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool WindowsDateListingToTime(const std::vector<string16>& columns, 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::Time* time) { 2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen DCHECK_LE(3U, columns.size()); 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::Time::Exploded time_exploded = { 0 }; 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Date should be in format MM-DD-YY[YY]. 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<string16> date_parts; 26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick base::SplitString(columns[0], '-', &date_parts); 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (date_parts.size() != 3) 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!base::StringToInt(date_parts[0], &time_exploded.month)) 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!base::StringToInt(date_parts[1], &time_exploded.day_of_month)) 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!base::StringToInt(date_parts[2], &time_exploded.year)) 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (time_exploded.year < 0) 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If year has only two digits then assume that 00-79 is 2000-2079, 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // and 80-99 is 1980-1999. 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (time_exploded.year < 80) 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott time_exploded.year += 2000; 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else if (time_exploded.year < 100) 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott time_exploded.year += 1900; 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Time should be in format HH:MM(AM|PM) 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (columns[1].length() != 7) 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<string16> time_parts; 48731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick base::SplitString(columns[1].substr(0, 5), ':', &time_parts); 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (time_parts.size() != 2) 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!base::StringToInt(time_parts[0], &time_exploded.hour)) 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!base::StringToInt(time_parts[1], &time_exploded.minute)) 543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!time_exploded.HasValidValues()) 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string16 am_or_pm(columns[1].substr(5, 2)); 583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (EqualsASCII(am_or_pm, "PM")) { 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (time_exploded.hour < 12) 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick time_exploded.hour += 12; 613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else if (EqualsASCII(am_or_pm, "AM")) { 623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (time_exploded.hour == 12) 633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick time_exploded.hour = 0; 643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We don't know the time zone of the server, so just use local time. 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *time = base::Time::FromLocalExploded(time_exploded); 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net { 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ParseFtpDirectoryListingWindows( 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::vector<string16>& lines, 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::vector<FtpDirectoryListingEntry>* entries) { 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (size_t i = 0; i < lines.size(); i++) { 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (lines[i].empty()) 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen continue; 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::vector<string16> columns; 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::SplitString(CollapseWhitespace(lines[i], false), ' ', &columns); 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Every line of the listing consists of the following: 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 1. date 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 2. time 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 3. size in bytes (or "<DIR>" for directories) 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 4. filename (may be empty or contain spaces) 93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // For now, make sure we have 1-3, and handle 4 later. 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (columns.size() < 3) 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FtpDirectoryListingEntry entry; 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (EqualsASCII(columns[2], "<DIR>")) { 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.type = FtpDirectoryListingEntry::DIRECTORY; 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.size = -1; 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.type = FtpDirectoryListingEntry::FILE; 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!base::StringToInt64(columns[2], &entry.size)) 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (entry.size < 0) 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!WindowsDateListingToTime(columns, &entry.last_modified)) 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.name = FtpUtil::GetStringPartAfterColumns(lines[i], 3); 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (entry.name.empty()) { 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Some FTP servers send listing entries with empty names. 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // It's not obvious how to display such an entry, so ignore them. 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // We don't want to make the parsing fail at this point though. 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Other entries can still be useful. 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen continue; 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entries->push_back(entry); 12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace net 129