home

about

license

support

K/Base

Indy
HomeContactsSite Map


The OnMLST event

Recently, I added a new OnMLST event to our FTP server component.    I decided that this was necessary because the regular OnListDirectory event handler would probably be a mess if I didn't.  The reason is that the OnListDirectory is triggered by the LIST and MLSD commands.  Usually, when listing a directory, if you specify a subdirectory such as "pub", you usually  want the contents of that directory and the MLSD command requires that behavior.  The MLST command is intended to give information about one particular item so if you wanted information about the pub directory, the command would be "MLST pub".  I have found that NcFTP Client does use the MLST command to get information about a file or verify that it exists.

The MLST event is defined like this:

procedure TForm1.IdFTPServer1MLST(ASender: TIdFTPServerContext;
  const APath: string; ADirectoryListing: TIdFTPListOutput);

The reason why we do not simply provide one TIdFTPListOutputItem that you simply fill in is because you might have an occaision where you may need to have two "type" facts in your information.  Thus, there can be more than one entry.

Here is a sample showing how this event is used.  Note that this does use the Win32 API.  I've already described the reason that I don't use FindFirst Borland RTL function.

function TForm1.FileTimeToTDateTime(const AFileTime: TFileTime): TDateTime;
var   LDosTime : LongInt;
begin
  Result := 0;
  if Windows.FileTimeToDosDateTime(AFileTime, LongRec(LDosTime).Hi,
      LongRec(LDosTime).Lo) then
  begin
    Result := SysUtils.FileDateToDateTime(LDosTime);
  end
  else
  begin
     SysUtils.RaiseLastOSError;
  end;
end;

procedure TForm1.IdFTPServer1MLST(ASender: TIdFTPServerContext;
  const APath: string; ADirectoryListing: TIdFTPListOutput);
var
 LFTPItem :TIdFTPListOutputItem;
 SR : TSearchRec;
 SRI : Integer;
 LTmpPath : String;
begin
//for this, we return information only about the item, not the contents
    LTmpPath := RemoveTrailingPathDel ( ReplaceChars(AppDir  + APath));
    if LTmpPath = '' then
    begin
      LFTPItem := ADirectoryListing.Add;
      LFTPItem.ItemType   := ditDirectory;
      LFTPItem.FileName := '/';
      Exit;
    end;
    SRI := FindFirst(LTmpPath, faAnyFile , SR);
    if SRI = 0 then
    begin
      LFTPItem := ADirectoryListing.Add;
      //This is necessary because the Borland RTL FindData Size is an Integer and can't handle
      //anything greater than 2GB.
      LFTPItem.Size := Int64(SR.FindData.nFileSizeHigh shl 32) + SR.FindData.nFileSizeLow;
      //
//   The file name returned in the MLST response should be the same name
//   as was specified in the MLST command, or, where TVFS is supported, a
//   fully qualified TVFS path naming the same file.  Where no argument
//   was given to the MLST command, the server-PI may either include an
//   empty file name in the response, or it may supply a name that refers
//   to the current directory, if such a name is available.  Where TVFS is
//   supported, a fully qualified pathname of the current directory SHOULD
//   be returned.
//
      LTmpPath :=  RemoveTrailingPathDel(ReplaceChars(ASender.HomeDir + APath));
      if LTmpPath = '' then
      begin
        LTmpPath := '/';
      end;
      LFTPItem.FileName := StringReplace(LTmpPath,'\','/',[rfReplaceAll]);
      LFTPItem.ModifiedDateGMT := FileTimeToTDateTime( SR.FindData.ftLastWriteTime);
      LFTPItem.CreationDateGMT := FileTimeToTDateTime( SR.FindData.ftCreationTime);
      LFTPItem.LastAccessDateGMT := FileTimeToTDateTime( SR.FindData.ftLastAccessTime);
      LFTPItem.WinAttribs := SR.FindData.dwFileAttributes;
      if SR.Attr and faDirectory > 0 then
      begin
        LFTPItem.ItemType   := ditDirectory;
      end
      else
      begin
        LFTPItem.ItemType  := ditFile;
      end;
      FindClose(SR);
    end
    else
    begin
      RaiseLastOSError;
    end;
end;
  

As you can tell, this fairly streinghforward. The code is from a sample I intend to make available soon.   If you want to be more selective about processing certain file facts (only obtain them if the client specifically negotiated them), you can use the ASender.MLSOpts set (or enumeration in C#).  The values it contains currently are:

ItemType,Modify,Size,Perm,Unique,UnixMODE,UnixOwner, UnixGroup,CreateTime,LastAccessTime,WinAttribs

I will leave the more fancy work as an excersize for our readers.


Corporate Sponsors

Atozed







home

about

license

support

K/Base

site map

links

Copyright © 1993 - 2008 Chad Z. Hower (Kudzu) and the Indy Pit Crew.          Website design by RuInternet.ru