{
  $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.0    12/8/2004 8:45:02 AM  JPMugaas
}

unit IdFTPListParseUnisysClearPath;

{
  Unisys ClearPath (MCP and OS/2)
  DIRECTORY_FORMAT=NATIVE

  Much of this is based on:

  ClearPath Enterprise Servers
  FTP Services for ClearPath
  OS 2200 User's Guide
  ClearPath OS 2200 Release 8.0 January 2003
  © 2003 Unisys Corporation.
  All rights reserved.

  and

  ClearPath Enterprise Servers
  TCP/IP Distributed Systems Services Operations Guide
  ClearPath MCP Release 9.0 April 2004
  © 2004 Unisys Corporation.
  All rights reserved.

  With a sample showing a multiline response from:

  http://article.gmane.org/gmane.text.xml.cocoon.devel/24912

  This parses data in this form:
  ===
  Report for: (UC)A ON PACK
  A                       SEQDATA    84 03/08/1998  15:32
  A/B                     SEQDATA    84 06/09/1998  12:03
  A/B/C                   SEQDATA    84 06/09/1998  12:03
  A/C                     SEQDATA    84 06/09/1998  12:03
  A/C/C                   SEQDATA    84 06/09/1998  12:04
  A/C/C/D                 SEQDATA    84 06/09/1998  12:04
            6 Files     504 Octets
  ===

  The parserm only support DIRECTORY_FORMAT=NATIVE which is the default on that server.
  DIRECTORY_FORMAT=STANDARD does not need be supported because that is probably listed
  in Unix format. If not, we'll deal with it given some data samples.
}

interface

{$i IdCompilerDefines.inc}

uses
  Classes,
  IdFTPList, IdFTPListParseBase, IdFTPListTypes;

type
  TIdUnisysClearPathFTPListItem = class(TIdCreationDateFTPListItem)
  protected
    FFileKind : String;
  public
    property FileKind : String read FFileKind write FFileKind;
  end;

  TIdFTPLPUnisysClearPath = class(TIdFTPListBaseHeader)
  protected
    class function IsContinuedLine(const AData: String): Boolean;
    class function MakeNewItem(AOwner : TIdFTPListItems) : TIdFTPListItem; override;
    class function IsHeader(const AData: String): Boolean; override;
    class function IsFooter(const AData : String): Boolean; override;
    class function ParseLine(const AItem : TIdFTPListItem; const APath : String = ''): Boolean; override;
  public
    class function ParseListing(AListing : TStrings; ADir : TIdFTPListItems) : Boolean; override;
    class function GetIdent : String; 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 "IdFTPListParseUnisysClearPath"'}
  {$ENDIF}

implementation

uses
  IdGlobal, IdFTPCommon, IdGlobalProtocols, IdStrings, SysUtils;

{ TIdFTPLPUnisysClearPath }

class function TIdFTPLPUnisysClearPath.GetIdent: String;
begin
  Result := 'Unisys Clearpath'; {Do not localize}
end;

class function TIdFTPLPUnisysClearPath.IsContinuedLine(const AData: String): Boolean;
begin
  Result := TextStartsWith(AData, ' '); {Do not localize}
end;

class function TIdFTPLPUnisysClearPath.IsFooter(const AData: String): Boolean;
var
  s : TStrings;
begin
  Result := False;
  s := TStringList.Create;
  try
    SplitDelimitedString(AData, s, True);
    if s.Count = 4 then
    begin
      if (s[1] = 'Files') or (s[1] = 'File') then begin {Do not localize}
        Result := (s[3] = 'Octets') or (s[3] = 'Octet');  {Do not localize}
      end;
    end;
  finally
    FreeAndNil(s);
  end;
end;

class function TIdFTPLPUnisysClearPath.IsHeader(const AData: String): Boolean;
var
  s : TStrings;
begin
  Result := False;
  s := TStringList.Create;
  try
    SplitDelimitedString(AData, s, True);
    if s.Count > 2 then begin
      Result := (s[0] = 'Report') and (s[1] = 'for:');
    end;
  finally
    FreeAndNil(s);
  end;
end;

class function TIdFTPLPUnisysClearPath.MakeNewItem(AOwner: TIdFTPListItems): TIdFTPListItem;
begin
  Result := TIdUnisysClearPathFTPListItem.Create(AOwner);
end;

class function TIdFTPLPUnisysClearPath.ParseLine(const AItem: TIdFTPListItem;
  const APath: String): Boolean;
var
  s : TStrings;
  LI : TIdUnisysClearPathFTPListItem;
begin
  Result := False;
  LI := AItem as TIdUnisysClearPathFTPListItem;
  LI.ItemType := ditFile;
  s := TStringList.Create;
  try
    SplitDelimitedString(LI.Data, s, True);
    if s.Count > 4 then
    begin
      LI.FileName := s[0];
      LI.FileKind := s[1];
      //size
      if IsNumeric(s[2]) then
      begin
        LI.Size := IndyStrToInt(s[2], 0);
        AItem.SizeAvail := True;
        //creation date
        if IsMMDDYY(s[3], '/') then {Do not localize}
        begin
          LI.CreationDate := DateMMDDYY(s[3]);
          if IsHHMMSS(s[4], ':') then {Do not localize}
          begin
            LI.CreationDate := LI.CreationDate + TimeHHMMSS(s[4]);
            Result := True;
          end;
        end;
      end;
      s.Clear;
      //remove path from localFileName
      SplitDelimitedString(LI.FileName, s, True, '/'); {Do not localize}
      if s.Count > 0 then begin
        LI.LocalFileName := s[s.Count-1];
      end else begin
        Result := False;
      end;
    end;
  finally
    FreeAndNil(s);
  end;
end;

class function TIdFTPLPUnisysClearPath.ParseListing(AListing: TStrings;
  ADir: TIdFTPListItems): Boolean;
var
  i : Integer;
  LItem : TIdFTPListItem;
begin
  for i := 0  to AListing.Count-1 do
  begin
    if not IsWhiteString(AListing[i]) then
    begin
      if not (IsHeader(AListing[i]) or IsFooter(AListing[i])) then
      begin
        if (not IsContinuedLine(AListing[i])) then //needed because some VMS computers return entries with multiple lines
        begin
          LItem := MakeNewItem(ADir);
          LItem.Data := UnfoldLines(AListing[i], i, AListing);
          Result := ParseLine(LItem);
          if not Result then begin
            FreeAndNil(LItem);
            Exit;
          end;
        end;
      end;
    end;
  end;
  Result := True;
end;

initialization
  RegisterFTPListParser(TIdFTPLPUnisysClearPath);
finalization
  UnRegisterFTPListParser(TIdFTPLPUnisysClearPath);

end.
