703 lines
21 KiB
Plaintext
703 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.1 2/23/2005 6:34:26 PM JPMugaas
|
|||
|
New property for displaying permissions ina GUI column. Note that this
|
|||
|
should not be used like a CHMOD because permissions are different on
|
|||
|
different platforms - you have been warned.
|
|||
|
|
|||
|
Rev 1.0 11/24/2004 12:17:00 PM JPMugaas
|
|||
|
New parser for Stratus VOS. This will work with:
|
|||
|
}
|
|||
|
|
|||
|
unit IdFTPListParseStratusVOS;
|
|||
|
|
|||
|
{
|
|||
|
FTP server (FTP 1.0 for Stratus STCP)
|
|||
|
FTP server (OS TCP/IP)
|
|||
|
}
|
|||
|
|
|||
|
interface
|
|||
|
|
|||
|
{$i IdCompilerDefines.inc}
|
|||
|
|
|||
|
uses
|
|||
|
Classes,
|
|||
|
IdFTPList, IdFTPListParseBase, IdFTPListTypes;
|
|||
|
|
|||
|
type
|
|||
|
TIdStratusVOSFTPListItem = class(TIdFTPListItem)
|
|||
|
protected
|
|||
|
FAccess : String;
|
|||
|
FNumberBlocks : Integer;
|
|||
|
FBlockSize : Integer;
|
|||
|
FFileFormat : String;
|
|||
|
FLinkedItemName : string;
|
|||
|
public
|
|||
|
property Access : String read FAccess write FAccess;
|
|||
|
property NumberBlocks : Integer read FNumberBlocks write FNumberBlocks;
|
|||
|
property BlockSize : Integer read FBlockSize write FBlockSize;
|
|||
|
property FileFormat : String read FFileFormat write FFileFormat;
|
|||
|
//This results will look odd for symbolic links
|
|||
|
//Don't panic!!!
|
|||
|
//
|
|||
|
//Stratus VOS has an unusual path syntax such as:
|
|||
|
//
|
|||
|
//%phx_cac#m2_user>Stratus>Charles_Spitzer>junque>_edit.vterm1.1
|
|||
|
//
|
|||
|
//where the > is a path separator
|
|||
|
property LinkedItemName : string read FLinkedItemName write FLinkedItemName;
|
|||
|
end;
|
|||
|
|
|||
|
TIdFTPLPStratusVOS = class(TIdFTPListBase)
|
|||
|
protected
|
|||
|
class function IsValidFileEntry(const ALine : String) : Boolean;
|
|||
|
class function IsValidDirEntry(const ALine : String): Boolean;
|
|||
|
class function IsFilesHeader(const ALine : String): Boolean;
|
|||
|
class function IsDirsHeader(const ALine : String): Boolean;
|
|||
|
class function IsLinksHeader(const ALine : String): Boolean;
|
|||
|
class function MakeNewItem(AOwner : TIdFTPListItems) : TIdFTPListItem; override;
|
|||
|
class function ParseDirEntry(const AItem: TIdFTPListItem): Boolean;
|
|||
|
class function ParseFileEntry(const AItem : TIdFTPListItem): Boolean;
|
|||
|
class function ParseLinkEntry(const AItem : TIdFTPListItem): Boolean;
|
|||
|
class function ParseLine(const AItem : TIdFTPListItem; const APath : String = ''): Boolean; override;
|
|||
|
public
|
|||
|
class function GetIdent : String; override;
|
|||
|
class function CheckListing(AListing : TStrings; const ASysDescript : String = ''; const ADetails : Boolean = True): Boolean; override;
|
|||
|
class function ParseListing(AListing : TStrings; ADir : TIdFTPListItems) : Boolean; override;
|
|||
|
end;
|
|||
|
|
|||
|
// RLebeau 2/14/09: this forces C++Builder to link to this unit so
|
|||
|
// RegisterFTPListParser can be called correctly at program startup...
|
|||
|
|
|||
|
{$IFDEF HAS_DIRECTIVE_HPPEMIT_LINKUNIT}
|
|||
|
{$HPPEMIT LINKUNIT}
|
|||
|
{$ELSE}
|
|||
|
{$HPPEMIT '#pragma link "IdFTPListParseStratusVOS"'}
|
|||
|
{$ENDIF}
|
|||
|
|
|||
|
implementation
|
|||
|
|
|||
|
{
|
|||
|
From: Manual Name: VOS Reference Manual
|
|||
|
|
|||
|
Part Number: R002
|
|||
|
|
|||
|
Revision Number: 01
|
|||
|
|
|||
|
Printing Date: April 1990
|
|||
|
|
|||
|
Stratus Computer, Inc.
|
|||
|
|
|||
|
|
|||
|
Path Names
|
|||
|
|
|||
|
The most important function of the directory hierarchy is to provide
|
|||
|
a way to uniquely but conveniently name any object in the I/O
|
|||
|
system. Any user on any processing module or system that can
|
|||
|
communicate with the module containing the object can then refer to
|
|||
|
the object.
|
|||
|
|
|||
|
The unique name of an object is derived from the object's unique
|
|||
|
path in the I/O system. The unique name is called the path name of
|
|||
|
the object. A path name is constructed from the name of the object,
|
|||
|
the names of the directories in the path leading to the object, and
|
|||
|
the name of the system containing the root parent directory.
|
|||
|
|
|||
|
The path name of a file or directory is a combination of the
|
|||
|
following names:
|
|||
|
|
|||
|
1. the name of the system containing the object preceded by a
|
|||
|
percent sign (%).
|
|||
|
2. the name of the disk containing the object preceded by a number
|
|||
|
sign (#)
|
|||
|
3. the names of the directories in the path of the object, in order, each preceded by the greater-than sign (>)
|
|||
|
|
|||
|
4. the name of the object preceded by the greater-than sign (>).
|
|||
|
|
|||
|
The symbol > is used to separate directories and files in the path
|
|||
|
name. Its use is similar to the use of / or \ in other operating
|
|||
|
systems.
|
|||
|
|
|||
|
For example, suppose you have a system named %s containing a disk
|
|||
|
named #d01. (The module containing the disk is %s#m1.) The following
|
|||
|
is an example of a full path name for the file named this_week.
|
|||
|
|
|||
|
%s#d01>Administration>Jones>reports>this_week
|
|||
|
|
|||
|
|
|||
|
The file is immediately contained in the directory reports, which is
|
|||
|
subordinate to the directory Jones. The home directory Jones is a
|
|||
|
subdirectory of the group directory Administration which is a
|
|||
|
subdirectory of the disk #d01.
|
|||
|
Relative Path Names
|
|||
|
|
|||
|
The path names defined so far are full path names. The full path
|
|||
|
name of an object is unique because the path of an object is unique.
|
|||
|
The operating system can also interpret relative path names. A
|
|||
|
relative path name is a combination of object names and pecial
|
|||
|
symbols, like a full path name, that identifies an object in the
|
|||
|
directory hierarchy. A relative path name of the object generally
|
|||
|
does not contain all the directory names that are in the full path
|
|||
|
name. When you use a relative path name, the operating system
|
|||
|
determines the missing information about the object's location rom
|
|||
|
the location of the current directory.
|
|||
|
|
|||
|
If the operating system reads a string that it expects to be a path
|
|||
|
name and the leading character is not a percent sign, it interprets
|
|||
|
the string as a relative path name.
|
|||
|
|
|||
|
The single character < can be used to refer to the parent directory
|
|||
|
of the current directory. For example, the command
|
|||
|
change_current_dir < moves you up one directory in the directory
|
|||
|
hierarchy. A single period (.) also refers to the current directory
|
|||
|
and two periods (..) refers to the parent directory. Thus,
|
|||
|
change_current_dir .. is the same as the change_current_dir <.
|
|||
|
}
|
|||
|
|
|||
|
uses
|
|||
|
IdFTPCommon, IdGlobal, IdGlobalProtocols, SysUtils;
|
|||
|
|
|||
|
{ TIdFTPLPStratusVOS }
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.CheckListing(AListing: TStrings;
|
|||
|
const ASysDescript: String; const ADetails: Boolean): Boolean;
|
|||
|
var
|
|||
|
i : Integer;
|
|||
|
LMode : TIdDirItemType;
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
LMode := ditFile;
|
|||
|
for i := 0 to AListing.Count - 1 do
|
|||
|
begin
|
|||
|
if AListing[i] <> '' then
|
|||
|
begin
|
|||
|
if IsFilesHeader(AListing[i]) then begin
|
|||
|
LMode := ditFile;
|
|||
|
end
|
|||
|
else if IsDirsHeader(AListing[i]) then begin
|
|||
|
LMode := ditDirectory;
|
|||
|
end
|
|||
|
else if IsLinksHeader(AListing[i]) then begin
|
|||
|
LMode := ditSymbolicLink;
|
|||
|
end else
|
|||
|
begin
|
|||
|
case LMode of
|
|||
|
ditFile :
|
|||
|
begin
|
|||
|
if not IsValidFileEntry(AListing[i]) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
ditDirectory :
|
|||
|
begin
|
|||
|
if not IsValidDirEntry(AListing[i]) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
Result := True;
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.GetIdent: String;
|
|||
|
begin
|
|||
|
Result := 'Stratus VOS'; {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.IsDirsHeader(const ALine: String): Boolean;
|
|||
|
begin
|
|||
|
{ Dirs: 0 }
|
|||
|
Result := TextStartsWith(ALine, 'Dirs: '); {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.IsFilesHeader(const ALine: String): Boolean;
|
|||
|
begin
|
|||
|
{ Files: 4 Blocks: 609 }
|
|||
|
Result := TextStartsWith(ALine, 'Files: ') and (IndyPos('Blocks: ', ALine) > 8); {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.IsLinksHeader(const ALine: String): Boolean;
|
|||
|
begin
|
|||
|
{ Links: 0 }
|
|||
|
Result := TextStartsWith(ALine, 'Links: '); {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.IsValidDirEntry(const ALine: String): Boolean;
|
|||
|
var
|
|||
|
s, s2 : String;
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
s := ALine;
|
|||
|
//a listing may start of with one space
|
|||
|
//permissions
|
|||
|
if TextStartsWith(s, ' ') then begin {do not localize}
|
|||
|
IdDelete(s, 1, 1);
|
|||
|
end;
|
|||
|
if Length(Fetch(s)) <> 1 then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
s := TrimLeft(s);
|
|||
|
//block count
|
|||
|
if not IsNumeric(Fetch(s)) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
s := TrimLeft(s);
|
|||
|
s2 := Fetch(s);
|
|||
|
//date
|
|||
|
if not IsYYYYMMDD(s2) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
s := TrimLeft(s);
|
|||
|
s2 := Fetch(s);
|
|||
|
//time
|
|||
|
Result := IsHHMMSS(s2, ':'); {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.IsValidFileEntry(const ALine: String): Boolean;
|
|||
|
var
|
|||
|
s, s2 : String;
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
s := ALine;
|
|||
|
//a listing may start of with one space
|
|||
|
if TextStartsWith(s, ' ') then begin {do not localize}
|
|||
|
IdDelete(s, 1, 1);
|
|||
|
end;
|
|||
|
if Length(Fetch(s)) <> 1 then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
s := TrimLeft(s);
|
|||
|
if not IsNumeric(Fetch(s)) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
s := TrimLeft(s);
|
|||
|
s2 := Fetch(s);
|
|||
|
if not IsNumeric(s2, 2) then
|
|||
|
begin
|
|||
|
s := TrimLeft(s);
|
|||
|
s2 := Fetch(s);
|
|||
|
end;
|
|||
|
if not IsYYYYMMDD(s2) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
s := TrimLeft(s);
|
|||
|
s2 := Fetch(s);
|
|||
|
Result := IsHHMMSS(s2, ':'); {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.MakeNewItem(AOwner: TIdFTPListItems): TIdFTPListItem;
|
|||
|
begin
|
|||
|
Result := TIdStratusVOSFTPListItem.Create(AOwner);
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.ParseDirEntry(const AItem: TIdFTPListItem): Boolean;
|
|||
|
var
|
|||
|
LV : TIdStratusVOSFTPListItem;
|
|||
|
LBuf, LPart : String;
|
|||
|
begin
|
|||
|
//w 158 stm 90-05-19 11:53:44 acctng.cobol
|
|||
|
{
|
|||
|
Files
|
|||
|
Access Access Description
|
|||
|
Right Code
|
|||
|
--------------------------------
|
|||
|
undefined u Denies the user all access to the file. This code
|
|||
|
occurs only if the effective access list for the
|
|||
|
file does not contain any entry applicable to the
|
|||
|
given user name.
|
|||
|
|
|||
|
nul n Denies the user all access to the file.
|
|||
|
|
|||
|
execute e Allows the user to execute a program module or
|
|||
|
command macro, but not to read, modify, or delete
|
|||
|
it.
|
|||
|
|
|||
|
read r Allows the user to read the file (or to execute
|
|||
|
it, if it is executable), but not to modify or
|
|||
|
delete it.
|
|||
|
|
|||
|
write w Gives the user full access to the contents of
|
|||
|
the file. (However, to delete or write to the
|
|||
|
file, the user must have modify access to the
|
|||
|
directory in which the file is contained.)
|
|||
|
|
|||
|
|
|||
|
Directory
|
|||
|
Access Access Description
|
|||
|
Right Code
|
|||
|
--------------------------------
|
|||
|
undefined u Denies the user all access to the directory.
|
|||
|
This code occurs only if the effective access
|
|||
|
list for the directory does not contain any
|
|||
|
entry applicable to the given user name.
|
|||
|
|
|||
|
nul n Denies the user all access to the directory.
|
|||
|
|
|||
|
status s Allows the user to list the contents of the
|
|||
|
directory and to see other status information,
|
|||
|
but not to change any of the contents.
|
|||
|
|
|||
|
modify m Gives the user full access to the contents of
|
|||
|
the directory.
|
|||
|
}
|
|||
|
Result := False;
|
|||
|
LV := AItem as TIdStratusVOSFTPListItem;
|
|||
|
LBuf := AItem.Data;
|
|||
|
if TextStartsWith(LBuf, ' ') then begin {do not localize}
|
|||
|
IdDelete(LBuf, 1, 1);
|
|||
|
end;
|
|||
|
LV.FAccess := Fetch(LBuf);
|
|||
|
if Length(LV.FAccess) <> 1 then
|
|||
|
begin
|
|||
|
//invalid
|
|||
|
LV.FAccess := '';
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
//block count
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsNumeric(LPart) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.NumberBlocks := IndyStrToInt(LPart, 0);
|
|||
|
//size
|
|||
|
LV.Size := (LV.NumberBlocks * 4096);
|
|||
|
LV.SizeAvail := True;
|
|||
|
//Note that will NOT be accurate but it's the best you can do.
|
|||
|
//date
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsYYYYMMDD(LPart) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.ModifiedDate := DateYYMMDD(LPart);
|
|||
|
//time
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsHHMMSS(LPart, ':') then begin {do not localize}
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.ModifiedDate := LV.ModifiedDate + TimeHHMMSS(LPart);
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LV.FileName := LBuf;
|
|||
|
Result := True;
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.ParseFileEntry(const AItem: TIdFTPListItem): Boolean;
|
|||
|
var
|
|||
|
LV : TIdStratusVOSFTPListItem;
|
|||
|
LBuf, LPart : String;
|
|||
|
begin
|
|||
|
//w 158 stm 90-05-19 11:53:44 acctng.cobol
|
|||
|
{
|
|||
|
Files
|
|||
|
Access Access Description
|
|||
|
Right Code
|
|||
|
--------------------------------
|
|||
|
undefined u Denies the user all access to the file. This code
|
|||
|
occurs only if the effective access list for the
|
|||
|
file does not contain any entry applicable to the
|
|||
|
given user name.
|
|||
|
|
|||
|
nul n Denies the user all access to the file.
|
|||
|
|
|||
|
execute e Allows the user to execute a program module or
|
|||
|
command macro, but not to read, modify, or delete
|
|||
|
it.
|
|||
|
|
|||
|
read r Allows the user to read the file (or to execute
|
|||
|
it, if it is executable), but not to modify or
|
|||
|
delete it.
|
|||
|
|
|||
|
write w Gives the user full access to the contents of
|
|||
|
the file. (However, to delete or write to the
|
|||
|
file, the user must have modify access to the
|
|||
|
directory in which the file is contained.)
|
|||
|
|
|||
|
|
|||
|
Directory
|
|||
|
Access Access Description
|
|||
|
Right Code
|
|||
|
--------------------------------
|
|||
|
undefined u Denies the user all access to the directory.
|
|||
|
This code occurs only if the effective access
|
|||
|
list for the directory does not contain any
|
|||
|
entry applicable to the given user name.
|
|||
|
|
|||
|
nul n Denies the user all access to the directory.
|
|||
|
|
|||
|
status s Allows the user to list the contents of the
|
|||
|
directory and to see other status information,
|
|||
|
but not to change any of the contents.
|
|||
|
|
|||
|
modify m Gives the user full access to the contents of
|
|||
|
the directory.
|
|||
|
}
|
|||
|
Result := False;
|
|||
|
LV := AItem as TIdStratusVOSFTPListItem;
|
|||
|
LBuf := AItem.Data;
|
|||
|
if TextStartsWith(LBuf, ' ') then begin {do not localize}
|
|||
|
IdDelete(LBuf, 1, 1);
|
|||
|
end;
|
|||
|
LV.FAccess := Fetch(LBuf);
|
|||
|
LV.PermissionDisplay := LV.Access;
|
|||
|
if Length(LV.FAccess) <> 1 then
|
|||
|
begin
|
|||
|
//invalid
|
|||
|
LV.FAccess := '';
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
//block count
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsNumeric(LPart) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.NumberBlocks := IndyStrToInt(LPart, 0);
|
|||
|
//file format
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LV.FileFormat := Fetch(LBuf);
|
|||
|
{
|
|||
|
Charlie Spitzer, stratus customer service, made this note in an E-Mail to me:
|
|||
|
|
|||
|
not all files can be directly calculated in size. there are different file
|
|||
|
types, each of which has a different file calculation. for example, in the
|
|||
|
above list, stm means stream, and is directly equal to a unix file. however,
|
|||
|
seq stands for sequential, and there is a 4 byte overhead per record, and no
|
|||
|
way to determine the number of records from ftp. there are other file types
|
|||
|
which you can see, rel (relative) being one of them, and the overhead is 2
|
|||
|
bytes per record, but each record doesn't have to be the same size, and
|
|||
|
again there is no way to determine the # of records.
|
|||
|
|
|||
|
READ THIS!!!
|
|||
|
|
|||
|
In a further correspondance, Charlie Spitzer did note this:
|
|||
|
|
|||
|
a block count is the number of 4096 byte blocks allocated to the file. it
|
|||
|
contains data blocks + index blocks, if any. there is no way to get a record
|
|||
|
count, and if the file is sparse (not all records of the file are written,
|
|||
|
since it's possible to write a record not at the beginning of a file), the
|
|||
|
block count may be wildly inaccurate.
|
|||
|
}
|
|||
|
LV.Size := LV.NumberBlocks;
|
|||
|
|
|||
|
{
|
|||
|
John M. Cassidy, CISSP, euroConex noted in a private E-Mail that the blocksize
|
|||
|
is 4096 bytes.
|
|||
|
|
|||
|
This will NOT be exact. That's one reason why I don't use file sizes right from
|
|||
|
a directory listing when writing FTP programs.
|
|||
|
}
|
|||
|
LV.Size := LV.NumberBlocks * 4096;
|
|||
|
|
|||
|
{
|
|||
|
Otto Newman noted this, Stratus Technologies noted this:
|
|||
|
|
|||
|
Transmit sizes are shown in terms of bytes which are blocks * 4096.
|
|||
|
}
|
|||
|
LV.SizeAvail := True;
|
|||
|
//date
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsYYYYMMDD(LPart) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.ModifiedDate := DateYYMMDD(LPart);
|
|||
|
//time
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsHHMMSS(LPart, ':') then begin {do not localize}
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.ModifiedDate := LV.ModifiedDate + TimeHHMMSS(LPart);
|
|||
|
{ From:
|
|||
|
|
|||
|
Manual Name: VOS Reference Manual
|
|||
|
|
|||
|
Part Number: R002
|
|||
|
|
|||
|
Revision Number: 01
|
|||
|
|
|||
|
Printing Date: April 1990
|
|||
|
|
|||
|
Stratus Computer, Inc.
|
|||
|
|
|||
|
55 Fairbanks Blvd.
|
|||
|
|
|||
|
Marlboro, Massachusetts 01752
|
|||
|
|
|||
|
<EFBFBD> 1990 by Stratus Computer, Inc. All rights reserved.
|
|||
|
|
|||
|
A name is an ASCII character string that contains no more than 32 characters. The characters must be chosen from the following set of 81 characters:
|
|||
|
the upper-case letters
|
|||
|
the lower-case letters
|
|||
|
the decimal digits
|
|||
|
the ASCII national use characters
|
|||
|
//@ [ \ ] ^ ` { | close-bracket ~
|
|||
|
" $ + , - . / : _
|
|||
|
}
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LV.FileName := LBuf;
|
|||
|
Result := True;
|
|||
|
//item type can't be determined here, that has to be done in the main parsing procedure
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.ParseLine(const AItem: TIdFTPListItem;
|
|||
|
const APath: String): Boolean;
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
case AItem.ItemType of
|
|||
|
DitFile : Result := ParseFileEntry(AItem);
|
|||
|
DitDirectory : Result := ParseDirEntry(AItem);
|
|||
|
ditSymbolicLink : Result := ParseLinkEntry(AItem);
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.ParseLinkEntry(const AItem: TIdFTPListItem): Boolean;
|
|||
|
var
|
|||
|
LV : TIdStratusVOSFTPListItem;
|
|||
|
LBuf, LPart : String;
|
|||
|
begin
|
|||
|
//04-07-13 21:15:43 backholding_logs -> %descc#m2_d01>l3s>db>lti>in>cp_exception
|
|||
|
Result := False;
|
|||
|
LV := AItem as TIdStratusVOSFTPListItem;
|
|||
|
LBuf := AItem.Data;
|
|||
|
//date
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsYYYYMMDD(LPart) then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.ModifiedDate := DateYYMMDD(LPart);
|
|||
|
//time
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
|
|||
|
LPart := Fetch(LBuf);
|
|||
|
if not IsHHMMSS(LPart, ':') then begin {do not localize}
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LV.ModifiedDate := LV.ModifiedDate + TimeHHMMSS(LPart);
|
|||
|
//name
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LV.FileName := TrimRight(Fetch(LBuf, '->')); {do not localize}
|
|||
|
//link to
|
|||
|
LBuf := TrimLeft(LBuf);
|
|||
|
LV.LinkedItemName := Trim(LBuf);
|
|||
|
//size
|
|||
|
LV.SizeAvail := False;
|
|||
|
Result := True;
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPStratusVOS.ParseListing(AListing: TStrings;
|
|||
|
ADir: TIdFTPListItems): Boolean;
|
|||
|
var
|
|||
|
LDit : TIdDirItemType; //for tracking state
|
|||
|
LItem : TIdFTPListItem;
|
|||
|
i : Integer;
|
|||
|
LIsContinuedLine : Boolean;
|
|||
|
LLine, LPart, LBuf : String;
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
LDit := ditFile;
|
|||
|
LIsContinuedLine := False;
|
|||
|
for i := 0 to AListing.Count -1 do
|
|||
|
begin
|
|||
|
LBuf := AListing[i];
|
|||
|
if LBuf <> '' then
|
|||
|
begin
|
|||
|
if IsFilesHeader(LBuf) then begin
|
|||
|
LDit := ditFile;
|
|||
|
end
|
|||
|
else if IsDirsHeader(LBuf) then begin
|
|||
|
LDit := ditDirectory;
|
|||
|
end
|
|||
|
else if IsLinksHeader(LBuf) then begin
|
|||
|
LDit := ditSymbolicLink;
|
|||
|
end
|
|||
|
else if LDit <> ditSymbolicLink then
|
|||
|
begin
|
|||
|
LItem := MakeNewItem(ADir);
|
|||
|
LItem.ItemType := LDit;
|
|||
|
LItem.Data := LBuf;
|
|||
|
if not ParseLine(LItem) then begin
|
|||
|
FreeAndNil(LItem);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end
|
|||
|
else if not LIsContinuedLine then
|
|||
|
begin
|
|||
|
LLine := TrimRight(LBuf);
|
|||
|
if TextEndsWith(LLine, '->') then begin {do not localize}
|
|||
|
LIsContinuedLine := True;
|
|||
|
end else
|
|||
|
begin
|
|||
|
LItem := MakeNewItem(ADir);
|
|||
|
LItem.ItemType := LDit;
|
|||
|
LItem.Data := LLine;
|
|||
|
if not ParseLine(LItem) then begin
|
|||
|
FreeAndNil(LItem);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end else
|
|||
|
begin
|
|||
|
LPart := LBuf;
|
|||
|
if TextStartsWith(LPart, '+') then begin
|
|||
|
IdDelete(LPart, 1, 1);
|
|||
|
end;
|
|||
|
LLine := LLine + LPart;
|
|||
|
LIsContinuedLine := False;
|
|||
|
if i < (AListing.Count-2) then
|
|||
|
begin
|
|||
|
if TextStartsWith(AListing[i+1], '+') then begin
|
|||
|
LIsContinuedLine := True;
|
|||
|
end else
|
|||
|
begin
|
|||
|
LItem := MakeNewItem(ADir);
|
|||
|
LItem.ItemType := LDit;
|
|||
|
LItem.Data := LLine;
|
|||
|
if not ParseLine(LItem) then begin
|
|||
|
FreeAndNil(LItem);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end else
|
|||
|
begin
|
|||
|
LItem := MakeNewItem(ADir);
|
|||
|
LItem.ItemType := LDit;
|
|||
|
LItem.Data := LLine;
|
|||
|
if not ParseLine(LItem) then begin
|
|||
|
FreeAndNil(LItem);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
Result := True;
|
|||
|
end;
|
|||
|
|
|||
|
initialization
|
|||
|
RegisterFTPListParser(TIdFTPLPStratusVOS);
|
|||
|
finalization
|
|||
|
UnRegisterFTPListParser(TIdFTPLPStratusVOS);
|
|||
|
|
|||
|
end.
|