Logo Search packages:      
Sourcecode: bareftp version File versions  Download package

ListParser.cs

// ListParser.cs
//
//  Major parts of this code is based on code from edtftpnet see CREDITS,
//  Copyright (C) 2004 Enterprise Distributed Technologies Ltd

//  Modifications by Christian Eide, Copyright (C) 2008-2009 
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;

namespace bareFTP.Protocol.Ftp
{
      public class ListParser
      {     
            public static List<RemoteFile> ParseList(List<string> list)
            {
                  if(list == null || list.Count < 1)
                        return new List<RemoteFile>();

                  
                  string format1a = "MMM'-'d'-'yyyy";
                  string format1b = "MMM'-'dd'-'yyyy";
                  string[] format1 = {format1a,format1b};
                  string format2a = "MMM'-'d'-'yyyy'-'HH':'mm";
                  string format2b = "MMM'-'dd'-'yyyy'-'HH':'mm";  
            string format2c = "MMM'-'d'-'yyyy'-'H':'mm";         
            string format2d = "MMM'-'dd'-'yyyy'-'H':'mm";
                  string winformat = "MM'-'dd'-'yy hh':'mmtt";
            string mlsdformat = "yyyyMMddHHmmss";
                  
              string[] format2 = {format2a,format2b,format2c,format2d};
        
                  System.Globalization.CultureInfo ParsingCulture = System.Globalization.CultureInfo.InvariantCulture;
                  
                  bool sysUnix = false;
                  bool mlsd = false;
                  
                  string teststr = string.Empty;
                  foreach(string test in list)
                  {
                        if(!string.IsNullOrEmpty(test.Trim()))
                        {
                              teststr = test;
                              break;
                        }
                  }
                  
                  if(teststr.StartsWith("-") || teststr.StartsWith("d") || teststr.StartsWith("l") || teststr.StartsWith("total"))
                  sysUnix = true;
                  
                  if(teststr.StartsWith("type="))
                        mlsd = true;
                  
            // TODO: I bet we have more systems out there...
            
                  List<RemoteFile> files = new List<RemoteFile>();
                  
                  if(mlsd)
                  {
                        foreach(string s in list)
                        {
                              RemoteFile file = new RemoteFile();
                              
                              foreach(string fact in s.Split(';'))
                              {
                                    if(fact.IndexOf('=') > 0)
                                    {
                                          string[] keyval = fact.Split('=');
                                          if(keyval[0].ToLower() == "type")
                                          {
                                                if(keyval[1].ToLower() == "file")
                                                      file.IsDir = false;
                                                else
                                                      file.IsDir = true;
                                          }
                                          else if(keyval[0].ToLower() == "size")
                                          {
                                                file.Size = Convert.ToInt64(keyval[1]);
                                          }
                                          else if(keyval[0].ToLower() == "modify")
                                          {
                                                file.LastModified = DateTime.ParseExact(keyval[1].Substring(0,14), mlsdformat,
                                                            ParsingCulture.DateTimeFormat, DateTimeStyles.None);
                                          }
                                          else if(keyval[0].ToLower() == "unix.mode")
                                          {
                                                file.Permissions = bareFTP.Common.Utils.PermissionParser.ModeToRWXT(keyval[1]);
                                          }
                                          else if(keyval[0].ToLower() == "unix.uid")
                                          {
                                                file.Owner = keyval[1];
                                          }
                                          else if(keyval[0].ToLower() == "unix.gid")
                                          {
                                                file.Group = keyval[1];
                                          }
                                    }
                                    else
                                          file.Filename = fact.Trim();
                                    
                              }
                              files.Add(file);
                        }
                  
                  }
                  else if(sysUnix)
                  {
                        foreach(string s in list)
                              {
                                    if(s.StartsWith("total") || string.IsNullOrEmpty(s.Trim()))
                              continue;
                              
                              List<string> fields = getFields(s);
                              
                                    
                              ////////////////
                              // field pos
                              int index = 0;
                                                      // first field is perms
                              string permissions = fields[index++];
                              char ch = permissions[0];
                              bool isDir = false;
                              bool isLink = false;
                              if (ch == 'd')
                                    isDir = true;
                              else if (ch == 'l')
                                    isLink = true;
                              
                              // some servers don't supply the link count                             
                              int linkCount = 0;
                        if (Char.IsDigit(fields[index][0])) // assume it is if a digit
                        {
                            try
                                    {
                                          linkCount = System.Int32.Parse(fields[index++]);
                                    }
                                    catch (FormatException)
                                    {
                                    }
                        }
                        else if (fields[index][0] == '-') // IPXOS Treck FTP server
                        {
                            index++;
                        }

                                    
                              // owner and group
                              string owner = fields[index++];
                              string group = fields[index++];
                  
                              // size
                              long size = 0L;
                              string sizeStr = fields[index];
                        // some listings don't have owner - make owner -> group & group -> size in
                        // this case, and use the sizeStr for the start of the date
                        if (!Char.IsDigit(sizeStr[0]) && Char.IsDigit(group[0])) 
                        {
                        sizeStr = group;  
                        group = owner;
                        owner = "";
                        }
                        else 
                        {
                        index++; 
                        }
            
                              try
                              {
                                    size = Int64.Parse(sizeStr);
                              }
                              catch (FormatException)
                              {
                                    throw new FormatException("Failed to parse size: " + sizeStr);
                              }                     
            
                        // next 3 fields are the date time
                        
                        // we expect the month first on Unix. 
                        // Connect:Enterprise UNIX has a weird extra field here - we test if the 
                        // next field starts with a digit and if so, we skip it
                        if (Char.IsDigit(fields[index][0]))
                            index++;

                              int dateTimePos = index;
                              DateTime lastModified;
                              StringBuilder stamp = new StringBuilder(fields[index++]);
                              stamp.Append('-').Append(fields[index++]).Append('-');
                              
                              string field = fields[index++];
                              if (field.IndexOf((System.Char) ':') < 0)
                              {
                                    stamp.Append(field); // year
                            try
                            {
                                lastModified = DateTime.ParseExact(stamp.ToString(), format1,
                                                            ParsingCulture.DateTimeFormat, DateTimeStyles.None);
                            }
                            catch (FormatException)
                            {
                                //log.Error("Failed to parse date string '" + stamp.ToString() + "'");
                                throw;
                            }
                              }
                              else
                              {
                                    // add the year ourselves as not present
                            int year = ParsingCulture.Calendar.GetYear(DateTime.Now);
                                    stamp.Append(year).Append('-').Append(field);
                            try
                            {

                                lastModified = DateTime.ParseExact(stamp.ToString(), format2,
                                                            ParsingCulture.DateTimeFormat, DateTimeStyles.None);
                            }
                            catch (FormatException)
                            {
                                //log.Error("Failed to parse date string '" + stamp.ToString() + "'");
                                throw;
                            }
                                    
                                    // can't be in the future - must be the previous year
                            // add 2 days for time zones (thanks hgfischer)
                                    if (lastModified > DateTime.Now.AddDays(2))
                                    {
                                lastModified = lastModified.AddYears(-1);
                                    }
                              }                             
                  
                              
                              
                              // name of file or dir. Extract symlink if possible
                              string name = null;
                              string linkedname = null;
                  
                              // we've got to find the starting point of the name. We
                              // do this by finding the pos of all the date/time fields, then
                              // the name - to ensure we don't get tricked up by a userid the
                              // same as the filename,for example
                              int pos = 0;
                              bool ok = true;
                              for (int i = dateTimePos; i < dateTimePos + 3; i++)
                              {
                                    pos = s.IndexOf(fields[i], pos);
                                    if (pos < 0)
                                    {
                                          ok = false;
                                          break;
                                    }
                            else {
                                pos += fields[i].Length;
                            }
                              }
                              if (ok)
                              {
                            string remainder = s.Substring(pos).Trim();
                                    if (!isLink)
                                          name = remainder;
                                    else
                                    {
                                          // symlink, try to extract it
                                          pos = remainder.IndexOf("->");
                                          if (pos <= 0)
                                          {
                                                // couldn't find symlink, give up & just assign as name
                                                name = remainder;
                                          }
                                          else
                                          {
                                                int len = 2; // Length of "->"
                                                name = remainder.Substring(0, (pos) - (0)).Trim();
                                                if (pos + len < remainder.Length)
                                                      linkedname = remainder.Substring(pos + len).Trim();
                                          }
                                    }
                              }
                              else
                              {
                                    throw new FormatException("Failed to retrieve name: " + s);
                              }
                              
                              RemoteFile file = new RemoteFile();
                              file.Filename = name;
                              file.Size = size;
                              file.LastModified = lastModified; 
                              file.Owner = owner; 
                              file.Group = group;
                              file.Permissions =  permissions;
                              file.IsDir =  isDir;
                              file.IsLink =  isLink;
                              file.LinkCount = linkCount;
                              file.Linkdest = linkedname;
                              
                              files.Add(file);
                        
                                    ////////////////
                        }
                  }
                  else
                  {
                        // Probably windows system..
                        foreach(string s in list)
                        {
                              List<string> fields = getFields(s);
                              
                              // first two fields are date time
                              DateTime lastModified = DateTime.ParseExact(fields[0] + " " + fields[1], 
                                                winformat, ParsingCulture.DateTimeFormat);
                  
                              // dir flag
                              bool isDir = false;
                              long size = 0L;
                              if (fields[2].ToUpper().Equals("<DIR>"))
                                    isDir = true;
                              else
                              {
                                    try
                                    {
                                          size = Int64.Parse(fields[2]);
                                    }
                                    catch (FormatException)
                                    {
                                          throw new FormatException("Failed to parse size: " + fields[2]);
                                    }
                              }
                  
                              // we've got to find the starting point of the name. We
                              // do this by finding the pos of all the date/time fields, then
                              // the name - to ensure we don't get tricked up by a date or dir the
                              // same as the filename, for example
                              int pos = 0;
                              bool ok = true;
                              for (int i = 0; i < 3; i++)
                              {
                                    pos = s.IndexOf(fields[i], pos);
                                    if (pos < 0)
                                    {
                                          ok = false;
                                          break;
                                    }
                            else {
                                pos += fields[i].Length;
                            }
                              }
                              if (ok)
                              {
                              
                        string name = s.Substring(pos).Trim();
                              RemoteFile file = new RemoteFile();
                              file.Filename = name;
                              file.Size = size;
                              file.LastModified = lastModified; 
                              file.Owner = String.Empty; 
                              file.Group = String.Empty;
                              file.Permissions =  String.Empty;
                              file.IsDir =  isDir;
                              file.IsLink =  false;
                              file.Linkdest = String.Empty;
                              
                              files.Add(file);
                              }
                              else
                              {
                                    throw new FormatException("Failed to retrieve name: " + s);
                              }
                        
                        }
                  
                  }
                  
                  return files;
                  
            }
            
            public static List<string> getFields(string str) {
            List<string> fields = new List<string>();
            StringBuilder field = new StringBuilder();
            
            for (int i = 0; i < str.Length; i++) {
                char ch = str[i];
                if (!Char.IsWhiteSpace(ch))
                    field.Append(ch);
                else {
                    if (field.Length > 0) {
                        fields.Add(field.ToString());
                                    field.Length = 0;

                    }
                }
            }
            // pick up last field
            if (field.Length > 0) {
                fields.Add(field.ToString());
            }
            return fields;
        }
      }
}

Generated by  Doxygen 1.6.0   Back to index