This is not an error in TIdFTP . This is more of an omission in the Indy documentation.
EIdReplyRFCError means that the FTP server itself reports an error in response to the command that TIdFTP.List() sends. Depending on the values of the ADetails and TIdFTP UseMLIS + CanUseMLS , List() can send one of three different commands:
ADetails=False: NLST [ASpecifier] ADetails=True: TIdFTP.UseMLIS=True and TIdFTP.CanUseMLS=True: MLSD [ASpecifier] TIdFTP.UseMLIS=False or TIdFTP.CanUseMLS=False: LIST [ASpecifier]
Thus:
FTP.List( aFiles, '', true ); // this works // sends either 'LIST' or 'MLSD' FTP.List( aFiles, '*.*', false ); // this works too // sends 'NLST *.*' FTP.List( aFiles, '*.*', true ); // this fails // sends either 'LIST *.*' or 'MLSD *.*' FTP.List( aFiles, '*.zip', true ); // this fails too // sends either 'LIST *.zip' or 'MLSD *.zip' FTP.List( '*.*', false ); // this works // sends 'NLST *.*' FTP.List( '*.*', true ); // this fails // sends either 'LIST *.*' or 'MLSD *.*'
Note that all failed commands have something in common that can send the MLSD ASpecifier .
Per RFC 959 , which defines the LIST and NLST commands:
LIST (LIST)
This command causes the list to be sent from the server to passive DTP. If the path name indicates a directory or another group of files, the server must transfer a list of files in the specified directory. If the path name indicates the file, then the server should send the current information to the file. A null argument implies that the current user is running or the default directory. ...
LIST NAME (NLST)
This command sends a directory listing from the server to the user. The path must specify a directory or other system filegroup descriptor; null indicates the current directory. ...
Per RFC 3659 , which defines the MLSD command:
The MLST and MLSD commands allow one optional argument to be resolved. This argument can be either a directory name or just for the MLST file name. For these purposes, “file name” is the name of any object on the NVFS server that is not a directory. Where TVFS is supported by any relative TVFS path existing in the current working directory or any fully qualified TVFS channel name. If a directory name is specified then MLSD should return a list of the contents of the named directory; otherwise, it returns 501 and does not open a data connection. ...
If no argument is specified, MLSD should return a list of the contents of the current working directory , and MLST should return a list containing information about the current working directory itself ....
...
If the FTP client sends an invalid argument, the FTP server MUST respond with error code 501.
*.* and *.zip are not directory names, so the server will fail if TIdFTP.List() sends the MLSD *.* or MLSD *.zip . So it’s reasonable that TIdFTP.UseMLIS and TIdFTP.CanUseMLS most likely True in your case ( UseMLIS is True by default, and CanUseMLS usually used on modern FTP servers).
The MLSD command MLSD not support server-side filtering, as the LIST / NLST commands do. Therefore, you cannot use things like *.* And *.zip with MLSD . You will need to get a complete list of directories and then ignore any entries that you are not interested in. Otherwise, set TIdFTP.UseMLIS to False before calling TIdFTP.List() , but then you risk TIdFTP.DirectoryListing incorrectly TIdFTP.DirectoryListing list of directories on some servers, since the format used by the LIST command has never been standardized, and there are hundreds of custom formats. used all over the Internet (and why TIdFTP in Indy 10 includes dozens of parsing listings when LIST used). Unlike MLSx , which has a standardized format (therefore it was introduced primarily to replace the disadvantages of LIST ).
Thus, it all boils down to the fact that - when TIdFTP.UseMLIS and TIdFTP.CanUseMLS both True, the ASpecifier MUST be empty or a directory, NOT a file mask.
The TIdFTP.List() documentation states that List() can internally call TIdFTP.ExtListDir() to send the MLSD command, but in this case this restriction is not specifically mentioned in the ASpecifier parameter:
If CanUseMLS contains True, ExtListDir is called to capture and store the results of the FTP MLSD command in the ADest parameter variable instead of the LIST or NLST commands . No further processing is performed in the list method under this circumstance, and the method ends.
When ADetails is False, only the file or directory name is returned in the ADest line list using the FTP NLST command . When ADetails is True, the List can return FTP server-specific data, including file size, modification date, and permissions for the owner, group, and user using the FTP LIST command.
The TIdFTP.ExtListDir() documentation states that its input parameter must be a directory name:
The MLSD command supported by ExtListDir accepts an optional directory name or relative path in the Adirectory for the directory listing. If an empty string is passed to ADirectory, the current directory is used for directory operations.
On the other hand: the TIdFTP.DirFormat property will tell you which list format was found after TIdFTP.DirectoryListing parsed the results. Or you can look at the Details and UsedMLS TListFTP.ListResult (type TIdFTPListResult to access the properties) to see which command was sent to TIdFTP.List() (if it was successful).