using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace AR.FTPClient { /// /// ''' Represents a file or directory entry from an FTP listing /// ''' /// ''' /// ''' This class is used to parse the results from a detailed /// ''' directory list from FTP. It supports most formats of /// ''' public class FTPfileInfo { // Stores extended info about FTP file public string FullName { get { var retval = Path + "/" + Filename; return retval.Replace("//", "/"); } } public string Filename { get { return _filename; } } public string Path { get { return _path; } } public DirectoryEntryTypes FileType { get { return _fileType; } } public long Size { get { return _size; } } public DateTime FileDateTime { get { return _fileDateTime; } } public string Permission { get { return _permission; } } public string Extension { get { int i = this.Filename.LastIndexOf("."); if (i >= 0 & i < (this.Filename.Length - 1)) return this.Filename.Substring(i + 1); else return ""; } } public string NameOnly { get { int i = this.Filename.LastIndexOf("."); if (i > 0) return this.Filename.Substring(0, i); else return this.Filename; } } private string _filename; private string _path; private DirectoryEntryTypes _fileType; private long _size; private DateTime _fileDateTime; private string _permission; /// /// ''' Identifies entry as either File or Directory /// ''' public enum DirectoryEntryTypes { File, Directory, Link } /// /// ''' Constructor taking a directory listing line and path /// ''' /// ''' The line returned from the detailed directory list /// ''' Path of the directory /// ''' public FTPfileInfo(string line, string path) { // parse line Match m = GetMatchingRegex(line); if (m == null) // failed throw new ApplicationException("Unable to parse line: " + line); else { _filename = m.Groups["name"].Value; _path = path; _permission = m.Groups["permission"].Value; string _dir = m.Groups["dir"].Value; if ((_dir != "" & (_dir == "d" || _dir == "D"))) { _fileType = DirectoryEntryTypes.Directory; _size = 0; // CLng(m.Groups("size").Value) } else if ((_dir != "" & (_dir == "l" || _dir == "L"))) { _fileType = DirectoryEntryTypes.Link; _size = 0; // CLng(m.Groups("size").Value) } else { _fileType = DirectoryEntryTypes.File; _size = System.Convert.ToInt64(m.Groups["size"].Value); } try { var timestamp = m.Groups["timestamp"].Value; if (timestamp.IndexOf(':') == -1) { _fileDateTime = DateTime.Parse(timestamp); } else { _fileDateTime = DateTime.Parse(DateTime.Now.Year + " " + timestamp); } } catch { // MsgBox("datetime err=" & Now.Year & Space(1) & "value=" & m.Groups("timestamp").Value & vbCrLf & ex.Message.ToString) _fileDateTime = DateTime.Parse("1982-11-23"); } } } public FTPfileInfo(string filename, string permission, string dir, int size, DateTime filetime, Boolean isdir, string path) { _filename = filename;// m.Groups["name"].Value; _path = path; _permission = permission; // m.Groups["permission"].Value; string _dir = dir;// m.Groups["dir"].Value; if (isdir == true) { _fileType = DirectoryEntryTypes.Directory; _size = 0; // CLng(m.Groups("size").Value) } else { _fileType = DirectoryEntryTypes.File; _size = size;// } _fileDateTime = filetime; } private Match GetMatchingRegex(string line) { Regex rx; Match m; for (int i = 0; i <= _ParseFormats.Length - 1; i++) { rx = new Regex(_ParseFormats[i]); m = rx.Match(line); if (m.Success) return m; } return null; } /// /// ''' List of REGEX formats for different FTP server listing formats /// ''' /// ''' /// ''' The first three are various UNIX/LINUX formats, fourth is for MS FTP /// ''' in detailed mode and the last for MS FTP in 'DOS' mode. /// ''' I wish VB.NET had support for Const arrays like C# but there you go /// ''' private static string[] _ParseFormats = new[] { @"(?[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{4})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{4})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?\d+)\s+(?\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?.+)", @"(?[\-dl])(?([\-r][\-w][\-xs]){3})(\s+)(?(\d+))(\s+)(?(\w+\s\w+))(\s+)(?(\d+))\s+(?\w+\s+\d+\s+\d{2}:\d{2})\s+(?.+)", @"(?\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?\<\w+\>){0,1}(?\d+){0,1}\s+(?.+)" }; } }