Fix for WIndows NT FTP Service Directory List parser
THis is a fix for a parsing problem with file sizes that are greater than 9 digits.
Earlier this morning, Jeff Easton, has posted about a problem with the
Windows NT IIS FTP Service list parser class. The parser could not detect that
it could handle a file size greater than 9 digits. I confirmed the bug myself
and I checked in a fix for it. The fix is a minor reworking for the parser
detection routine to be more liberal about numbers in specific string positions.
At the same time, I changed things so the parser would be less tolorant of
spaces to the right side of a number. I did that because FTP list parsing is
always a mess since there are many formats and if I'm not careful, I can easily
do a fix that introduces other problems.
If you are interested, just replace the TIdFTPLPWindowsNT.CheckListing class
procedure in the IdFTPListParseWindowsNT unit with this one:
class function TIdFTPLPWindowsNT.CheckListing(AListing: TIdStrings;
const ASysDescript: String; const ADetails: Boolean): boolean;
var SDir, sSize : String;
i : Integer;
SData : String;
begin
//maybe, we are dealing with this pattern
//2002-09-02 18:48 <DIR> DOS dir 2
//
//or
//2002-09-02 19:06 9,730 DOS file 2
//
//Those were obtained from soem comments in some FileZilla source-code.
//FtpListResult.cpp
//Note that none of that GNU source-code was used.
//
//I personally came accross the following when on Microsoft IIS
//FTP Service on WIndowsXP Pro when I enabled the "FtpDirBrowseShowLongDate"
//metadata property.
//
//02-16-2005 04:16AM <DIR> pub
Result := False;
for i := 0 to AListing.Count - 1 do
begin
if (AListing[i]<>'') and
(IsSubDirContentsBanner(AListing[i])=False) then
begin
SData := Sys.UpperCase(AListing[i]);
sDir := Copy(SData, 25, 5);
//maybe this is two spacs off. We don't use TrimLeft at this point
//because we can't assume that this is a valid WIndows FTP Service listing.
if sDir = ' <DI' then {do not localize}
begin
sDir := Copy(SData, 27, 5);
end;
sDir := Sys.TrimLeft(sDir);
//This is a workaround for large file sizes such as:
//09-08-05 10:22AM 628551680 Test.txt
//09-08-05 10:23AM 628623360 Test2.txt
if IsNumeric(Sys.TrimLeft(sDir)) then
begin
sDir := '';
end;
sSize := Sys.StringReplace(Sys.TrimLeft(Copy(SData, 20, 19)), ',', ''); {Do not Localize}
//VM/BFS does share the date/time format as MS-DOS for the first two columns
// if ((CharIsInSet(SData, 3, ['/', '-'])) and (CharIsInSet(SData, 6, ['/', '-']))) then
if IsMMDDYY(Copy(SData,1,8),'-') or IsMMDDYY(Copy(SData,1,8),'/') then
begin
if (sDir = '<DIR>') then {do not localize}
begin
Result := IsVMBFS(SData)=False;
end
else
begin
//may be a file - see if we can get the size if sDir is empty
if ((sDir = '') and {Do not Localize}
(Sys.StrToInt64(sSize, -1) <> -1)) then
begin
Result := IsVMBFS(SData)=False;
end;
end;
end
else
begin
if IsYYYYMMDD(SData) then
begin
if (sDir = '<DIR>') then {do not localize}
begin
Result := IsVMBFS(SData)=False;
end
else
begin
//may be a file - see if we can get the size if sDir is empty
if ((sDir = '') and {Do not Localize}
(Sys.StrToInt64(sSize, -1) <> -1)) then
begin
Result := IsVMBFS(SData)=False;
end;
end;
end
else
begin
if IsMMDDYY(SData,'-') then
begin
{
It might be like this:
02-16-2005 04:16AM <DIR> pub
02-14-2005 07:22AM 9112103 ethereal-setup-0.10.9.exe
}
if (sDir = '<DIR>') then {do not localize}
begin
Result := IsVMBFS(SData)=False;
end
else
begin
if ((sDir = '') and {Do not Localize}
(Sys.StrToInt64(sSize, -1) <> -1)) then
begin
Result := IsVMBFS(SData)=False;
end;
end;
end;
end;
end;
end;
end;
end;
It goes without saying that the ultimate fix to these parsing problems is if
all servers and clients support the MLSD/MLST
commands.