// edtFTPnet
//
// Copyright (C) 2004 Enterprise Distributed Technologies Ltd
//
// www.enterprisedt.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Bug fixes, suggestions and comments should posted on
// http://www.enterprisedt.com/forums/index.php
//
// Change Log:
//
// $Log: FTPFileFactory.cs,v $
// Revision 1.21 2009-06-22 09:07:43 bruceb
// bug fix re disconnect/reconnect
//
// Revision 1.20 2008-12-02 07:47:34 bruceb
// parser tweaks
//
// Revision 1.19 2008-07-15 05:42:57 bruceb
// refactor parsing code
//
// Revision 1.18 2007-11-12 05:20:38 bruceb
// fix bugs whereby explicitly set parsers weren't used
//
// Revision 1.17 2007-06-26 01:36:32 bruceb
// CF changes
//
// Revision 1.16 2007-06-20 08:45:17 hans
// Made sure TimeIncludesSeconds getter doesn't throw an exception if parser is null.
//
// Revision 1.15 2007-05-23 00:28:32 hans
// Added TimeDifference and TimeIncludesSeconds properties.
//
// Revision 1.14 2007-03-16 04:57:49 bruceb
// VMSParser property
//
// Revision 1.13 2007/02/02 01:44:03 bruceb
// OS400 changes + use of RestartParsingException
//
// Revision 1.12 2006/11/17 15:38:42 bruceb
// rename Logger to string
//
// Revision 1.11 2006/07/12 08:24:46 bruceb
// added debug
//
// Revision 1.10 2006/06/14 10:08:21 bruceb
// VMS fixes
//
// Revision 1.9 2005/08/04 21:57:35 bruceb
// throw change
//
// Revision 1.8 2005/06/10 15:47:51 bruceb
// more vms tweaks
//
// Revision 1.7 2005/06/03 11:32:47 bruceb
// vms changes
//
// Revision 1.6 2005/02/07 17:19:34 bruceb
// support for setting the CultureInfo
//
// Revision 1.5 2004/12/22 22:41:50 bruceb
// made methods public
//
// Revision 1.4 2004/11/05 20:00:28 bruceb
// cleaned up namespaces
//
// Revision 1.3 2004/10/29 09:41:44 bruceb
// removed /// in file header
//
//
//
using System;
using System.Globalization;
using System.Text;
using System.ComponentModel;
using System.Collections;
using LoggerEnterpriseDT.Util.Debug.Logger;
namespace EnterpriseDT.Net.Ftp{
/// <summary>
/// Factory for creating FTPFile objects
/// </summary>
/// <author> Bruce Blackshaw
/// </author>
/// <version> $Revision: 1.21 $
/// </version>
public class FTPFileFactory
{
/// <summary>
/// Get/set the culture info for parsing
/// </summary>
public CultureInfo ParsingCulture
{
get
{
return parserCulture;
}
set
{
this.parserCulture = value;
windows.ParsingCulture = value;
unix.ParsingCulture = value;
vms.ParsingCulture = value;
os400.ParsingCulture = value;
if (parser != null)
parser.ParsingCulture = value;
}
}
/// <summary> Logging object</summary>
private Logger log = Logger.GetLogger("FTPFileFactory");
/// <summary> Windows server comparison string</summary>
internal const string WINDOWS_STR = "WINDOWS";
/// <summary> UNIX server comparison string</summary>
internal const string UNIX_STR = "UNIX";
/// <summary> VMS server comparison string</summary>
internal const string VMS_STR = "VMS";
/// <summary> OS/400 server comparison string</summary>
internal const string OS400_STR = "OS/400";
/// <summary> SYST string</summary>
private string system;
/// <summary> Cached windows parser</summary>
private WindowsFileParser windows = new WindowsFileParser();
/// <summary> Cached unix parser</summary>
private UnixFileParser unix = new UnixFileParser();
/// <summary> Cached unix parser</summary>
private VMSFileParser vms = new VMSFileParser();
/// <summary> Cached OS400 parser</summary>
private OS400FileParser os400 = new OS400FileParser();
/// <summary> Does the parsing work</summary>
private FTPFileParser parser = null;
/// <summary>
/// List of the parsers
/// </summary>
private ArrayList parsers = new ArrayList();
/// <summary>
/// Did the user set the parser?
/// </summary>
private bool userSetParser = false;
/// <summary>
/// Has the parser been detected?
/// </summary>
private bool parserDetected = false;
/// <summary>Culture used for parsing file details</summary>
private CultureInfo parserCulture = CultureInfo.InvariantCulture;
/// <summary>Time difference between server and client (relative to client).</summary>
protected TimeSpan timeDiff = new TimeSpan();
/// <summary>
/// Constructor
/// </summary>
/// <param name="system"> SYST string
/// </param>
public FTPFileFactory(string system)
{
InitializeParsers();
SetParser(system);
}
/// <summary> Constructor. User supplied parser. Note that parser
/// detection is disabled if a parser is explicitly supplied
/// </summary>
/// <param name="parser"> the parser to use
/// </param>
public FTPFileFactory(FTPFileParser parser)
{
InitializeParsers();
this.parser = parser;
}
private void InitializeParsers()
{
parsers.Add(unix);
parsers.Add(windows);
parsers.Add(os400);
parsers.Add(vms);
parser = unix;
}
/// <summary> Default constructor. No parsers are set.
/// </summary>
public FTPFileFactory()
{
InitializeParsers();
}
/// <summary>
/// Rather than forcing a parser (as in the constructor that accepts
/// a parser), this adds a parser to the list of those used.
/// </summary>
/// <param name="parser">parser to add to list being used</param>
public void AddParser(FTPFileParser parser)
{
parsers.Add(parser);
}
/// <summary>
/// Was the parser set explicitly, or was it worked out
/// via the SYST command>
/// </summary>
public bool ParserSetExplicitly
{
get { return userSetParser; }
}
/// <summary>
/// Get or set the file parser to be used. If it is
/// set explicitly, it is never rotated.
/// </summary>
[DefaultValue(null)]
public FTPFileParser FileParser
{
get
{
return this.parser;
}
set
{
this.parser = value;
if (value != null)
{
userSetParser = true;
}
else // reset back to how it was
{
userSetParser = false;
SetParser(system);
}
}
}
/// <summary>
/// Get the instance of the VMS parser
/// </summary>
public VMSFileParser VMSParser
{
get
{
return vms;
}
}
/// <summary>
/// [FTP/FTPS Only] Time difference between server and client (relative to client).
/// </summary>
/// <remarks>
/// The time-difference is relative to the server such that, for example, if the server is
/// in New York and the client is in London then the difference would be -5 hours
/// (ignoring daylight savings differences). This property only applies to FTP and FTPS.
/// </remarks>
public TimeSpan TimeDifference
{
get { return timeDiff; }
set { timeDiff = value; }
}
/// <summary>
/// Get flag indicating whether or not the most recent parse returned seconds.
/// </summary>
public bool TimeIncludesSeconds
{
get { return parser!=null && parser.TimeIncludesSeconds; }
}
/// <summary>
/// Set the remote server type
/// </summary>
/// <param name="system">SYST string</param>
public void SetParser(string system)
{
parserDetected = false;
this.system = system != null ? system.Trim() : null;
if (system != null)
{
if (system.ToUpper().StartsWith(WINDOWS_STR))
{
log.Debug("Selected Windows parser");
parser = windows;
}
else if (system.ToUpper().IndexOf(UNIX_STR) >= 0)
{
log.Debug("Selected UNIX parser");
parser = unix;
}
else if (system.ToUpper().IndexOf(VMS_STR) >= 0)
{
log.Debug("Selected VMS parser");
parser = vms;
}
else if (system.ToUpper().IndexOf(OS400_STR) >= 0)
{
log.Debug("Selected OS/400 parser");
parser = os400;
}
else
{
parser = unix;
log.Warn("Unknown SYST '" + system + "' - defaulting to Unix parsing");
}
}
else
{
parser = unix;
log.Debug("Defaulting to Unix parsing");
}
}
/// <summary>
/// Detect the parser format to use
/// </summary>
/// <param name="files"></param>
private void DetectParser(string[] files)
{
// use the initially set parser (from SYST)
if (parser.IsValidFormat(files))
{
log.Debug("Confirmed format " + parser.ToString());
parserDetected = true;
return;
}
IEnumerator i = parsers.GetEnumerator();
while (i.MoveNext())
{
FTPFileParser p = (FTPFileParser)i.Current;
if (p.IsValidFormat(files))
{
parser = p;
log.Debug("Detected format " + parser.ToString());
parserDetected = true;
return;
}
}
parser = unix;
log.Warn("Could not detect format. Using default " + parser.ToString());
}
/// <summary>
/// Parse an array of raw file information returned from the
/// FTP server
/// </summary>
/// <param name="fileStrings"> array of strings
/// </param>
/// <returns> array of FTPFile objects
/// </returns>
public virtual FTPFile[] Parse(string[] fileStrings)
{
log.Debug("Parse() called using culture: " + parserCulture.EnglishName);
FTPFile[] files = new FTPFile[fileStrings.Length];
// quick check if no files returned
if (fileStrings.Length == 0)
return files;
if (!userSetParser && !parserDetected)
DetectParser(fileStrings);
int count = 0;
for (int i = 0; i < fileStrings.Length; i++)
{
if (fileStrings[i] == null || fileStrings[i].Trim().Length == 0)
continue;
try
{
FTPFile file = null;
if (parser.IsMultiLine())
{
// vms uses more than 1 line for some file listings. We must keep going
// thru till we've got everything
StringBuilder filename = new StringBuilder(fileStrings[i]);
while (i+1 < fileStrings.Length && fileStrings[i+1].IndexOf(';') < 0)
{
filename.Append(" ").Append(fileStrings[i+1]);
i++;
}
file = parser.Parse(filename.ToString());
}
else
{
file = parser.Parse(fileStrings[i]);
}
// we skip null returns - these are duff lines we know about and don't
// really want to throw an exception
if (file != null)
{
if (timeDiff.Ticks != 0)
file.ApplyTimeDifference(timeDiff);
files[count++] = file;
}
}
catch (RestartParsingException)
{
log.Debug("Restarting parsing from first entry in list");
i = -1;
count = 0;
continue;
}
}
FTPFile[] result = new FTPFile[count];
Array.Copy(files, 0, result, 0, count);
return result;
}
/// <summary>
/// Get the SYST string
/// </summary>
/// <returns> the system string.
/// </returns>
[Obsolete("Use the System property.")]
public string GetSystem()
{
return system;
}
/// <summary>
/// Get or set the system string (typically the string
/// returned from the SYST command).
/// </summary>
[DefaultValue(null)]
public string System
{
get
{
return system;
}
set
{
SetParser(value);
}
}
}
}
|