restemplate/indy/Protocols/IdFTPListTypes.pas

664 lines
21 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.6 3/23/2005 4:52:28 AM JPMugaas
Expansion with MLSD and WIN32.ea fact in MLSD directories as described by:
http://www.raidenftpd.com/kb/kb000000049.htm
This returns Win32 file attributes including some that Borland does not
support.
Rev 1.5 12/8/2004 8:35:18 AM JPMugaas
Minor class restructure to support Unisys ClearPath.
Rev 1.4 11/29/2004 2:45:30 AM JPMugaas
Support for DOS attributes (Read-Only, Archive, System, and Hidden) for use
by the Distinct32, OS/2, and Chameleon FTP list parsers.
Rev 1.3 10/26/2004 9:27:34 PM JPMugaas
Updated references.
Rev 1.2 6/27/2004 1:45:36 AM JPMugaas
Can now optionally support LastAccessTime like Smartftp's FTP Server could.
I also made the MLST listing object and parser support this as well.
Rev 1.1 6/4/2004 2:11:00 PM JPMugaas
Added an indexed read-only Facts property to the MLST List Item so you can
get information that we didn't parse elsewhere. MLST is extremely flexible.
Rev 1.0 4/20/2004 2:43:20 AM JPMugaas
Abstract FTPList objects for reuse.
}
unit IdFTPListTypes;
interface
{$i IdCompilerDefines.inc}
uses
Classes,
IdGlobal,
IdFTPList;
type
{ For FTP servers using OS/2 and other MS-DOS-like file systems that report file attributes }
TIdDOSAttributes = class(TPersistent)
protected
FFileAttributes: UInt32;
function GetRead_Only: Boolean;
procedure SetRead_Only(const AValue: Boolean);
function GetHidden: Boolean;
procedure SetHidden(const AValue: Boolean);
function GetSystem: Boolean;
procedure SetSystem(const AValue: Boolean);
function GetArchive: Boolean;
procedure SetArchive(const AValue: Boolean);
function GetDirectory: Boolean;
procedure SetDirectory(const AValue: Boolean);
function GetNormal: Boolean;
procedure SetNormal(const AValue: Boolean);
public
procedure Assign(Source: TPersistent); override;
function GetAsString: String; virtual;
function AddAttribute(const AString : String) : Boolean;
published
property FileAttributes : UInt32 read FFileAttributes write FFileAttributes;
property AsString : String read GetAsString;
// can't be ReadOnly because that's a reserved word
property Read_Only : Boolean read GetRead_Only write SetRead_Only;
property Archive : Boolean read GetArchive write SetArchive;
property System : Boolean read GetSystem write SetSystem;
property Directory : Boolean read GetDirectory write SetDirectory;
property Hidden : Boolean read GetHidden write SetHidden;
property Normal : Boolean read GetNormal write SetNormal;
end;
{ Win32 Extended Attributes as in WIN32_FIND_DATA data structure in the Windows API.
Analagous to the System.IO.FileAttributes enumeration in .Net }
TIdWin32ea = class(TIdDOSAttributes)
protected
function GetDevice: Boolean;
procedure SetDevice(const AValue: Boolean);
function GetTemporary: Boolean;
procedure SetTemporary(const AValue: Boolean);
function GetSparseFile: Boolean;
procedure SetSparseFile(const AValue: Boolean);
// this is also called a junction and it works like a Unix Symbolic link to a dir
function GetReparsePoint: Boolean;
procedure SetReparsePoint(const AValue: Boolean);
function GetCompressed: Boolean;
procedure SetCompressed(const AValue: Boolean);
function GetOffline: Boolean;
procedure SetOffline(const AValue: Boolean);
function GetNotContextIndexed: Boolean;
procedure SetNotContextIndexed(const AValue: Boolean);
function GetEncrypted: Boolean;
procedure SetEncrypted(const AValue: Boolean);
public
function GetAsString: String; override;
published
property Device : Boolean read GetDevice write SetDevice;
property Temporary : Boolean read GetTemporary write SetTemporary;
property SparseFile : Boolean read GetSparseFile write SetSparseFile;
property ReparsePoint : Boolean read GetReparsePoint write SetReparsePoint;
property Compressed : Boolean read GetCompressed write SetCompressed;
property Offline : Boolean read GetOffline write SetOffline;
property NotContextIndexed : Boolean read GetNotContextIndexed write SetNotContextIndexed;
property Encrypted : Boolean read GetEncrypted write SetEncrypted;
end;
//For NLST and Cisco IOS
TIdMinimalFTPListItem = class(TIdFTPListItem)
public
constructor Create(AOwner: TCollection); override;
end;
//This is for some mainframe items which are based on records
TIdRecFTPListItem = class(TIdFTPListItem)
protected
//These are for VM/CMS which uses a record type of file system
FRecLength : Integer;
FRecFormat : String;
FNumberRecs : Integer;
property RecLength : Integer read FRecLength write FRecLength;
property RecFormat : String read FRecFormat write FRecFormat;
property NumberRecs : Integer read FNumberRecs write FNumberRecs;
end;
{ listing formats that include Creation timestamp information }
TIdCreationDateFTPListItem = class(TIdFTPListItem)
protected
FCreationDate: TDateTime;
public
constructor Create(AOwner: TCollection); override;
property CreationDate: TDateTime read FCreationDate write FCreationDate;
end;
// for MLST, MLSD listing outputs
TIdMLSTFTPListItem = class(TIdCreationDateFTPListItem)
protected
FAttributesAvail : Boolean;
FAttributes : TIdWin32ea;
FCreationDateGMT : TDateTime;
FLastAccessDate: TDateTime;
FLastAccessDateGMT : TDateTime;
FLinkedItemName : String;
//Unique ID for an item to prevent yourself from downloading something twice
FUniqueID : String;
//MLIST things
FMLISTPermissions : String;
function GetFact(const AName : String) : String;
public
constructor Create(AOwner: TCollection); override;
destructor Destroy; override;
//Creation time values are for MLSD data output and can be returned by the
//the MLSD parser in some cases
property ModifiedDateGMT;
property CreationDateGMT : TDateTime read FCreationDateGMT write FCreationDateGMT;
property LastAccessDate: TDateTime read FLastAccessDate write FLastAccessDate;
property LastAccessDateGMT : TDateTime read FLastAccessDateGMT write FLastAccessDateGMT;
//Valid only with EPLF and MLST
property UniqueID : string read FUniqueID write FUniqueID;
//MLIST Permissions
property MLISTPermissions : string read FMLISTPermissions write FMLISTPermissions;
property Facts[const Name: string] : string read GetFact;
property AttributesAvail : Boolean read FAttributesAvail write FAttributesAvail;
property Attributes : TIdWin32ea read FAttributes;
property LinkedItemName : String read FLinkedItemName write FLinkedItemName;
end;
//for some parsers that output an owner sometimes
TIdOwnerFTPListItem = class(TIdFTPListItem)
protected
FOwnerName : String;
public
property OwnerName : String read FOwnerName write FOwnerName;
end;
{ This class type is used by Novell Netware, Novell Print Services for
Unix with DOS namespace, and HellSoft FTPD for Novell Netware }
TIdNovellBaseFTPListItem = class(TIdOwnerFTPListItem)
protected
FNovellPermissions : String;
public
property NovellPermissions : string read FNovellPermissions write FNovellPermissions;
end;
//Bull GCOS 8 uses this and Unix will use a descendent
TIdUnixPermFTPListItem = class(TIdOwnerFTPListItem)
protected
FUnixGroupPermissions: string;
FUnixOwnerPermissions: string;
FUnixOtherPermissions: string;
public
property UnixOwnerPermissions: string read FUnixOwnerPermissions write FUnixOwnerPermissions;
property UnixGroupPermissions: string read FUnixGroupPermissions write FUnixGroupPermissions;
property UnixOtherPermissions: string read FUnixOtherPermissions write FUnixOtherPermissions;
end;
// Unix and Novell Netware Print Services for Unix with NFS namespace need to use this
TIdUnixBaseFTPListItem = class(TIdUnixPermFTPListItem)
protected
FLinkCount: Integer;
FGroupName: string;
FLinkedItemName : string;
public
property LinkCount: Integer read FLinkCount write FLinkCount;
property GroupName: string read FGroupName write FGroupName;
property LinkedItemName : string read FLinkedItemName write FLinkedItemName;
end;
TIdDOSBaseFTPListItem = class(TIdFTPListItem)
protected
FAttributes : TIdDOSAttributes;
procedure SetAttributes(AAttributes : TIdDOSAttributes);
public
constructor Create(AOwner: TCollection); override;
destructor Destroy; override;
property Attributes : TIdDOSAttributes read FAttributes write SetAttributes;
end;
{These are needed for interpretting Win32.ea in some MLSD output}
const
IdFILE_ATTRIBUTE_READONLY = $00000001;
IdFILE_ATTRIBUTE_HIDDEN = $00000002;
IdFILE_ATTRIBUTE_SYSTEM = $00000004;
IdFILE_ATTRIBUTE_DIRECTORY = $00000010;
IdFILE_ATTRIBUTE_ARCHIVE = $00000020;
IdFILE_ATTRIBUTE_DEVICE = $00000040;
IdFILE_ATTRIBUTE_NORMAL = $00000080;
IdFILE_ATTRIBUTE_TEMPORARY = $00000100;
IdFILE_ATTRIBUTE_SPARSE_FILE = $00000200;
IdFILE_ATTRIBUTE_REPARSE_POINT = $00000400;
IdFILE_ATTRIBUTE_COMPRESSED = $00000800;
IdFILE_ATTRIBUTE_OFFLINE = $00001000;
IdFILE_ATTRIBUTE_NOT_CONTENT_INDEXED = $00002000;
IdFILE_ATTRIBUTE_ENCRYPTED = $00004000;
implementation
uses
IdException,
IdFTPCommon, SysUtils;
{ TIdMinimalFTPListItem }
constructor TIdMinimalFTPListItem.Create(AOwner: TCollection);
begin
inherited Create(AOwner);
FSizeAvail := False;
FModifiedAvail := False;
end;
{ TIdMLSTFTPListItem }
constructor TIdMLSTFTPListItem.Create(AOwner: TCollection);
begin
inherited Create(AOwner);
FAttributesAvail := False;
FAttributes := TIdWin32ea.Create;
end;
destructor TIdMLSTFTPListItem.Destroy;
begin
FreeAndNil(FAttributes);
inherited Destroy;
end;
function TIdMLSTFTPListItem.GetFact(const AName: String): String;
var
LFacts : TStrings;
begin
LFacts := TStringList.Create;
try
ParseFacts(Data, LFacts);
Result := LFacts.Values[AName];
finally
FreeAndNil(LFacts);
end;
end;
{ TIdDOSBaseFTPListItem }
constructor TIdDOSBaseFTPListItem.Create(AOwner: TCollection);
begin
inherited Create(AOwner);
FAttributes := TIdDOSAttributes.Create;
end;
destructor TIdDOSBaseFTPListItem.Destroy;
begin
FreeAndNil(FAttributes);
inherited Destroy;
end;
procedure TIdDOSBaseFTPListItem.SetAttributes(
AAttributes: TIdDOSAttributes);
begin
FAttributes.Assign(AAttributes);
end;
{ TIdDOSAttributes }
function TIdDOSAttributes.AddAttribute(const AString: String): Boolean;
var
i : Integer;
S: String;
begin
S := UpperCase(AString);
for i := 1 to Length(S) do begin
case CharPosInSet(S, i, 'RASHW-D') of
//R
1 : Read_Only := True;
//A
2 : Archive := True;
//S
3 : System := True;
//H
4 : Hidden := True;
//W - W was added only for Distinct32's FTP server which reports 'w' if you
//write instead of a r for read-only
5 : Read_Only := False;
6,7 : ;//for the "-" and "d" that Distinct32 may give
else
begin
Result := False; //failure
Exit;
end;
end;
end;
Result := True;
end;
procedure TIdDOSAttributes.Assign(Source: TPersistent);
begin
if Source is TIdDOSAttributes then begin
FFileAttributes := (Source as TIdDOSAttributes).FFileAttributes;
end else begin
inherited Assign(Source);
end;
end;
function TIdDOSAttributes.GetAsString: String;
//This is just a handy thing for some programs to try
//to output attribute bits similarly to the DOS
//ATTRIB command
//
//which is like this:
//
// R C:\File
//A SH C:\File
{$IFDEF STRING_IS_IMMUTABLE}
var
LSB: TIdStringBuilder;
{$ENDIF}
begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(' ');
{$ELSE}
Result := ' ';
{$ENDIF}
if Archive then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[0]{$ELSE}Result[1]{$ENDIF} := 'A'; {do not localize}
end;
if System then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[3]{$ELSE}Result[4]{$ENDIF} := 'S'; {do not localize}
end;
if Hidden then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[4]{$ELSE}Result[5]{$ENDIF} := 'H'; {do not localize}
end;
if Read_Only then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[5]{$ELSE}Result[6]{$ENDIF} := 'R'; {do not localize}
end;
{$IFDEF STRING_IS_IMMUTABLE}
Result := LSB.ToString;
{$ENDIF}
end;
function TIdDOSAttributes.GetRead_Only: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_READONLY) > 0;
end;
function TIdDOSAttributes.GetHidden: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_HIDDEN) > 0;
end;
function TIdDOSAttributes.GetSystem: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_SYSTEM) > 0;
end;
function TIdDOSAttributes.GetDirectory: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_DIRECTORY) > 0;
end;
function TIdDOSAttributes.GetArchive: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_ARCHIVE) > 0;
end;
function TIdDOSAttributes.GetNormal: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_NORMAL) > 0;
end;
procedure TIdDOSAttributes.SetRead_Only(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_READONLY;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_READONLY);
end;
end;
procedure TIdDOSAttributes.SetHidden(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_HIDDEN;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_HIDDEN);
end;
end;
procedure TIdDOSAttributes.SetSystem(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_SYSTEM;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_SYSTEM);
end;
end;
procedure TIdDOSAttributes.SetDirectory(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_DIRECTORY;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_DIRECTORY);
end;
end;
procedure TIdDOSAttributes.SetArchive(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_ARCHIVE;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_ARCHIVE);
end;
end;
procedure TIdDOSAttributes.SetNormal(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_NORMAL;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_NORMAL);
end;
end;
{ TIdCreationDateFTPListItem }
constructor TIdCreationDateFTPListItem.Create(AOwner: TCollection);
begin
inherited Create(AOwner);
SizeAvail := False;
ModifiedAvail := False;
end;
{ TIdWin32ea }
function TIdWin32ea.GetDevice: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_DEVICE) > 0;
end;
function TIdWin32ea.GetTemporary: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_TEMPORARY) > 0;
end;
function TIdWin32ea.GetSparseFile: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_SPARSE_FILE) > 0;
end;
function TIdWin32ea.GetReparsePoint: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_REPARSE_POINT) > 0;
end;
function TIdWin32ea.GetCompressed: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_COMPRESSED) > 0;
end;
function TIdWin32ea.GetOffline: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_OFFLINE) > 0;
end;
function TIdWin32ea.GetNotContextIndexed: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_NOT_CONTENT_INDEXED) > 0;
end;
function TIdWin32ea.GetEncrypted: Boolean;
begin
Result := (FFileAttributes and IdFILE_ATTRIBUTE_ENCRYPTED) > 0;
end;
procedure TIdWin32ea.SetDevice(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_DEVICE;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_DEVICE);
end;
end;
procedure TIdWin32ea.SetTemporary(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_TEMPORARY;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_TEMPORARY);
end;
end;
procedure TIdWin32ea.SetSparseFile(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_SPARSE_FILE;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_SPARSE_FILE);
end;
end;
procedure TIdWin32ea.SetReparsePoint(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_NORMAL;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_NORMAL);
end;
end;
procedure TIdWin32ea.SetCompressed(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_NORMAL;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_NORMAL);
end;
end;
procedure TIdWin32ea.SetOffline(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_OFFLINE;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_OFFLINE);
end;
end;
procedure TIdWin32ea.SetNotContextIndexed(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
end;
end;
procedure TIdWin32ea.SetEncrypted(const AValue: Boolean);
begin
if AValue then begin
FFileAttributes := FFileAttributes or IdFILE_ATTRIBUTE_ENCRYPTED;
end else begin
FFileAttributes := FFileAttributes and (not IdFILE_ATTRIBUTE_ENCRYPTED);
end;
end;
function TIdWin32ea.GetAsString: String;
//we'll do this similarly to 4NT
//which renders the bits like this order:
//RHSADENTJPCOI
{$IFDEF STRING_IS_IMMUTABLE}
var
LSB: TIdStringBuilder;
{$ENDIF}
begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(' ');
{$ELSE}
Result := ' ';
{$ENDIF}
if Read_Only then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[0]{$ELSE}Result[1]{$ENDIF} := 'R'; {do not localize}
end;
if Hidden then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[1]{$ELSE}Result[2]{$ENDIF} := 'H'; {do not localize}
end;
if System then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[2]{$ELSE}Result[3]{$ENDIF} := 'S'; {do not localize}
end;
if Archive then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[3]{$ELSE}Result[4]{$ENDIF} := 'A'; {do not localize}
end;
if Directory then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[4]{$ELSE}Result[5]{$ENDIF} := 'D'; {do not localize}
end;
if Encrypted then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[5]{$ELSE}Result[6]{$ENDIF} := 'E'; {do not localize}
end;
if Normal then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[6]{$ELSE}Result[7]{$ENDIF} := 'N'; {do not localize}
end;
if Temporary then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[7]{$ELSE}Result[8]{$ENDIF} := 'T'; {do not localize}
end;
if ReparsePoint then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[8]{$ELSE}Result[9]{$ENDIF} := 'J'; {do not localize}
end;
if SparseFile then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[9]{$ELSE}Result[10]{$ENDIF} := 'P'; {do not localize}
end;
if Compressed then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[10]{$ELSE}Result[11]{$ENDIF} := 'C'; {do not localize}
end;
if Offline then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[11]{$ELSE}Result[12]{$ENDIF} := 'O'; {do not localize}
end;
if NotContextIndexed then begin
{$IFDEF STRING_IS_IMMUTABLE}LSB[12]{$ELSE}Result[13]{$ENDIF} := 'I'; {do not localize}
end;
{$IFDEF STRING_IS_IMMUTABLE}
Result := LSB.ToString;
{$ENDIF}
end;
end.