608 lines
19 KiB
Plaintext
608 lines
19 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.8 2/24/2005 10:01:34 AM JPMugaas
|
|||
|
Fixed estimation of filesize for variable record length files (V) in z/VM to
|
|||
|
conform to what was specified in:
|
|||
|
|
|||
|
z/VMTCP/IP User<65>s Guide Version 5 Release 1.0
|
|||
|
|
|||
|
This will not always give the same estimate as the server would when listing
|
|||
|
in Unix format "SITE LISTFORMAT UNIX" because we can't know the block size
|
|||
|
(we have to assume a size of 4096).
|
|||
|
|
|||
|
Rev 1.7 10/26/2004 10:03:20 PM JPMugaas
|
|||
|
Updated refs.
|
|||
|
|
|||
|
Rev 1.6 9/7/2004 10:02:30 AM JPMugaas
|
|||
|
Tightened the VM/BFS parser detector so that valid dates have to start the
|
|||
|
listing item. This should reduce the likelyhood of error.
|
|||
|
|
|||
|
Rev 1.5 6/28/2004 4:34:18 AM JPMugaas
|
|||
|
VM_CMS-ftp.marist.edu-7.txt was being detected as VM/BFS instead of VM/CMS
|
|||
|
causing a date encode error.
|
|||
|
|
|||
|
Rev 1.4 4/19/2004 5:05:32 PM JPMugaas
|
|||
|
Class rework Kudzu wanted.
|
|||
|
|
|||
|
Rev 1.3 2004.02.03 5:45:22 PM czhower
|
|||
|
Name changes
|
|||
|
|
|||
|
Rev 1.2 10/19/2003 3:48:12 PM DSiders
|
|||
|
Added localization comments.
|
|||
|
|
|||
|
Rev 1.1 4/7/2003 04:04:30 PM JPMugaas
|
|||
|
User can now descover what output a parser may give.
|
|||
|
|
|||
|
Rev 1.0 2/19/2003 04:18:20 AM JPMugaas
|
|||
|
More things restructured for the new list framework.
|
|||
|
}
|
|||
|
|
|||
|
unit IdFTPListParseVM;
|
|||
|
|
|||
|
{
|
|||
|
IBM VM and z/VM parser
|
|||
|
}
|
|||
|
|
|||
|
interface
|
|||
|
|
|||
|
{$i IdCompilerDefines.inc}
|
|||
|
|
|||
|
uses
|
|||
|
Classes,
|
|||
|
IdFTPList, IdFTPListParseBase, IdFTPListTypes;
|
|||
|
|
|||
|
type
|
|||
|
TIdVMCMSFTPListItem = class(TIdRecFTPListItem)
|
|||
|
protected
|
|||
|
FOwnerName : String;
|
|||
|
FNumberBlocks : Integer;
|
|||
|
public
|
|||
|
property RecLength : Integer read FRecLength write FRecLength;
|
|||
|
property RecFormat : String read FRecFormat write FRecFormat;
|
|||
|
property NumberRecs : Integer read FNumberRecs write FNumberRecs;
|
|||
|
property OwnerName : String read FOwnerName write FOwnerName;
|
|||
|
property NumberBlocks : Integer read FNumberBlocks write FNumberBlocks;
|
|||
|
end;
|
|||
|
|
|||
|
TIdVMVirtualReaderFTPListItem = class(TIdFTPListItem)
|
|||
|
protected
|
|||
|
FNumberRecs : Integer;
|
|||
|
public
|
|||
|
constructor Create(AOwner: TCollection); override;
|
|||
|
property NumberRecs : Integer read FNumberRecs write FNumberRecs;
|
|||
|
end;
|
|||
|
|
|||
|
TIdVMBFSFTPListItem = class(TIdFTPListItem);
|
|||
|
|
|||
|
TIdFTPLPVMCMS = class(TIdFTPListBaseHeaderOpt)
|
|||
|
protected
|
|||
|
class function IsHeader(const AData : String): Boolean; override;
|
|||
|
class function MakeNewItem(AOwner : TIdFTPListItems) : TIdFTPListItem; override;
|
|||
|
class function ParseLine(const AItem : TIdFTPListItem; const APath : String = ''): Boolean; override;
|
|||
|
class function CheckListingAlt(AListing : TStrings; const ASysDescript : String = ''; const ADetails : Boolean = True): Boolean; override;
|
|||
|
public
|
|||
|
class function GetIdent : String; override;
|
|||
|
end;
|
|||
|
|
|||
|
TIdFTPLPVMBFS = class(TIdFTPListBase)
|
|||
|
protected
|
|||
|
class function MakeNewItem(AOwner : TIdFTPListItems) : TIdFTPListItem; override;
|
|||
|
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;
|
|||
|
end;
|
|||
|
|
|||
|
TIdFTPLVirtualReader = class(TIdFTPListBase)
|
|||
|
protected
|
|||
|
class function MakeNewItem(AOwner : TIdFTPListItems) : TIdFTPListItem; override;
|
|||
|
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;
|
|||
|
|
|||
|
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 "IdFTPListParseVM"'}
|
|||
|
{$ENDIF}
|
|||
|
|
|||
|
implementation
|
|||
|
|
|||
|
uses
|
|||
|
IdException,
|
|||
|
IdGlobal, IdFTPCommon, IdGlobalProtocols,
|
|||
|
SysUtils;
|
|||
|
|
|||
|
function IsFileMode(const AStr : String) : Boolean;
|
|||
|
begin
|
|||
|
Result := CharIsInSet(AStr,1,'ABCDEFGHIJKLMNOPQRSTUV') and
|
|||
|
CharIsInSet(AStr,2,'0123456');
|
|||
|
end;
|
|||
|
|
|||
|
{ TIdFTPLPVMCMS }
|
|||
|
|
|||
|
class function TIdFTPLPVMCMS.CheckListingAlt(AListing: TStrings; const ASysDescript: String;
|
|||
|
const ADetails: Boolean): Boolean;
|
|||
|
const
|
|||
|
VMTypes : array [1..3] of string = ('F','V','DIR'); {do not localize}
|
|||
|
var
|
|||
|
LData : String;
|
|||
|
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
if AListing.Count > 0 then begin
|
|||
|
LData := AListing[0];
|
|||
|
if IsFileMode(Trim(Copy(LData, 19, 3))) then begin
|
|||
|
Result := PosInStrArray(Trim(Copy(LData, 22, 3)), VMTypes) <> -1;
|
|||
|
if Result then begin
|
|||
|
Result := IsMMDDYY(Trim(Copy(LData,52,10)),'/');
|
|||
|
end;
|
|||
|
end else begin
|
|||
|
Result := PosInStrArray(Trim(Copy(LData, 19, 3)), VMTypes) <> -1;
|
|||
|
if Result then begin
|
|||
|
Result := (Copy(LData, 56, 1) = '/') and (Copy(LData, 59, 1) = '/'); {do not localize}
|
|||
|
if not Result then begin
|
|||
|
Result := (Copy(LData, 58, 1) = '-') and (Copy(LData, 61, 1) = '-'); {do not localize}
|
|||
|
if not Result then begin
|
|||
|
Result := (Copy(LData, 48, 1) = '-') and (Copy(LData, 51, 1) = '-'); {do not localize}
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPVMCMS.GetIdent: String;
|
|||
|
begin
|
|||
|
Result := 'VM/CMS'; {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPVMCMS.IsHeader(const AData: String): Boolean;
|
|||
|
begin
|
|||
|
Result := Trim(AData) = 'Filename FileType Fm Format Lrecl Records Blocks Date Time'
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPVMCMS.MakeNewItem(AOwner: TIdFTPListItems): TIdFTPListItem;
|
|||
|
begin
|
|||
|
Result := TIdVMCMSFTPListItem.Create(AOwner);
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPVMCMS.ParseLine(const AItem: TIdFTPListItem;
|
|||
|
const APath: String): Boolean;
|
|||
|
var
|
|||
|
LBuffer : String;
|
|||
|
LCols : TStrings;
|
|||
|
LI : TIdVMCMSFTPListItem;
|
|||
|
LSize : Int64;
|
|||
|
LPRecLn,LLRecLn : Integer;
|
|||
|
LPRecNo, LLRecNo : Integer;
|
|||
|
LPBkNo,LLBkNo : Integer;
|
|||
|
LPCol : Integer;
|
|||
|
begin
|
|||
|
{Some of this is based on the following:
|
|||
|
|
|||
|
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=utf-8&threadm=4e7k0p%24t1v%40blackice.winternet.com&rnum=4&prev=/groups%3Fq%3DVM%2BFile%2BRecords%2Bdirectory%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3Dutf-8%26selm%3D4e7k0p%2524t1v%2540blackice.winternet.com%26rnum%3D4
|
|||
|
|
|||
|
and
|
|||
|
|
|||
|
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=utf-8&selm=DLspv2.G2w%40epsilon.com&rnum=2
|
|||
|
}
|
|||
|
{
|
|||
|
123456789012345678901234567890123456789012345678901234567890123456789012
|
|||
|
1 2 3 4 5 6 7
|
|||
|
OMA00215 PLAN V 64 28 1 6/26/02 9:33:21 -
|
|||
|
WEBSHARE DIR - - - 5/30/97 18:44:17 -
|
|||
|
|
|||
|
or
|
|||
|
|
|||
|
README ANONYMOU V 71 26 1 1997-04-02 12:33:20 TCP291
|
|||
|
|
|||
|
or maybe this:
|
|||
|
|
|||
|
ENDTRACE TCPIP F 80 1 1 1999-07-28 12:24:01 TCM191
|
|||
|
123456789012345678901234567890123456789012345678901234567890123456789012
|
|||
|
1 2 3 4 5 6 7
|
|||
|
|
|||
|
or possibly this FILELIST format:
|
|||
|
|
|||
|
Filename FileType Fm Format Lrecl Records Blocks Date Time
|
|||
|
LASTING GLOBALV A1 V 41 21 1 9/16/91 15:10:32
|
|||
|
J43401 NETLOG A0 V 77 1 1 9/12/91 12:36:04
|
|||
|
PROFILE EXEC A1 V 17 3 1 9/12/91 12:39:07
|
|||
|
DIRUNIX SCRIPT A1 V 77 1216 17 1/04/93 20:30:47
|
|||
|
MAIL PROFILE A2 F 80 1 1 10/14/92 16:12:27
|
|||
|
BADY2K TEXT A0 V 1 1 1 1/03/102 10:11:12
|
|||
|
AUTHORS A1 DIR - - - 9/20/99 10:31:11
|
|||
|
---------------
|
|||
|
|
|||
|
123456789012345678901234567890123456789012345678901234567890123456789012
|
|||
|
1 2 3 4 5 6 7
|
|||
|
|
|||
|
}
|
|||
|
LI := AItem as TIdVMCMSFTPListItem;
|
|||
|
//File Name
|
|||
|
LI.FileName := Trim(Copy(AItem.Data, 1, 8));
|
|||
|
//File Type - extension
|
|||
|
if LI.Data[9] = ' ' then begin
|
|||
|
LBuffer := Copy(AItem.Data, 10, 9);
|
|||
|
end else begin
|
|||
|
LBuffer := Copy(AItem.Data, 9, 9);
|
|||
|
end;
|
|||
|
LBuffer := Trim(LBuffer);
|
|||
|
if LBuffer <> '' then begin
|
|||
|
LI.FileName := LI.FileName + '.' + LBuffer; {do not localize}
|
|||
|
end;
|
|||
|
//Record format
|
|||
|
LBuffer := Trim(Copy(AItem.Data, 19, 3));
|
|||
|
if IsFileMode(LBuffer) then begin
|
|||
|
LBuffer := Trim(Copy(AItem.Data, 23, 3));
|
|||
|
LPRecLn := 30;
|
|||
|
LLRecLn := 7;
|
|||
|
LPRecNo := 37;
|
|||
|
LLRecNo := 7;
|
|||
|
LPBkNo := 44;
|
|||
|
LLBkNo := 8;
|
|||
|
LPCol := 52;
|
|||
|
end else begin
|
|||
|
LPRecLn := 22;
|
|||
|
LLRecLn := 9;
|
|||
|
LPRecNo := 31;
|
|||
|
LLRecNo := 11;
|
|||
|
LPBkNo := 42;
|
|||
|
LLBkNo := 11;
|
|||
|
if (Copy(AItem.Data, 48, 1) = '-') and (Copy(AItem.Data, 51, 1) = '-') then begin {do not localize}
|
|||
|
LPCol := 44;
|
|||
|
end else begin
|
|||
|
LPCol := 54;
|
|||
|
end;
|
|||
|
end;
|
|||
|
LI.RecFormat := LBuffer;
|
|||
|
if LI.RecFormat = 'DIR' then begin {do not localize}
|
|||
|
LI.ItemType := ditDirectory;
|
|||
|
LI.RecLength := 0;
|
|||
|
end else begin
|
|||
|
LI.ItemType := ditFile;
|
|||
|
//Record Length - for files
|
|||
|
LBuffer := Copy(AItem.Data, LPRecLn, LLRecLn);
|
|||
|
LI.RecLength := IndyStrToInt(LBuffer, 0);
|
|||
|
//Record numbers
|
|||
|
LBuffer := Trim(Copy(AItem.Data, LPRecNo, LLRecNo));
|
|||
|
LBuffer := Fetch(LBuffer);
|
|||
|
LI.NumberRecs := IndyStrToInt(LBuffer, 0);
|
|||
|
//Number of Blocks
|
|||
|
{
|
|||
|
From:
|
|||
|
|
|||
|
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=utf-8&selm=DLspv2.G2w%40epsilon.com&rnum=2
|
|||
|
|
|||
|
Block sizes can be 800, 512, 1024,
|
|||
|
2048, or 4096, per the whim of the user. IBM loves 4096, but it wastes
|
|||
|
space (just like on FAT partitions on DOS.)
|
|||
|
|
|||
|
For F files (any type which begins with F), record count times logical
|
|||
|
record length.
|
|||
|
|
|||
|
For V files, you need to read the file for an exact count, or the block
|
|||
|
size (times block count) for a good guess. In other words, you're up
|
|||
|
the creek because you don't KNOW the block size. Use record size times
|
|||
|
record length for a _maximum_ file size.
|
|||
|
|
|||
|
Anyway, you can not know from the directory list.
|
|||
|
}
|
|||
|
LBuffer := Trim(Copy(AItem.Data, LPBkNo, LLBkNo));
|
|||
|
LI.NumberBlocks := IndyStrToInt(LBuffer, 0);
|
|||
|
LI.Size := LI.RecLength * LI.NumberRecs;
|
|||
|
//File Size - note that this is just an estimiate
|
|||
|
|
|||
|
{From:
|
|||
|
z/VMTCP/IP User<65>s Guide Version 5 Release 1.0
|
|||
|
<20> Copyright International Business Machines Corporation 1987, 2004.
|
|||
|
All rights reserved.
|
|||
|
|
|||
|
For fixed-record (F) format minidisk and SFS files,
|
|||
|
the size field indicates the actual size of a file.
|
|||
|
For variable-record (V) format minidisk and SFS files,
|
|||
|
the size field contains an estimated file size, this
|
|||
|
being the lesser value determined by:
|
|||
|
|
|||
|
<20> the number of records in the file and its maximum record length
|
|||
|
<20> the size and number of blocks required to maintain the file.
|
|||
|
|
|||
|
For virtual reader files, a size of 0 is always indicated.}
|
|||
|
|
|||
|
if LI.RecFormat = 'V' then begin
|
|||
|
LSize := LI.NumberBlocks * 4096;
|
|||
|
if LI.Size > LSize then begin
|
|||
|
LI.Size := LSize;
|
|||
|
end;
|
|||
|
end;
|
|||
|
if LI.RecFormat = 'DIR' then begin
|
|||
|
LI.SizeAvail := False;
|
|||
|
end;
|
|||
|
end;
|
|||
|
LCols := TStringList.Create;
|
|||
|
try
|
|||
|
// we do things this way for the rest because vm.sc.edu has
|
|||
|
// a variation on VM/CMS that does directory dates differently
|
|||
|
//and some columns could be off.
|
|||
|
//Note that the start position in one server it's column 44 while in others, it's column 54
|
|||
|
// handle both cases.
|
|||
|
LBuffer := Trim(Copy(AItem.Data, LPCol, MaxInt));
|
|||
|
SplitDelimitedString(LBuffer, LCols, True);
|
|||
|
//LCols - 0 - Date
|
|||
|
//LCols - 1 - Time
|
|||
|
//LCols - 2 - Owner if present
|
|||
|
if LCols.Count > 0 then begin
|
|||
|
//date
|
|||
|
if IsNumeric(LCols[0], 3) then begin
|
|||
|
// vm.sc.edu date stamps yyyy-mm-dd
|
|||
|
LI.ModifiedDate := DateYYMMDD(LCols[0]);
|
|||
|
end else begin
|
|||
|
//Note that the date is displayed as 2 digits not 4 digits
|
|||
|
//mm/dd/yy
|
|||
|
LI.ModifiedDate := DateMMDDYY(LCols[0]);
|
|||
|
end;
|
|||
|
//time
|
|||
|
LI.ModifiedDate := LI.ModifiedDate + TimeHHMMSS(LCols[1]);
|
|||
|
//owner
|
|||
|
if (LCols.Count > 2) and (LCols[2] <> '-') then begin {do not localize}
|
|||
|
LI.OwnerName := LCols[2];
|
|||
|
end;
|
|||
|
end;
|
|||
|
finally
|
|||
|
FreeAndNil(LCols);
|
|||
|
end;
|
|||
|
Result := True;
|
|||
|
end;
|
|||
|
|
|||
|
{ TIdFTPLPVMBFS }
|
|||
|
|
|||
|
{List format like:
|
|||
|
|
|||
|
===
|
|||
|
05/20/2000 13:38:19 F 1 65758 <20>bfsline.cpy<70>
|
|||
|
05/19/2000 11:02:15 F 1 65758 <20>bfsline.txt<78>
|
|||
|
06/03/2000 12:27:48 F 1 15414 <20>bfstest.cpy<70>
|
|||
|
05/20/2000 13:38:05 F 1 15414 <20>bfstest.output<75>
|
|||
|
05/20/2000 13:38:42 F 1 772902 <20>bfswork.output<75>
|
|||
|
03/31/2000 15:49:27 F 1 782444 <20>bfswork.txt<78>
|
|||
|
05/20/2000 13:39:20 F 1 13930 <20>lotsonl.putdata<74>
|
|||
|
05/19/2000 09:41:21 F 1 13930 <20>lotsonl.txt<78>
|
|||
|
06/15/2000 09:29:25 F 1 278 <20>mail.maw<61>
|
|||
|
05/20/2000 13:39:34 F 1 278 <20>mail.putdata<74>
|
|||
|
05/20/2000 15:30:45 F 1 13930 <20>nls.new<65>
|
|||
|
05/20/2000 14:02:24 F 1 13931 <20>nls.txt<78>
|
|||
|
08/21/2000 10:03:17 F 1 328 <20>rock.rules<65>
|
|||
|
05/20/2000 13:40:05 F 1 58 <20>testfil2.putdata<74>
|
|||
|
04/26/2000 14:34:42 F 1 63 <20>testfil2.txt<78>
|
|||
|
08/21/2000 05:28:40 D - - <20>ALTERNATE<54>
|
|||
|
12/28/2000 17:36:19 D - - <20>FIRST
|
|||
|
===
|
|||
|
}
|
|||
|
class function TIdFTPLPVMBFS.CheckListing(AListing: TStrings;
|
|||
|
const ASysDescript: String; const ADetails: Boolean): Boolean;
|
|||
|
var
|
|||
|
s : TStrings;
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
|
|||
|
if AListing.Count > 0 then begin
|
|||
|
//should have a "'" as the terminator
|
|||
|
if AListing[0] <> '' then begin
|
|||
|
if not TextEndsWith(AListing[0], '''') then begin
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
s := TStringList.Create;
|
|||
|
try
|
|||
|
SplitDelimitedString(AListing[0], s, True);
|
|||
|
if s.Count > 4 then begin
|
|||
|
if not IsMMDDYY(s[0], '/') then begin {do not localize}
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
Result := CharIsInSet(s[2], 1, 'FD'); {do not localize}
|
|||
|
if Result then begin
|
|||
|
Result := IsNumeric(s[4]) or (s[4] <> '-'); {do not localize}
|
|||
|
end;
|
|||
|
end;
|
|||
|
finally
|
|||
|
FreeAndNil(s);
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPVMBFS.GetIdent: String;
|
|||
|
begin
|
|||
|
Result := 'VM/BFS'; {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPVMBFS.MakeNewItem(AOwner: TIdFTPListItems): TIdFTPListItem;
|
|||
|
begin
|
|||
|
Result := TIdVMBFSFTPListItem.Create(AOwner);
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLPVMBFS.ParseLine(const AItem: TIdFTPListItem;
|
|||
|
const APath: String): Boolean;
|
|||
|
var
|
|||
|
LBuffer : String;
|
|||
|
LCols : TStrings;
|
|||
|
begin
|
|||
|
// z/VM Byte File System
|
|||
|
|
|||
|
//This is based on:
|
|||
|
//
|
|||
|
// z/VM: TCP/IP Level 430 User's Guide Version 4 Release 3.0
|
|||
|
//
|
|||
|
// http://www.vm.ibm.com/pubs/pdf/hcsk7a10.pdf
|
|||
|
//
|
|||
|
LBuffer := AItem.Data;
|
|||
|
LCols := TStringList.Create;
|
|||
|
try
|
|||
|
SplitDelimitedString(Fetch(LBuffer, #39), LCols, True); {do not localize}
|
|||
|
//0 - date
|
|||
|
//1 - time
|
|||
|
//2 - (D) dir or file (F)
|
|||
|
//3 - not sure what this is
|
|||
|
//4 - file size
|
|||
|
AItem.FileName := LBuffer;
|
|||
|
if TextEndsWith(AItem.FileName, '''') then begin
|
|||
|
AItem.FileName := Copy(AItem.FileName, 1, Length(AItem.FileName)-1);
|
|||
|
end;
|
|||
|
//date
|
|||
|
if LCols.Count > 0 then begin
|
|||
|
AItem.ModifiedDate := DateMMDDYY(LCols[0]);
|
|||
|
end;
|
|||
|
if LCols.Count > 1 then begin
|
|||
|
AItem.ModifiedDate := AItem.ModifiedDate + TimeHHMMSS(LCols[1]);
|
|||
|
end;
|
|||
|
if LCols.Count > 2 then
|
|||
|
begin
|
|||
|
if LCols[2] = 'D' then begin
|
|||
|
AItem.ItemType := ditDirectory;
|
|||
|
end else begin
|
|||
|
AItem.ItemType := ditFile;
|
|||
|
end;
|
|||
|
end;
|
|||
|
//file size
|
|||
|
if LCols.Count > 4 then begin
|
|||
|
if IsNumeric(LCols[3]) then begin
|
|||
|
AItem.Size := IndyStrToInt64(LCols[4], 0);
|
|||
|
AItem.SizeAvail := True;
|
|||
|
end else begin
|
|||
|
AItem.SizeAvail := False;
|
|||
|
end;
|
|||
|
end;
|
|||
|
finally
|
|||
|
FreeAndNil(LCols);
|
|||
|
end;
|
|||
|
Result := True;
|
|||
|
end;
|
|||
|
|
|||
|
{ TIdFTPLVirtualReader }
|
|||
|
|
|||
|
class function TIdFTPLVirtualReader.CheckListing(AListing: TStrings;
|
|||
|
const ASysDescript: String; const ADetails: Boolean): Boolean;
|
|||
|
var
|
|||
|
s : TStrings;
|
|||
|
begin
|
|||
|
Result := False;
|
|||
|
if AListing.Count > 0 then begin
|
|||
|
s := TStringList.Create;
|
|||
|
try
|
|||
|
SplitDelimitedString(AListing[0], s, True);
|
|||
|
if s.Count > 2 then begin
|
|||
|
if (Length(s[0]) = 4) and IsNumeric(s[0]) then begin
|
|||
|
Result := (Length(s[2]) = 8) and (IsNumeric(s[2]));
|
|||
|
end;
|
|||
|
end;
|
|||
|
finally
|
|||
|
FreeAndNil(s);
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLVirtualReader.GetIdent: String;
|
|||
|
begin
|
|||
|
Result := 'VM Virtual Reader'; {do not localize}
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLVirtualReader.MakeNewItem(AOwner: TIdFTPListItems): TIdFTPListItem;
|
|||
|
begin
|
|||
|
Result := TIdVMVirtualReaderFTPListItem.Create(AOwner);
|
|||
|
end;
|
|||
|
|
|||
|
class function TIdFTPLVirtualReader.ParseLine(const AItem: TIdFTPListItem;
|
|||
|
const APath: String): Boolean;
|
|||
|
var
|
|||
|
LCols : TStrings;
|
|||
|
LI : TIdVMVirtualReaderFTPListItem;
|
|||
|
begin
|
|||
|
// z/VM Byte File System
|
|||
|
|
|||
|
//This is based on:
|
|||
|
//
|
|||
|
// z/VM: TCP/IP Level 430 User's Guide Version 4 Release 3.0
|
|||
|
//
|
|||
|
// http://www.vm.ibm.com/pubs/pdf/hcsk7a10.pdf
|
|||
|
//
|
|||
|
LI := AItem as TIdVMVirtualReaderFTPListItem;
|
|||
|
LCols := TStringList.Create;
|
|||
|
try
|
|||
|
// z/VM Virtual Reader (RDR)
|
|||
|
//Col 0 - spool ID
|
|||
|
//Col 1 - origin
|
|||
|
//Col 2 - records
|
|||
|
//Col 3 - date
|
|||
|
//Col 4 - time
|
|||
|
//Col 5 - filename
|
|||
|
//Col 6 - file type
|
|||
|
SplitDelimitedString(AItem.Data, LCols, True);
|
|||
|
if LCols.Count > 5 then begin
|
|||
|
LI.FileName := LCols[5];
|
|||
|
end;
|
|||
|
if LCols.Count > 6 then begin
|
|||
|
LI.FileName := LI.FileName + '.' + LCols[6]; {do not localize}
|
|||
|
end;
|
|||
|
//record count
|
|||
|
if LCols.Count > 2 then begin
|
|||
|
LI.NumberRecs := IndyStrToInt(LCols[2], 0);
|
|||
|
end;
|
|||
|
//date
|
|||
|
if LCols.Count > 3 then begin
|
|||
|
LI.ModifiedDate := DateYYMMDD(LCols[3]);
|
|||
|
end;
|
|||
|
//Time
|
|||
|
if LCols.Count > 4 then begin
|
|||
|
LI.ModifiedDate := LI.ModifiedDate + TimeHHMMSS(LCols[1]);
|
|||
|
end;
|
|||
|
//Note that IBM does not even try to give an estimate
|
|||
|
//with reader file sizes when emulating Unix. We can't support file sizes
|
|||
|
//with this.
|
|||
|
finally
|
|||
|
FreeAndNil(LCols);
|
|||
|
end;
|
|||
|
Result := True;
|
|||
|
end;
|
|||
|
|
|||
|
{ TIdVMVirtualReaderFTPListItem }
|
|||
|
|
|||
|
constructor TIdVMVirtualReaderFTPListItem.Create(AOwner: TCollection);
|
|||
|
begin
|
|||
|
inherited Create(AOwner);
|
|||
|
//There's no size for things in a virtual reader
|
|||
|
SizeAvail := False;
|
|||
|
end;
|
|||
|
|
|||
|
initialization
|
|||
|
RegisterFTPListParser(TIdFTPLVirtualReader);
|
|||
|
RegisterFTPListParser(TIdFTPLPVMBFS);
|
|||
|
RegisterFTPListParser(TIdFTPLPVMCMS);
|
|||
|
finalization
|
|||
|
UnRegisterFTPListParser(TIdFTPLVirtualReader);
|
|||
|
UnRegisterFTPListParser(TIdFTPLPVMBFS);
|
|||
|
UnRegisterFTPListParser(TIdFTPLPVMCMS);
|
|||
|
|
|||
|
end.
|