using Sarand.Net.Standard.Base.App; using System; using System.Text.RegularExpressions; namespace Sarand.Net.Standard.Base.Utils { //======================================================================= public static class FtpUtil { //------------------------------------------------------------------- /// Cleanse the folder name - delimit with '/', remove duplicate, leading and trailing delimiters. public static String CleansePath (String path) { return path.ReplaceAll("\\", "/").ReplaceAll("//", "/").TrimStart('/').TrimEnd('/'); } //------------------------------------------------------------------- /// Retrieve parent folder for folder. Parent for top level folder is blank. public static String GetParentFolder (String folder) { String parentFolder = ""; String[] folders = CleansePath(folder).Split('/'); if (folders.Length > 0) parentFolder = String.Join("/", folders, 0, folders.Length - 1); return parentFolder; } //------------------------------------------------------------------- /// Retrieve bottom level item name from path. Parent for top level folder is blank. public static String GetItemName (String folder) { String[] folders = CleansePath(folder).Split('/'); if (folders.Length >= 0) return folders[folders.Length - 1]; return ""; } //------------------------------------------------------------------- public class FtpDirectoryItem { public String Attr { get; set; } = ""; public bool IsDirectory { get; set; } public String Owner { get; set; } = ""; public String Group { get; set; } = ""; public int Links { get; set; } public long Size { get; set; } public int Day { get; set; } public int Month { get; set; } public String MonthName { get; set; } = ""; public int Year { get; set; } public String Time { get; set; } = ""; public DateTime Modified { get; set; } public String Name { get; set; } = ""; } // YangMing (Unix?) format: // 08-03-18 10:10AM SolentInboundTest // 08-03-18 10:10AM SolentOutboundTest // 08-03-18 11:23AM 8507075 testDataWithRatherLongFilename.zip // 08-03-18 11:17AM 22 test.txt public static readonly Regex DirectoryListPattern_Unix = new Regex(@"^"+ // 1. Month. @"(\d{2})-"+ // 2. Day of month. @"(\d{2})-"+ // 3. Year. @"(\d{2})\s+"+ // 4. Time. @"(\d{2}:\d{2})"+ // 5. Time period. @"(\w{2})\s+"+ // 6. Directory indicator or Filesize. @"(|\d+)\s+"+ // Name. @"([^\s]+)$", RegexOptions.IgnoreCase); // Windows/DOS format: // drwx------ 3 user group 0 Apr 10 07:47 test // -rw - r--r-- 1 ftp ftp 5592560 Feb 26 18:53 DamonJenkinsA_84_C_CTS.dds // Update date format: // MMM dd HH:mm if the file was modified in the last six months // MMM dd yyyy otherwise. public static readonly Regex DirectoryListPattern_Windows = new Regex(@"^"+ // 1. Attributes. // 1st Character: '-' file. 'b' Block special file. 'c' Character special file. 'd' directory. 'l' link. 'n' Network file. 'p' FIFO. 's' Socket. // Attributes: r Permission to read file. w Permission to write to file. x Permission to execute file. a Archive bit is on (file has not been backed up). // c Compressed file. s System file. h Hidden file. t Temporary file. @"([abcdhlnprstwx-]{10})\s+" + // 2. Number of links to ths file. @"(\d+)\s+"+ // 3. Owner. @"([^\s]+)\s+"+ // 4. Group. @"([^\s]+)\s+"+ // 5. Size. @"(\d+)\s+"+ // 6. Month. @"(\w{3})\s+"+ // 7. Day of month. @"(\d{1,2})\s+"+ // 8. Time or Year. @"(\d{4}|\d\d:\d\d)\s+"+ // Name. @"(.+)$", RegexOptions.IgnoreCase); /// Extract details from Directory detail list item. public static FtpDirectoryItem GetDirectoryItem (String directoryItemData) { if (StringUtil.IsEmpty(StringUtil.EmptyOnNull(directoryItemData).Trim())) return null; // Check for Unix directory listing pattern. Match match = DirectoryListPattern_Unix.Match(directoryItemData); if (match.Success && match.Groups.Count == 8) { FtpDirectoryItem directoryItem = new FtpDirectoryItem(); directoryItem.Month = StringUtil.ToInt(match.Groups[1].Value); directoryItem.Day = StringUtil.ToInt(match.Groups[2].Value); directoryItem.Year = StringUtil.ToInt(match.Groups[3].Value); String directoryOrFileSize = match.Groups[6].Value; if (directoryOrFileSize.EqualsCI("")) directoryItem.IsDirectory = true; else directoryItem.Size = StringUtil.ToLong(directoryOrFileSize); directoryItem.Name = match.Groups[7].Value; return directoryItem; } // Check for Windows directory listing pattern. match = DirectoryListPattern_Windows.Match(directoryItemData); if (match.Success && match.Groups.Count == 10) { FtpDirectoryItem directoryItem = new FtpDirectoryItem(); directoryItem.Attr = match.Groups[1].Value; directoryItem.IsDirectory = StringUtil.Left(directoryItem.Attr, 1).EqualsCI("d"); directoryItem.Links = StringUtil.ToInt(match.Groups[2].Value); directoryItem.Owner = match.Groups[3].Value; directoryItem.Group = match.Groups[4].Value; directoryItem.Size = StringUtil.ToInt(match.Groups[5].Value); directoryItem.MonthName = match.Groups[6].Value; directoryItem.Day = StringUtil.ToInt(match.Groups[7].Value); String timeYear = match.Groups[8].Value; if (StringUtil.IsNumeric(timeYear)) directoryItem.Year = StringUtil.ToInt(timeYear); directoryItem.Name = match.Groups[9].Value; return directoryItem; } // Log failure. SaLogger.Warn("FtpUtils.GetDirectoryItem Parse Failed: '" + directoryItemData + "'", true); return null; } //------------------------------------------------------------------- } //======================================================================= }