PageRenderTime 86ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/ProSnooperFx_src/indy10.0.52_source/Protocols/IdFTPListOutput.pas

http://github.com/lookias/ProSnooper
Pascal | 1795 lines | 1481 code | 109 blank | 205 comment | 179 complexity | 9feff2840746e3e672d489605a592c0d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 16230: IdFTPListOutput.pas
  11. {
  12. { Rev 1.17 10/26/2004 9:36:26 PM JPMugaas
  13. { Updated ref.
  14. }
  15. {
  16. { Rev 1.16 10/26/2004 9:19:14 PM JPMugaas
  17. { Fixed references.
  18. }
  19. {
  20. { Rev 1.15 10/1/2004 6:17:12 AM JPMugaas
  21. { Removed some dead code.
  22. }
  23. {
  24. { Rev 1.14 6/27/2004 1:45:36 AM JPMugaas
  25. { Can now optionally support LastAccessTime like Smartftp's FTP Server could.
  26. { I also made the MLST listing object and parser support this as well.
  27. }
  28. {
  29. Rev 1.13 6/11/2004 9:34:44 AM DSiders
  30. Added "Do not Localize" comments.
  31. }
  32. {
  33. { Rev 1.12 4/19/2004 5:06:02 PM JPMugaas
  34. { Class rework Kudzu wanted.
  35. }
  36. {
  37. { Rev 1.11 2004.02.03 5:45:34 PM czhower
  38. { Name changes
  39. }
  40. {
  41. { Rev 1.10 24/01/2004 19:18:48 CCostelloe
  42. { Cleaned up warnings
  43. }
  44. {
  45. { Rev 1.9 1/4/2004 12:09:54 AM BGooijen
  46. { changed System.Delete to IdDelete
  47. }
  48. {
  49. { Rev 1.8 11/26/2003 6:23:44 PM JPMugaas
  50. { Quite a number of fixes for recursive dirs and a few other things that
  51. { slipped my mind.
  52. }
  53. {
  54. Rev 1.7 10/19/2003 2:04:02 PM DSiders
  55. Added localization comments.
  56. }
  57. {
  58. { Rev 1.6 3/11/2003 07:36:00 PM JPMugaas
  59. { Now reports permission denied in subdirs when doing recursive listts in Unix
  60. { export.
  61. }
  62. {
  63. { Rev 1.5 3/9/2003 12:01:26 PM JPMugaas
  64. { Now can report errors in recursive lists.
  65. { Permissions work better.
  66. }
  67. {
  68. { Rev 1.4 3/3/2003 07:18:34 PM JPMugaas
  69. { Now honors the FreeBSD -T flag and parses list output from a program using
  70. { it. Minor changes to the File System component.
  71. }
  72. {
  73. { Rev 1.3 2/26/2003 08:57:10 PM JPMugaas
  74. { Bug fix. The owner and group should be left-justified.
  75. }
  76. {
  77. { Rev 1.2 2/24/2003 07:24:00 AM JPMugaas
  78. { Now honors more Unix switches just like the old code and now work with the
  79. { NLIST command when emulating Unix. -A switch support added. Switches are
  80. { now in constants.
  81. }
  82. {
  83. { Rev 1.1 2/23/2003 06:19:42 AM JPMugaas
  84. { Now uses Classes instead of classes.
  85. }
  86. {
  87. { Rev 1.0 2/21/2003 06:51:46 PM JPMugaas
  88. { FTP Directory list output object for the FTP server.
  89. }
  90. unit IdFTPListOutput;
  91. interface
  92. uses IdFTPList, Classes, IdTStrings;
  93. type
  94. //we can't use the standard FTP MLSD option types in the FTP Server
  95. //because we support some minimal things that the user can't set.
  96. //We have the manditory items to make it harder for the user to mess up.
  97. TIdFTPFactOutput = (ItemType,Modify,Size,Perm,Unique,UnixMODE,UnixOwner,UnixGroup,CreateTime,LastAccessTime);
  98. TIdFTPFactOutputs = set of TIdFTPFactOutput;
  99. TIdDirOutputFormat = (doUnix, doWin32, doEPLF);
  100. TIdFTPListOutputItem = class(TIdFTPListItem)
  101. protected
  102. FLinkCount: Integer;
  103. FGroupName: string;
  104. FOwnerName : String;
  105. FLinkedItemName : string;
  106. FNumberBlocks : Integer;
  107. FInode : Integer;
  108. FLastAccessDate: TDateTime;
  109. FLastAccessDateGMT: TDateTime;
  110. FCreationDate: TDateTime;
  111. FCreationDateGMT : TDateTime;
  112. //Unique ID for an item to prevent yourself from downloading something twice
  113. FUniqueID : String;
  114. //MLIST things
  115. FMLISTPermissions : String;
  116. FUnixGroupPermissions: string;
  117. FUnixOwnerPermissions: string;
  118. FUnixOtherPermissions: string;
  119. FUnixinode : Integer;
  120. //an error has been reported in the DIR listing itself for an item
  121. FDirError : Boolean;
  122. public
  123. property NumberBlocks : Integer read FNumberBlocks write FNumberBlocks;
  124. property Inode : Integer read FInode write FInode;
  125. //Last Access time values are for MLSD data output and can be returned by the
  126. //MLST command
  127. property LastAccessDate: TDateTime read FLastAccessDate write FLastAccessDate;
  128. property LastAccessDateGMT : TDateTime read FLastAccessDateGMT write FLastAccessDateGMT;
  129. //Creation time values are for MLSD data output and can be returned by the
  130. //MLST command
  131. property CreationDate: TDateTime read FCreationDate write FCreationDate;
  132. property CreationDateGMT : TDateTime read FCreationDateGMT write FCreationDateGMT;
  133. // If this is not blank, you can use this as a unique identifier for an item to prevent
  134. // yourself from downloading the same item twice (which is not easy to see with some
  135. // some FTP sites where symbolic links or similar things are used.
  136. //Valid only with EPLF and MLST
  137. property UniqueID : string read FUniqueID write FUniqueID;
  138. //Creation time values are for MLSD data output and can be returned by the
  139. //the MLSD parser in some cases
  140. property ModifiedDateGMT;
  141. //MLIST Permissions
  142. property MLISTPermissions : string read FMLISTPermissions write FMLISTPermissions;
  143. property UnixOwnerPermissions: string read FUnixOwnerPermissions write FUnixOwnerPermissions;
  144. property UnixGroupPermissions: string read FUnixGroupPermissions write FUnixGroupPermissions;
  145. property UnixOtherPermissions: string read FUnixOtherPermissions write FUnixOtherPermissions;
  146. property LinkCount: Integer read FLinkCount write FLinkCount;
  147. property OwnerName: string read FOwnerName write FOwnerName;
  148. property GroupName: string read FGroupName write FGroupName;
  149. property LinkedItemName : string read FLinkedItemName write FLinkedItemName;
  150. property DirError : Boolean read FDirError write FDirError;
  151. end;
  152. TIdFTPListOutput = class(TCollection)
  153. protected
  154. FSwitches : String;
  155. FOutput : String;
  156. FDirFormat : TIdDirOutputFormat;
  157. FExportTotalLine : Boolean;
  158. function GetLocalModTime(AItem : TIdFTPListOutputItem) : TDateTime; virtual;
  159. function UnixItem(AItem : TIdFTPListOutputItem) : String; virtual;
  160. function Win32Item(AItem : TIdFTPListOutputItem) : String; virtual;
  161. function EPLFItem(AItem : TIdFTPListOutputItem) : String; virtual;
  162. function NListItem(AItem : TIdFTPListOutputItem) : String; virtual;
  163. function MListItem(AItem : TIdFTPListOutputItem; AMLstOpts : TIdFTPFactOutputs) : String; virtual;
  164. procedure InternelOutputDir(AOutput : TIdStrings; ADetails : Boolean = true); virtual;
  165. function UnixINodeOutput(AItem : TIdFTPListOutputItem) : String;
  166. function UnixBlocksOutput(AItem : TIdFTPListOutputItem) : String;
  167. function UnixGetOutputOwner(AItem : TIdFTPListOutputItem) : String;
  168. function UnixGetOutputGroup(AItem : TIdFTPListOutputItem) : String;
  169. function UnixGetOutputOwnerPerms(AItem : TIdFTPListOutputItem) : String;
  170. function UnixGetOutputGroupPerms(AItem : TIdFTPListOutputItem) : String;
  171. function UnixGetOutputOtherPerms(AItem : TIdFTPListOutputItem) : String;
  172. function GetItems(AIndex: Integer): TIdFTPListOutputItem;
  173. procedure SetItems(AIndex: Integer; const AValue: TIdFTPListOutputItem);
  174. public
  175. function Add: TIdFTPListOutputItem;
  176. constructor Create; reintroduce;
  177. function IndexOf(AItem: TIdFTPListOutputItem): Integer;
  178. property Items[AIndex: Integer]: TIdFTPListOutputItem read GetItems write SetItems; default;
  179. procedure LISTOutputDir(AOutput : TIdStrings); virtual;
  180. procedure MLISTOutputDir(AOutput : TIdStrings; AMLstOpts : TIdFTPFactOutputs); virtual;
  181. procedure NLISTOutputDir(AOutput : TIdStrings); virtual;
  182. property DirFormat : TIdDirOutputFormat read FDirFormat write FDirFormat;
  183. property Switches : String read FSwitches write FSwitches;
  184. property Output : String read FOutput write FOutput;
  185. property ExportTotalLine : Boolean read FExportTotalLine write FExportTotalLine;
  186. end;
  187. const
  188. DEF_FILE_OWN_PERM = 'rw-'; {do not localize}
  189. DEF_FILE_GRP_PERM = DEF_FILE_OWN_PERM;
  190. DEF_FILE_OTHER_PERM = 'r--'; {do not localize}
  191. DEF_DIR_OWN_PERM = 'rwx'; {do not localize}
  192. DEF_DIR_GRP_PERM = DEF_DIR_OWN_PERM;
  193. DEF_DIR_OTHER_PERM = 'r-x'; {do not localize}
  194. DEF_OWNER = 'root'; {do not localize}
  195. {NLIST and LIST switches - based on /bin/ls }
  196. {
  197. Note that the standard Unix form started simply by Unix
  198. FTP deamons piping output from the /bin/ls program for both
  199. the NLIST and LIST FTP commands. The standard /bin/ls
  200. program has several standard switches that allow the output
  201. to be customized. For our output, we wish to emulate this behavior.
  202. Microsoft IIS even honors a subset of these switches dealing sort order
  203. and recursive listings. It does not honor some sort-by-switches although
  204. we honor those in Win32 (hey, we did MS one better, not that it says much though.
  205. }
  206. const
  207. {format switches - used by Unix mode only}
  208. SWITCH_COLS_ACCROSS = 'x';
  209. SWITCH_COLS_DOWN = 'C';
  210. SWITCH_ONE_COL = '1';
  211. SWITCH_ONE_DIR = 'f';
  212. SWITCH_COMMA_STREAM = 'm';
  213. SWITCH_LONG_FORM = 'l';
  214. {recursive for both Win32 and Unix forms}
  215. SWITCH_RECURSIVE = 'R';
  216. {sort switches - used both by Win32 and Unix forms}
  217. SWITCH_SORT_REVERSE = 'r';
  218. SWITCH_SORTBY_MTIME = 't';
  219. SWITCH_SORTBY_CTIME = 'u';
  220. SWITCH_SORTBY_EXT = 'X';
  221. SWITCH_SORTBY_SIZE = 'S';
  222. {Output switches for Unix mode only}
  223. SWITCH_CLASSIFY = 'F';
  224. //
  225. { -F Put aslash (/) aftereach filename if the file is a directory, an
  226. asterisk (*) if the file is executable, an equal sign(=) if the
  227. file is an AF_UNIX address family socket, andan ampersand (@) if
  228. the file is asymbolic link.Unless the -H option isalso used,
  229. symbolic links are followed to see ifthey might be adirectory; see
  230. above.
  231. From:
  232. http://www.mcsr.olemiss.edu/cgi-bin/man-cgi?ls+1 }
  233. SWITCH_SLASHDIR = 'p';
  234. SWITCH_QUOTEDNAME = 'Q';
  235. SWITCH_PRINT_BLOCKS = 's';
  236. SWITCH_PRINT_INODE = 'i';
  237. SWITCH_SHOW_ALLPERIOD = 'a'; //show all entries even ones with a pariod starting the filename/hidden
  238. //note that anything starting with a period is shown except for the .. and . entries for security reasons
  239. SWITCH_HIDE_DIRPOINT = 'A'; //hide the "." and ".." entries
  240. SWITCH_BOTH_TIME_YEAR = 'T'; //This is used by FTP Voyager with a Serv-U FTP Server to both
  241. //a time and year in the FTP list. Note that this does conflict with a ls -T flag used to specify a column size
  242. //on Linux but in FreeBSD, the -T flag is also honored.
  243. implementation
  244. uses
  245. IdContainers, IdGlobal, IdFTPCommon, IdGlobalProtocols, IdStrings, SysUtils;
  246. type
  247. TDirEntry = class(TObject)
  248. protected
  249. FPathName : String;
  250. FDirListItem : TIdFTPListOutputItem;
  251. FSubDirs : TIdObjectList;
  252. FFileList : TIdBubbleSortStringList;
  253. public
  254. constructor Create(const APathName : String; ADirListItem : TIdFTPListOutputItem);
  255. destructor Destroy; override;
  256. // procedure Sort(ACompare: TIdSortCompare;const Recurse : Boolean = True);
  257. procedure SortAscendFName;
  258. procedure SortDescendFName;
  259. procedure SortAscendMTime;
  260. procedure SortDescendMTime;
  261. procedure SortAscendSize;
  262. procedure SortDescendSize;
  263. procedure SortAscendFNameExt;
  264. procedure SortDescendFNameExt;
  265. function AddSubDir(const APathName : String; ADirEnt : TIdFTPListOutputItem) : Boolean;
  266. function AddFileName(const APathName : String; ADirEnt : TIdFTPListOutputItem) : Boolean;
  267. property SubDirs : TIdObjectList read FSubDirs;
  268. property FileList : TIdBubbleSortStringList read FFileList;
  269. property PathName : String read FPathName;
  270. property DirListItem : TIdFTPListOutputItem read FDirListItem;
  271. end;
  272. function RawSortAscFName(AItem1, AItem2: TObject; const ASubDirs : Boolean = True): Integer;
  273. var LItem1, LItem2 : TIdFTPListItem;
  274. {
  275. > 0 (positive) Item1 is less than Item2
  276. 0 Item1 is equal to Item2
  277. < 0 (negative) Item1 is greater than Item2
  278. }
  279. LTmpPath1, LTmpPath2 : String;
  280. begin
  281. LItem1 := TIdFTPListItem(AItem1);
  282. LItem2 := TIdFTPListItem(AItem2);
  283. LTmpPath1 := IndyGetFileName( LItem1.FileName );
  284. LTmpPath2 := IndyGetFileName( LItem2.FileName );
  285. //periods are always greater then letters in dir lists
  286. if (Copy(LTmpPath1,1,1)='.') and (Copy(LTmpPath2,1,1)='.') then
  287. begin
  288. if (LTmpPath1=CUR_DIR) and (LTmpPath2=PARENT_DIR) then
  289. begin
  290. Result := 1;
  291. Exit;
  292. end;
  293. if (LTmpPath2=CUR_DIR) and (LTmpPath1=PARENT_DIR) then
  294. begin
  295. Result := -1;
  296. Exit;
  297. end;
  298. if (LTmpPath2=CUR_DIR) and (LTmpPath1=CUR_DIR) then
  299. begin
  300. Result := 0;
  301. Exit;
  302. end;
  303. if (LTmpPath2=PARENT_DIR) and (LTmpPath1=PARENT_DIR) then
  304. begin
  305. Result := 0;
  306. Exit;
  307. end;
  308. end;
  309. if (Copy(LTmpPath2,1,1)='.') and (Copy(LTmpPath1,1,1)<>'.') then
  310. begin
  311. Result := -1;
  312. Exit;
  313. end;
  314. if (Copy(LTmpPath1,1,1)='.') and (Copy(LTmpPath2,1,1)<>'.') then
  315. begin
  316. Result := 1;
  317. Exit;
  318. end;
  319. Result := -IndyCompareStr(LTmpPath1, LTmpPath2);
  320. end;
  321. function RawSortDescFName(AItem1, AItem2: TObject): Integer;
  322. begin
  323. Result := -RawSortAscFName(AItem1,AItem2);
  324. end;
  325. function RawSortAscFNameExt(AItem1, AItem2: TObject; const ASubDirs : Boolean = True): Integer;
  326. var LItem1, LItem2 : TIdFTPListItem;
  327. {
  328. > 0 (positive) Item1 is less than Item2
  329. 0 Item1 is equal to Item2
  330. < 0 (negative) Item1 is greater than Item2
  331. }
  332. LTmpPath1, LTmpPath2 : String;
  333. begin
  334. LItem1 := TIdFTPListItem(AItem1);
  335. LItem2 := TIdFTPListItem(AItem2);
  336. LTmpPath1 := ExtractFileExt(LItem1.FileName);
  337. LTmpPath2 := ExtractFileExt(LItem2.FileName);
  338. Result := -IndyCompareStr(LTmpPath1, LTmpPath2);
  339. if Result = 0 then
  340. begin
  341. Result := RawSortAscFName(AItem1,AItem2);
  342. end;
  343. end;
  344. function RawSortDescFNameExt(AItem1, AItem2: TObject): Integer;
  345. begin
  346. Result := -RawSortAscFNameExt(AItem1,AItem2,False);
  347. end;
  348. function RawSortAscMTime(AItem1, AItem2: TObject): Integer;
  349. var LItem1, LItem2 : TIdFTPListItem;
  350. {
  351. > 0 (positive) Item1 is less than Item2
  352. 0 Item1 is equal to Item2
  353. < 0 (negative) Item1 is greater than Item2
  354. }
  355. begin
  356. LItem1 := TIdFTPListItem(AItem1);
  357. LItem2 := TIdFTPListItem(AItem2);
  358. if LItem1.ModifiedDate < LItem2.ModifiedDate then
  359. begin
  360. Result := -1;
  361. end
  362. else
  363. begin
  364. if LItem1.ModifiedDate > LItem2.ModifiedDate then
  365. begin
  366. Result := 1;
  367. end
  368. else
  369. begin
  370. Result := 0;
  371. end;
  372. end;
  373. if Result=0 then
  374. begin
  375. Result := RawSortAscFName (AItem1, AItem2);
  376. end;
  377. end;
  378. function RawSortDescMTime(AItem1, AItem2: TObject): Integer;
  379. begin
  380. Result := -RawSortAscMTime(AItem1,AItem2);
  381. end;
  382. function RawSortAscSize(AItem1, AItem2: TObject; const ASubDirs : Boolean = True): Integer;
  383. var LItem1, LItem2 : TIdFTPListItem;
  384. LSize1, LSize2 : Int64;
  385. {
  386. > 0 (positive) Item1 is less than Item2
  387. 0 Item1 is equal to Item2
  388. < 0 (negative) Item1 is greater than Item2
  389. }
  390. begin
  391. LItem1 := TIdFTPListItem(AItem1);
  392. LItem2 := TIdFTPListItem(AItem2);
  393. LSize1 := LItem1.Size;
  394. LSize2 := LItem2.Size;
  395. if TIdFTPListOutput(LItem1.Collection).DirFormat = doUnix then
  396. begin
  397. if LItem1.ItemType = ditDirectory then
  398. begin
  399. LSize1 := UNIX_DIR_SIZE;
  400. end;
  401. if LItem2.ItemType = ditDirectory then
  402. begin
  403. LSize2 := UNIX_DIR_SIZE;
  404. end;
  405. end;
  406. if LSize1 < LSize2 then
  407. begin
  408. Result := -1;
  409. end
  410. else
  411. begin
  412. if LSize1 > LSize2 then
  413. begin
  414. Result := 1;
  415. end
  416. else
  417. begin
  418. Result := 0;
  419. end;
  420. end;
  421. if Result=0 then
  422. begin
  423. Result := RawSortAscFName (AItem1, AItem2);
  424. end;
  425. end;
  426. function RawSortDescSize(AItem1, AItem2: TObject): Integer;
  427. begin
  428. Result := -RawSortAscSize(AItem1,AItem2,False);
  429. end;
  430. {DirEntry objects}
  431. function DESortAscFName(AItem1, AItem2: TObject): Integer;
  432. var L1, L2 : TDirEntry;
  433. begin
  434. L1 := TDirEntry(AItem1);
  435. L2 := TDirEntry(AItem2);
  436. Result := -IndyCompareStr(L1.PathName,L2.PathName);
  437. end;
  438. function DESortAscMTime(AItem1, AItem2: TObject): Integer;
  439. var L1, L2 : TIdFTPListItem;
  440. {
  441. > 0 (positive) Item1 is less than Item2
  442. 0 Item1 is equal to Item2
  443. < 0 (negative) Item1 is greater than Item2
  444. }
  445. begin
  446. L1 := TDirEntry(AItem1).DirListItem;
  447. L2 := TDirEntry(AItem2).DirListItem;
  448. if L1.ModifiedDate > L2.ModifiedDate then
  449. begin
  450. Result := -1;
  451. end
  452. else
  453. begin
  454. if L1.ModifiedDate = L2.ModifiedDate then
  455. begin
  456. Result := 0;
  457. end
  458. else
  459. begin
  460. Result := 1;
  461. end;
  462. end;
  463. if Result = 0 then
  464. begin
  465. Result := DESortAscFName(AItem1,AItem2);
  466. end;
  467. end;
  468. function DESortDescMTime(AItem1, AItem2: TObject): Integer;
  469. begin
  470. Result := -DESortAscMTime(AItem1,AItem2);
  471. end;
  472. function DESortDescFName(AItem1, AItem2: TObject): Integer;
  473. begin
  474. Result := -DESortAscFName(AItem1, AItem2);
  475. end;
  476. {stringlist objects}
  477. function StrSortAscMTime(List: TIdStringList; Index1, Index2: Integer): Integer;
  478. var L1, L2 : TIdFTPListItem;
  479. begin
  480. L1 := TIdFTPListItem(List.Objects[Index1]);
  481. L2 := TIdFTPListItem(List.Objects[Index2]);
  482. Result := RawSortAscMTime(L1,L2);
  483. end;
  484. function StrSortDescMTime(List: TIdStringList; Index1, Index2: Integer): Integer;
  485. var L1, L2 : TIdFTPListItem;
  486. begin
  487. L1 := TIdFTPListItem(List.Objects[Index1]);
  488. L2 := TIdFTPListItem(List.Objects[Index2]);
  489. Result := RawSortDescMTime(L1,L2);
  490. end;
  491. function StrSortAscSize(List: TIdStringList; Index1, Index2: Integer): Integer;
  492. var L1, L2 : TIdFTPListItem;
  493. begin
  494. L1 := TIdFTPListItem(List.Objects[Index1]);
  495. L2 := TIdFTPListItem(List.Objects[Index2]);
  496. Result := RawSortAscSize(L1,L2);
  497. end;
  498. function StrSortDescSize(List: TIdStringList; Index1, Index2: Integer): Integer;
  499. var L1, L2 : TIdFTPListItem;
  500. begin
  501. L1 := TIdFTPListItem(List.Objects[Index1]);
  502. L2 := TIdFTPListItem(List.Objects[Index2]);
  503. Result := RawSortDescSize(L1,L2);
  504. end;
  505. function StrSortAscFName(List: TIdStringList; Index1, Index2: Integer): Integer;
  506. var L1, L2 : TIdFTPListItem;
  507. begin
  508. L1 := TIdFTPListItem(List.Objects[Index1]);
  509. L2 := TIdFTPListItem(List.Objects[Index2]);
  510. Result := RawSortAscFName(L1,L2);
  511. end;
  512. function StrSortDescFName(List: TIdStringList; Index1, Index2: Integer): Integer;
  513. var L1, L2 : TIdFTPListItem;
  514. begin
  515. L1 := TIdFTPListItem(List.Objects[Index1]);
  516. L2 := TIdFTPListItem(List.Objects[Index2]);
  517. Result := RawSortDescFName(L1,L2);
  518. end;
  519. function StrSortAscFNameExt(List: TIdStringList; Index1, Index2: Integer): Integer;
  520. var L1, L2 : TIdFTPListItem;
  521. begin
  522. L1 := TIdFTPListItem(List.Objects[Index1]);
  523. L2 := TIdFTPListItem(List.Objects[Index2]);
  524. Result := RawSortAscFNameExt(L1,L2);
  525. end;
  526. function StrSortDescFNameExt(List: TIdStringList; Index1, Index2: Integer): Integer;
  527. var L1, L2 : TIdFTPListItem;
  528. begin
  529. L1 := TIdFTPListItem(List.Objects[Index1]);
  530. L2 := TIdFTPListItem(List.Objects[Index2]);
  531. Result := RawSortDescFNameExt(L1,L2);
  532. end;
  533. { TIdFTPListOutput }
  534. function TIdFTPListOutput.Add: TIdFTPListOutputItem;
  535. begin
  536. Result := TIdFTPListOutputItem( inherited Add);
  537. end;
  538. constructor TIdFTPListOutput.Create;
  539. begin
  540. inherited Create(TIdFTPListOutputItem);
  541. FDirFormat := doUnix;
  542. end;
  543. function TIdFTPListOutput.EPLFItem(AItem: TIdFTPListOutputItem): String;
  544. var LFileName : String;
  545. begin
  546. LFileName := IndyGetFileName(AItem.FileName);
  547. if AItem.ModifiedDateGMT > EPLF_BASE_DATE then
  548. begin
  549. Result := '+m'+GMTDateTimeToEPLFDate(AItem.ModifiedDateGMT);
  550. end
  551. else
  552. begin
  553. if AItem.ModifiedDate > EPLF_BASE_DATE then
  554. begin
  555. Result := '+m'+LocalDateTimeToEPLFDate(AItem.ModifiedDate);
  556. end;
  557. end;
  558. if AItem.ItemType = ditFile then
  559. begin
  560. Result := Result + ',r';
  561. end
  562. else
  563. begin
  564. Result := Result + ',/';
  565. end;
  566. Result := Result + ',s'+IntToStr(AItem.Size);
  567. Result := Result + #9 + LFileName;
  568. end;
  569. function TIdFTPListOutput.GetItems(AIndex: Integer): TIdFTPListOutputItem;
  570. begin
  571. Result := TIdFTPListOutputItem( inherited GetItem(AIndex));
  572. end;
  573. function TIdFTPListOutput.GetLocalModTime(
  574. AItem: TIdFTPListOutputItem): TDateTime;
  575. begin
  576. if AItem.ModifiedDateGMT<>0 then
  577. begin
  578. Result := AItem.ModifiedDateGMT - TimeZoneBias;
  579. end
  580. else
  581. begin
  582. Result := AItem.ModifiedDate;
  583. end;
  584. end;
  585. function TIdFTPListOutput.IndexOf(AItem: TIdFTPListOutputItem): Integer;
  586. Var
  587. i: Integer;
  588. begin
  589. result := -1;
  590. for i := 0 to Count - 1 do
  591. if AItem = Items[i] then begin
  592. result := i;
  593. break;
  594. end;
  595. end;
  596. procedure TIdFTPListOutput.InternelOutputDir(AOutput: TIdStrings;
  597. ADetails: Boolean);
  598. type TIdDirOutputType = (doColsAccross, doColsDown, doOneCol, doOnlyDirs, doComma, doLong);
  599. var i : Integer;
  600. // LIdx : Integer;
  601. // LBlockCount : Integer;
  602. //note we use this for sorting pathes with recursive dirs
  603. LRootPath : TDirEntry;
  604. LShowNavSym : BOolean;
  605. function DetermineOp : TIdDirOutputType;
  606. //we do things this way because the last switch in a mutually exclusive set
  607. //always takes precidence over the others.
  608. var
  609. LStopScan : Boolean;
  610. i : Integer;
  611. begin
  612. if ADetails then
  613. begin
  614. Result := doLong;
  615. end
  616. else
  617. begin
  618. Result := doOneCol;
  619. end;
  620. if DirFormat <> doUnix then
  621. begin
  622. Exit;
  623. end;
  624. LStopScan := False;
  625. for i := Length(Switches) downto 1 do
  626. begin
  627. case Switches[i] of
  628. SWITCH_COLS_ACCROSS : begin
  629. Result := doColsAccross;
  630. LStopScan := True;
  631. end;
  632. SWITCH_COLS_DOWN : begin
  633. Result := doColsDown;
  634. LStopScan := True;
  635. end;
  636. SWITCH_ONE_COL : begin
  637. Result := doOneCol;
  638. LStopScan := True;
  639. end;
  640. SWITCH_ONE_DIR : begin
  641. Result := doOnlyDirs;
  642. LStopScan := True;
  643. end;
  644. SWITCH_COMMA_STREAM : begin
  645. Result := doComma;
  646. LStopScan := True;
  647. end;
  648. SWITCH_LONG_FORM : begin
  649. Result := doLong;
  650. LStopScan := True;
  651. end;
  652. end;
  653. if LStopScan then
  654. begin
  655. break;
  656. end;
  657. end;
  658. end;
  659. procedure PrintSubDirHeader(ARoot, ACurDir : TDirEntry; AOutput : TIdStrings; const Recurse : Boolean = False);
  660. var LUnixPrependPath : Boolean;
  661. begin
  662. LUnixPrependPath := (IndyPos(SWITCH_SORT_REVERSE,Switches)>0) or (IndyPos(SWITCH_SORTBY_MTIME,Switches)>0)
  663. or (DetermineOp<>doLong);
  664. if (ACurDir <> ARoot) or LUnixPrependPath then
  665. begin
  666. //we don't want an empty line to start the list
  667. if (ACurDir <> ARoot) then
  668. begin
  669. AOutput.Add('');
  670. end;
  671. if Self.DirFormat = doWin32 then
  672. begin
  673. AOutput.Add(MS_DOS_CURDIR + UnixPathToDOSPath(ACurDir.PathName)+':');
  674. end
  675. else
  676. begin
  677. if LUnixPrependPath then
  678. begin
  679. if ACurDir = ARoot then
  680. begin
  681. AOutput.Add(CUR_DIR+':')
  682. end
  683. else
  684. begin
  685. AOutput.Add(UNIX_CURDIR + DOSPathToUnixPath (ACurDir.PathName)+':');
  686. end;
  687. end
  688. else
  689. begin
  690. AOutput.Add(DOSPathToUnixPath (ACurDir.PathName)+':');
  691. end;
  692. end;
  693. end;
  694. end;
  695. procedure ProcessOnePathCol(ARoot, ACurDir : TDirEntry; AOutput : TIdStrings; const Recurse : Boolean = False);
  696. var i : Integer;
  697. LCurItem : TIdFTPListOutputItem;
  698. begin
  699. if Recurse and Assigned(ACurDir.SubDirs) then
  700. begin
  701. if Recurse then
  702. begin
  703. PrintSubDirHeader(ARoot,ACurDir,AOutput,Recurse);
  704. end;
  705. end;
  706. for i := 0 to ACurDir.FileList.Count -1 do
  707. begin
  708. AOutput.Add(NListItem(TIdFTPListOutputItem(ACurDir.FileList.Objects[i])));
  709. end;
  710. if Recurse and Assigned(ACurDir.SubDirs) then
  711. begin
  712. for i := 0 to ACurDir.SubDirs.Count -1 do
  713. begin
  714. LCurItem := TDirEntry(ACurDir.SubDirs[i]).DirListItem;
  715. if LCurItem.DirError then
  716. begin
  717. if i = 0 then
  718. begin
  719. AOutput.Add('');
  720. end;
  721. AOutput.Add(Format('/bin/ls: %s: Permission denied', [LCurItem.FileName])); {do not localize}
  722. end
  723. else
  724. begin
  725. ProcessOnePathCol(ARoot,TDirEntry(ACurDir.SubDirs[i]),AOutput,Recurse);
  726. end;
  727. end;
  728. end;
  729. end;
  730. function CalcMaxLen(ARoot, ACurDir : TDirEntry; AOutput : TIdStrings; const Recurse : Boolean = False) : Integer;
  731. var LEntryMaxLen : Integer;
  732. i : Integer;
  733. begin
  734. Result := 0;
  735. for i := 0 to ACurDir.FileList.Count -1 do
  736. begin
  737. LEntryMaxLen := Length(NListItem(TIdFTPListOutputItem(ACurDir.FileList.Objects[i])) );
  738. if LEntryMaxLen > Result then
  739. begin
  740. Result := LEntryMaxLen;
  741. end;
  742. end;
  743. if Recurse and Assigned(ACurDir.SubDirs) then
  744. begin
  745. for i := 0 to ACurDir.SubDirs.Count -1 do
  746. begin
  747. LEntryMaxLen := CalcMaxLen(ARoot,TDirEntry(ACurDir.SubDirs[i]),AOutput,Recurse);
  748. if LEntryMaxLen > Result then
  749. begin
  750. Result := LEntryMaxLen;
  751. end;
  752. end;
  753. end;
  754. end;
  755. procedure ProcessPathAccross(ARoot, ACurDir : TDirEntry; AOutput : TIdStrings; const Recurse : Boolean = False);
  756. var i, j : Integer;
  757. LTmp : String;
  758. LMaxLen : Integer;
  759. LCols : Integer;
  760. LCurItem : TIdFTPListOutputItem;
  761. begin
  762. if ACurDir.FileList.Count = 0 then
  763. begin
  764. Exit;
  765. end;
  766. //Note that we will assume a console width of 80 and we don't want something to wrap
  767. //causing a blank line
  768. LMaxLen := CalcMaxLen(ARoot, ACurDir, AOutput, Recurse);
  769. //if more than 39, we probably are going to exceed the width of the screen,
  770. //just treat as one column
  771. if (LMaxLen > 39) then
  772. begin
  773. ProcessOnePathCol(ARoot, ACurDir, AOutput, Recurse);
  774. Exit;
  775. end;
  776. if Recurse and Assigned(ACurDir.SubDirs) then
  777. begin
  778. if Recurse then
  779. begin
  780. PrintSubDirHeader(ARoot,ACurDir,AOutput,Recurse);
  781. end;
  782. end;
  783. LCols := 79 div (LMaxLen + 2);//2 spaces between columns
  784. j := 0;
  785. repeat
  786. LTmp := '';
  787. for i := 0 to LCols -1 do
  788. begin
  789. LTmp := LTmp + PadSpaces(NListItem(TIdFTPListOutputItem(ACurDir.FileList.Objects[j])),LMaxLen)+' ';
  790. Inc(j);
  791. if j = ACurDir.FileList.Count then
  792. begin
  793. Break;
  794. end;
  795. end;
  796. AOutput.Add(TrimRight(LTmp));
  797. until (j = ACurDir.FileList.Count);
  798. if Recurse and Assigned(ACurDir.SubDirs) then
  799. begin
  800. for i := 0 to ACurDir.SubDirs.Count -1 do
  801. begin
  802. LCurItem := TDirEntry(ACurDir.SubDirs[i]).DirListItem;
  803. if LCurItem.DirError then
  804. begin
  805. if i = 0 then
  806. begin
  807. AOutput.Add('');
  808. end;
  809. AOutput.Add(Format('/bin/ls: %s: Permission denied', [LCurItem.FileName])); {do not localize}
  810. end
  811. else
  812. begin
  813. ProcessPathAccross(ARoot, TDirEntry(ACurDir.SubDirs[i]), AOutput, Recurse);
  814. end;
  815. end;
  816. end;
  817. end;
  818. procedure ProcessPathDown(ARoot, ACurDir : TDirEntry; AOutput : TIdStrings; const Recurse : Boolean = False);
  819. var i, j : Integer;
  820. LTmp : String;
  821. LMaxLen : Integer;
  822. LCols : Integer;
  823. LLines : Integer;
  824. LFrm : String;
  825. LCurItem : TIdFTPListOutputItem;
  826. begin
  827. LFrm := '';
  828. if ACurDir.FileList.Count = 0 then
  829. begin
  830. Exit;
  831. end;
  832. //Note that we will assume a console width of 80 and we don't want something to wrap
  833. //causing a blank line
  834. LMaxLen := CalcMaxLen(ARoot, ACurDir, AOutput, Recurse);
  835. //if more than 39, we probably are going to exceed the width of the screen,
  836. //just treat as one column
  837. if (LMaxLen > 39) then
  838. begin
  839. ProcessOnePathCol(ARoot, ACurDir, AOutput, Recurse);
  840. Exit;
  841. end;
  842. if Recurse and Assigned(ACurDir.SubDirs) then
  843. begin
  844. if Recurse then
  845. begin
  846. PrintSubDirHeader(ARoot,ACurDir,AOutput,Recurse);
  847. end;
  848. end;
  849. LCols := 79 div (LMaxLen + 2);//2 spaces between columns
  850. LLines := ACurDir.FileList.COunt div LCols;
  851. LFrm := '%'+IntToStr(LMaxLen+2)+'s';
  852. if (ACurDir.FileList.COunt mod LCols >0) then
  853. begin
  854. Inc(LLines);
  855. end;
  856. for i := 1 to LLines do
  857. begin
  858. j := 0;
  859. LTmp := '';
  860. repeat
  861. if (i-1)+(LLInes*j) < ACurDir.FileList.Count then
  862. begin
  863. LTmp := LTmp + PadSpaces(NListItem(TIdFTPListOutputItem(ACurDir.FileList.Objects[(i-1)+(LLInes*j)])),LMaxLen)+ ' ';
  864. end;
  865. Inc(j);
  866. until (j > LCols);
  867. AOutput.Add(TrimRight(LTmp));
  868. end;
  869. if Recurse and Assigned(ACurDir.SubDirs) then
  870. begin
  871. for i := 0 to ACurDir.SubDirs.Count -1 do
  872. begin
  873. LCurItem := TDirEntry(ACurDir.SubDirs[i]).DirListItem;
  874. if LCurItem.DirError then
  875. begin
  876. if i = 0 then
  877. begin
  878. AOutput.Add('');
  879. end;
  880. AOutput.Add(Format('/bin/ls: %s: Permission denied', [LCurItem.FileName])); {do not localize}
  881. end
  882. else
  883. begin
  884. ProcessPathAccross(ARoot, TDirEntry(ACurDir.SubDirs[i]), AOutput, Recurse);
  885. end;
  886. end;
  887. end;
  888. end;
  889. procedure ProcessPathComma(ARoot, ACurDir : TDirEntry; AOutput : TIdStrings; const Recurse : Boolean = False);
  890. var i : Integer;
  891. LTmp : String;
  892. LCurItem : TIdFTPListOutputItem;
  893. begin
  894. if Recurse then
  895. begin
  896. PrintSubDirHeader(ARoot,ACurDir,AOutput,Recurse);
  897. end;
  898. LTmp := '';
  899. for i := 0 to ACurDir.FileList.Count -1 do
  900. begin
  901. LTmp := LTmp + NListItem(TIdFTPListOutputItem(ACurDir.FileList.Objects[i])) +
  902. ', ';
  903. end;
  904. IdDelete(LTmp,Length(LTmp)-1,2);
  905. AOutput.Text := AOutput.Text + WrapText(LTmp);
  906. if Recurse and Assigned(ACurDir.SubDirs) then
  907. begin
  908. for i := 0 to ACurDir.SubDirs.Count -1 do
  909. begin
  910. LCurItem := TDirEntry(ACurDir.SubDirs[i]).DirListItem;
  911. if LCurItem.DirError then
  912. begin
  913. if i = 0 then
  914. begin
  915. AOutput.Add('');
  916. end;
  917. AOutput.Add(Format('/bin/ls: %s: Permission denied', [LCurItem.FileName])); {do not localize}
  918. end
  919. else
  920. begin
  921. ProcessPathComma(ARoot, TDirEntry(ACurDir.SubDirs[i]), AOutput, Recurse);
  922. end;
  923. end;
  924. end;
  925. end;
  926. procedure ProcessPathLong(ARoot, ACurDir : TDirEntry; AOutput : TIdStrings; const Recurse : Boolean = False);
  927. var i : Integer;
  928. LBlockCount : Integer;
  929. LCurItem : TIdFTPListOutputItem;
  930. begin
  931. if Recurse then
  932. begin
  933. PrintSubDirHeader(ARoot,ACurDir,AOutput,Recurse);
  934. end;
  935. if (DirFormat = doUnix) and ExportTotalLine then
  936. begin
  937. LBlockCount := 0;
  938. for i := 0 to ACurDir.FileList.Count -1 do
  939. begin
  940. LBlockCount := LBlockCount +
  941. TIdFTPListOutputItem(ACurDir.FileList.Objects[i]).NumberBlocks;
  942. end;
  943. AOutput.Add(Format('total %d',[LBlockCount])); {Do not translate}
  944. end;
  945. for i := 0 to ACurDir.FileList.Count -1 do
  946. begin
  947. LCurItem := TIdFTPListOutputItem(ACurDir.FileList.Objects[i]);
  948. case DirFormat of
  949. doEPLF : AOutput.Add(Self.EPLFItem(LCurItem));
  950. doWin32 : AOutput.Add(Self.Win32Item (LCurItem));
  951. else
  952. AOutput.Add(Self.UnixItem (LCurItem));
  953. end;
  954. end;
  955. if Recurse and Assigned(ACurDir.SubDirs) then
  956. begin
  957. for i := 0 to ACurDir.SubDirs.Count -1 do
  958. begin
  959. LCurItem := TDirEntry(ACurDir.SubDirs[i]).DirListItem;
  960. if LCurItem.DirError then
  961. begin
  962. if DirFormat = doUnix then
  963. begin
  964. if i = 0 then
  965. begin
  966. AOutput.Add('');
  967. end;
  968. AOutput.Add(Format('/bin/ls: %s: Permission denied', [LCurItem.FileName])); {do not localize}
  969. end;
  970. end
  971. else
  972. begin
  973. ProcessPathLong(ARoot, TDirEntry(ACurDir.SubDirs[i]), AOutput, Recurse);
  974. end;
  975. end;
  976. end;
  977. end;
  978. procedure DoUnixfParam(ARoot : TDirEntry; AOutput : TIdStrings);
  979. var i : Integer;
  980. LI : TIdFTPListItem;
  981. begin
  982. for i := 0 to ARoot.FileList.Count -1 do
  983. begin
  984. LI := TIdFTPListItem(ARoot.FileList.Objects[i]);
  985. if LI.ItemType = ditDirectory then
  986. begin
  987. AOutput.Add( IndyGetFileName(LI.FileName));
  988. end;
  989. end;
  990. end;
  991. begin
  992. LShowNavSym := (DirFormat=doUnix) and
  993. (IndyPos(SWITCH_SHOW_ALLPERIOD,Switches)>0);
  994. if LShowNavSym then
  995. begin
  996. LShowNavSym := (IndyPos(SWITCH_HIDE_DIRPOINT,Switches)=0);
  997. end;
  998. LRootPath := TDirEntry.Create('',nil);
  999. try
  1000. for i := 0 to Count -1 do
  1001. begin
  1002. if (Items[i].ItemType in [ditDirectory,ditSymbolicLinkDir]) then
  1003. begin
  1004. if IsNavPath(StripInitPathDelin(IndyGetFileName( Items[i].FileName)))=False then
  1005. begin
  1006. LRootPath.AddSubDir(StripInitPathDelin(Items[i].FileName),Items[i]);
  1007. end
  1008. else
  1009. begin
  1010. //if it's a "." or "..", we show it only in Unix mode and only with eht -a switch
  1011. if LShowNavSym then
  1012. begin
  1013. LRootPath.AddFileName(StripInitPathDelin(Items[i].FileName),Items[i]);
  1014. end;
  1015. end;
  1016. end;
  1017. end;
  1018. //add the file names
  1019. for i := 0 to Count -1 do
  1020. begin
  1021. if (Items[i].ItemType in [ditFile, ditSymbolicLink]) then
  1022. begin
  1023. if IsNavPath(StripInitPathDelin(IndyGetFileName( Items[i].FileName))) then
  1024. begin
  1025. if LShowNavSym then
  1026. begin
  1027. LRootPath.AddFileName(StripInitPathDelin(Items[i].FileName),Items[i]);
  1028. end;
  1029. end
  1030. else
  1031. begin
  1032. LRootPath.AddFileName(StripInitPathDelin(Items[i].FileName),Items[i]);
  1033. end;
  1034. end;
  1035. end;
  1036. //Note that Indy does not support a Last Access time in some file systems
  1037. //so we use the u parameter to mean the same as the t parameter
  1038. if IndyPos(SWITCH_SORT_REVERSE,Switches)>0 then
  1039. begin
  1040. if (IndyPos(SWITCH_SORTBY_MTIME,Switches)>0) or (IndyPos(SWITCH_SORTBY_CTIME,Switches)>0) then
  1041. begin
  1042. LRootPath.SortDescendMTime;
  1043. end
  1044. else
  1045. begin
  1046. if (IndyPos(SWITCH_SORTBY_EXT, Switches)>0) then
  1047. begin
  1048. LRootPath.SortDescendFNameExt;
  1049. end
  1050. else
  1051. begin
  1052. if (IndyPos(SWITCH_SORTBY_SIZE, Switches)>0) then
  1053. begin
  1054. LRootPath.SortDescendSize;
  1055. end
  1056. else
  1057. begin
  1058. LRootPath.SortDescendFName;
  1059. end;
  1060. end;
  1061. end;
  1062. end
  1063. else
  1064. begin
  1065. if (IndyPos(SWITCH_SORTBY_MTIME,Switches)>0) or (IndyPos(SWITCH_SORTBY_CTIME,Switches)>0) then
  1066. begin
  1067. LRootPath.SortAscendMTime;
  1068. end
  1069. else
  1070. begin
  1071. if (IndyPos(SWITCH_SORTBY_EXT, Switches)>0) then
  1072. begin
  1073. LRootPath.SortAscendFNameExt;
  1074. end
  1075. else
  1076. begin
  1077. if (IndyPos(SWITCH_SORTBY_SIZE, Switches)>0) then
  1078. begin
  1079. LRootPath.SortAscendSize;
  1080. end
  1081. else
  1082. begin
  1083. LRootPath.SortAscendFName;
  1084. end;
  1085. end;
  1086. end;
  1087. end;
  1088. //select the operation
  1089. // do the selected output operation
  1090. case DetermineOp of
  1091. doColsAccross : ProcessPathAccross(LRootPath,LRootPath,AOutput, IndyPos(SWITCH_RECURSIVE,Switches)>0 );
  1092. doColsDown : ProcessPathDown(LRootPath,LRootPath,AOutput, IndyPos(SWITCH_RECURSIVE,Switches)>0 );
  1093. doOneCol : ProcessOnePathCol(LRootPath,LRootPath,AOutput, IndyPos(SWITCH_RECURSIVE,Switches)>0 );
  1094. doOnlyDirs : DoUnixfParam(LRootPath,AOutput);
  1095. doComma : ProcessPathComma(LRootPath,LRootPath,AOutput, IndyPos(SWITCH_RECURSIVE,Switches)>0 );
  1096. else
  1097. ProcessPathLong(LRootPath,LRootPath,AOutput, IndyPos(SWITCH_RECURSIVE,Switches)>0 );
  1098. end;
  1099. finally
  1100. FreeAndNil(LRootPath);
  1101. end;
  1102. end;
  1103. procedure TIdFTPListOutput.LISTOutputDir(AOutput: TIdStrings);
  1104. begin
  1105. InternelOutputDir(AOutput,True);
  1106. end;
  1107. function TIdFTPListOutput.MListItem(AItem: TIdFTPListOutputItem;
  1108. AMLstOpts: TIdFTPFactOutputs): String;
  1109. begin
  1110. if AMLstOpts <> [] then
  1111. begin
  1112. if Size in AMLstOpts then {do not localize}
  1113. begin
  1114. Result := 'size=' + IntToStr(AItem.Size) + ';'; {do not localize}
  1115. end;
  1116. if ItemType in AMLstOpts then {do not localize}
  1117. begin
  1118. Result := Result + 'type='; {do not localize}
  1119. case AItem.ItemType of
  1120. ditFile : Result := Result + 'file;'; {do not localize}
  1121. ditDirectory :
  1122. begin
  1123. if (AItem.FileName = '..') then {do not localize}
  1124. begin
  1125. Result := Result + 'pdir;'; {do not localize}
  1126. end
  1127. else
  1128. begin
  1129. if (AItem.FileName = '.') then
  1130. begin
  1131. Result := Result + 'cdir;'; {do not localize}
  1132. end
  1133. else
  1134. begin
  1135. Result := Result + 'dir;'; {do not localize}
  1136. end;
  1137. end;
  1138. end;
  1139. ditSymbolicLink :
  1140. Result := Result + 'OS.unix=slink:' + AItem.FileName + ';'; {do not localize}
  1141. end;
  1142. end;
  1143. if Perm in AMLstOpts then {do not localize}
  1144. begin
  1145. Result := Result + 'perm=' + AItem.MLISTPermissions + ';'; {do not localize}
  1146. end;
  1147. if CreateTime in AMLstOpts then {do not localize}
  1148. begin
  1149. if AItem.CreationDateGMT<>0 then
  1150. begin
  1151. Result := Result + 'create='+ FTPGMTDateTimeToMLS(AItem.CreationDateGMT ) + ';'; {do not localize}
  1152. end
  1153. else
  1154. begin
  1155. if AItem.CreationDate<>0 then
  1156. begin
  1157. Result := Result + 'create='+ FTPLocalDateTimeToMLS(AItem.CreationDate ) + ';'; {do not localize}
  1158. end;
  1159. end;
  1160. end;
  1161. if Modify in AMLstOpts then {do not localize}
  1162. begin
  1163. if AItem.ModifiedDateGMT<>0 then
  1164. begin
  1165. Result := Result + 'modify='+ FTPGMTDateTimeToMLS(AItem.ModifiedDateGMT ) + ';'; {do not localize}
  1166. end
  1167. else
  1168. begin
  1169. if AItem.ModifiedDate<>0 then
  1170. begin
  1171. Result := Result + 'modify='+ FTPLocalDateTimeToMLS(AItem.ModifiedDate) + ';'; {do not localize}
  1172. end;
  1173. end;
  1174. end;
  1175. if UnixMODE in AMLstOpts then {do not localize}
  1176. begin
  1177. Result := Result + 'UNIX.mode='+ Format('%.4d', [PermsToChmodNo(UnixGetOutputOwnerPerms(AItem), UnixGetOutputGroupPerms(AItem), UnixGetOutputOtherPerms(AItem) )] ) + ';'; {do not localize}
  1178. end;
  1179. if UnixOwner in AMLstOpts then {do not localize}
  1180. begin
  1181. Result := Result + 'UNIX.owner=' + UnixGetOutputOwner(AItem) + ';'; {do not localize}
  1182. end;
  1183. if UnixGroup in AMLstOpts then {do not localize}
  1184. begin
  1185. Result := Result + 'UNIX.group=' + UnixGetOutputGroup(AItem) + ';'; {do not localize}
  1186. end;
  1187. if Unique in AMLstOpts then
  1188. begin
  1189. if AItem.UniqueID <> '' then
  1190. begin
  1191. Result := Result + 'unique=' + AItem.UniqueID+';'; {do not localize}
  1192. end;
  1193. end;
  1194. if LastAccessTime in AMLstOpts then {do not localize}
  1195. begin
  1196. if AItem.ModifiedDateGMT<>0 then
  1197. begin
  1198. Result := Result + 'windows.lastaccesstime='+ FTPGMTDateTimeToMLS(AItem.ModifiedDateGMT ) + ';'; {do not localize}
  1199. end
  1200. else
  1201. begin
  1202. if AItem.ModifiedDate<>0 then
  1203. begin
  1204. Result := Result + 'windows.lastaccesstime='+ FTPLocalDateTimeToMLS(AItem.ModifiedDate) + ';'; {do not localize}
  1205. end;
  1206. end;
  1207. end;
  1208. Result := Result + ' ' + AItem.FileName;
  1209. end
  1210. else
  1211. begin
  1212. Result := AItem.FileName;
  1213. end;
  1214. end;
  1215. procedure TIdFTPListOutput.MLISTOutputDir(AOutput : TIdStrings; AMLstOpts: TIdFTPFactOutputs);
  1216. var i : Integer;
  1217. begin
  1218. AOutput.Clear;
  1219. for i := 0 to Count -1 do
  1220. begin
  1221. AOutput.Add(MListItem(Items[i],AMLstOpts));
  1222. end;
  1223. end;
  1224. function TIdFTPListOutput.NListItem(AItem: TIdFTPListOutputItem): String;
  1225. begin
  1226. Result := IndyGetFileName(AItem.FileName);
  1227. case Self.DirFormat of
  1228. doUnix : begin
  1229. if (IndyPos(SWITCH_QUOTEDNAME,Switches) >0) then
  1230. begin
  1231. Result := '"'+Result+'"';
  1232. end;
  1233. if (IndyPos(SWITCH_CLASSIFY,Switches)>0) or (IndyPos(SWITCH_SLASHDIR,Switches)>0) then
  1234. begin
  1235. case AItem.ItemType of
  1236. ditDirectory : Result := Result + PATH_SUBDIR_SEP_UNIX;
  1237. ditSymbolicLink, ditSymbolicLinkDir : Result := Result + '@';
  1238. else
  1239. if IsUnixExec(AItem.UnixOwnerPermissions, AItem.UnixGroupPermissions , AItem.UnixOtherPermissions) then
  1240. begin
  1241. Result := Result + '*';
  1242. end;
  1243. end;
  1244. end;
  1245. Result := UnixinodeOutput(AItem)+ UnixBlocksOutput(AItem)+ Result;
  1246. end;
  1247. end;
  1248. end;
  1249. procedure TIdFTPListOutput.NLISTOutputDir(AOutput: TIdStrings);
  1250. begin
  1251. InternelOutputDir(AOutput,False);
  1252. end;
  1253. procedure TIdFTPListOutput.SetItems(AIndex: Integer;
  1254. const AValue: TIdFTPListOutputItem);
  1255. begin
  1256. inherited Items[AIndex] := AValue;
  1257. end;
  1258. function TIdFTPListOutput.UnixBlocksOutput(AItem: TIdFTPListOutputItem): String;
  1259. begin
  1260. Result := '';
  1261. if IndyPos(SWITCH_PRINT_BLOCKS,Switches)>0 then
  1262. begin
  1263. Result := Result + Format('%4d ',[ AItem.NumberBlocks ]);
  1264. end;
  1265. end;
  1266. function TIdFTPListOutput.UnixGetOutputGroup(
  1267. AItem: TIdFTPListOutputItem): String;
  1268. begin
  1269. if AItem.GroupName = '' then
  1270. begin
  1271. Result := UnixGetOutputOwner(AItem);
  1272. end
  1273. else
  1274. begin
  1275. Result := AItem.GroupName;
  1276. end;
  1277. end;
  1278. function TIdFTPListOutput.UnixGetOutputGroupPerms(
  1279. AItem: TIdFTPListOutputItem): String;
  1280. begin
  1281. if AItem.UnixOtherPermissions = '' then
  1282. begin
  1283. if AItem.ItemType in [ditSymbolicLink, ditSymbolicLinkDir] then
  1284. begin
  1285. Result := DEF_DIR_GRP_PERM;
  1286. end
  1287. else
  1288. begin
  1289. Result := DEF_FILE_GRP_PERM;
  1290. end;
  1291. end
  1292. else
  1293. begin
  1294. Result := AItem.UnixOtherPermissions;
  1295. end;
  1296. end;
  1297. function TIdFTPListOutput.UnixGetOutputOtherPerms(
  1298. AItem: TIdFTPListOutputItem): String;
  1299. begin
  1300. if AItem.UnixOtherPermissions = '' then
  1301. begin
  1302. if AItem.ItemType in [ditSymbolicLink, ditSymbolicLinkDir] then
  1303. begin
  1304. Result := DEF_DIR_OTHER_PERM;
  1305. end
  1306. else
  1307. begin
  1308. Result := DEF_FILE_OTHER_PERM
  1309. end;
  1310. end
  1311. else
  1312. begin
  1313. Result := AItem.UnixOtherPermissions;
  1314. end;
  1315. end;
  1316. function TIdFTPListOutput.UnixGetOutputOwner(
  1317. AItem: TIdFTPListOutputItem): String;
  1318. begin
  1319. if AItem.OwnerName = '' then
  1320. begin
  1321. Result := DEF_OWNER;
  1322. end
  1323. else
  1324. begin
  1325. Result := AItem.OwnerName;
  1326. end;
  1327. end;
  1328. function TIdFTPListOutput.UnixGetOutputOwnerPerms(
  1329. AItem: TIdFTPListOutputItem): String;
  1330. begin
  1331. if AItem.UnixOwnerPermissions = '' then
  1332. begin
  1333. if AItem.ItemType in [ditSymbolicLink, ditSymbolicLinkDir] then
  1334. begin
  1335. Result := DEF_DIR_OWN_PERM
  1336. end
  1337. else
  1338. begin
  1339. Result := DEF_FILE_OWN_PERM;
  1340. end;
  1341. end
  1342. else
  1343. begin
  1344. Result := AItem.UnixOwnerPermissions;
  1345. end;
  1346. end;
  1347. function TIdFTPListOutput.UnixINodeOutput(AItem: TIdFTPListOutputItem): String;
  1348. var LInode : String;
  1349. begin
  1350. Result := '';
  1351. if IndyPos(SWITCH_PRINT_INODE,Switches)>0 then
  1352. begin
  1353. LInode := IntToStr(Abs(AItem.Inode));
  1354. //should be no more than 10 digits
  1355. LInode := Copy(LInode,1,10);
  1356. Result := Result + Format('%10s ',[ LInode ]);
  1357. end;
  1358. end;
  1359. function TIdFTPListOutput.UnixItem(AItem: TIdFTPListOutputItem): String;
  1360. var
  1361. LSize, LTime: string;
  1362. l, month: Word;
  1363. LLinkNum : Integer;
  1364. LFileName : String;
  1365. LFormat : String;
  1366. LMTime : TDateTime;
  1367. begin
  1368. LFileName := IndyGetFileName(AItem.FileName);
  1369. Result := '';
  1370. Result := Result + UnixINodeOutput(AItem);
  1371. Result := Result + UnixBlocksOutput(AItem);
  1372. LSize := '-'; {Do not Localize}
  1373. case AItem.ItemType of
  1374. ditDirectory: begin
  1375. AItem.Size := UNIX_DIR_SIZE;
  1376. LSize := 'd'; {Do not Localize}
  1377. end;
  1378. ditSymbolicLink: LSize := 'l'; {Do not Localize}
  1379. end;
  1380. if AItem.LinkCount = 0 then
  1381. begin
  1382. LLinkNum := 1;
  1383. end
  1384. else
  1385. begin
  1386. LLinkNum := AItem.LinkCount;
  1387. end;
  1388. LFormat := '%3:3s%4:3s%5:3s %6:3d '; {Do not localize}
  1389. //g - surpress owner
  1390. //lrwxrwxrwx 1 other 7 Nov 16 2001 bin -> usr/bin
  1391. //where it would normally print
  1392. //lrwxrwxrwx 1 root other 7 Nov 16 2001 bin -> usr/bin
  1393. if (IndyPos('g',Switches)=0) then
  1394. begin
  1395. LFormat := LFormat + '%1:-8s '; {Do not localize}
  1396. end;
  1397. //o - surpress group
  1398. //lrwxrwxrwx 1 root 7 Nov 16 2001 bin -> usr/bin
  1399. //where it would normally print
  1400. //lrwxrwxrwx 1 root other 7 Nov 16 2001 bin -> usr/bin
  1401. if (IndyPos('o',Switches)=0) then
  1402. begin
  1403. LFormat := LFormat + '%2:-8s '; {Do not localize}
  1404. end;
  1405. LFormat := LFormat + '%0:8d'; {Do not localize}
  1406. LSize := LSize + Format(LFormat
  1407. , [AItem.Size, UnixGetOutputOwner(AItem), UnixGetOutputGroup(AItem), UnixGetOutputOwnerPerms(AItem), UnixGetOutputGroupPerms(AItem), UnixGetOutputOtherPerms(AItem),LLinkNum]);
  1408. LMTime := GetLocalModTime(AItem);
  1409. DecodeDate(LMTime, l, month, l);
  1410. LTime := MonthNames[month] + FormatDateTime(' dd', LMTime); {Do not Localize}
  1411. if (IndyPos(SWITCH_BOTH_TIME_YEAR,Switches)>0) then
  1412. begin
  1413. LTime := LTime + FormatDateTime(' hh:mm:ss yyyy', AItem.ModifiedDate); {Do not Localize}
  1414. end
  1415. else
  1416. begin
  1417. if IsIn6MonthWindow(LMTime) then begin {Do not Localize}
  1418. LTime := LTime + FormatDateTime(' hh:mm', LMTime); {Do not Localize}
  1419. end else begin
  1420. LTime := LTime + FormatDateTime(' yyyy', LMTime); {Do not Localize}
  1421. end;
  1422. end;
  1423. // A.Neillans, 20 Apr 2002, Fixed glitch, extra space in front of names.
  1424. // Result := LSize + ' ' + LTime + ' ' + FileName; {Do not Localize}
  1425. Result := Result + LSize + ' ' + LTime + ' ';
  1426. if (IndyPos(SWITCH_QUOTEDNAME,Switches)>0) then
  1427. begin
  1428. Result := Result + '"'+LFileName+'"';
  1429. end
  1430. else
  1431. begin
  1432. Result := Result + LFileName; {Do not Localize}
  1433. end;
  1434. if AItem.ItemType in [ditSymbolicLink, ditSymbolicLinkDir] then
  1435. begin
  1436. if (IndyPos(SWITCH_QUOTEDNAME,Switches)>0) then
  1437. begin
  1438. Result := Result + UNIX_LINKTO_SYM + '"'+AItem.LinkedItemName+'"';
  1439. end
  1440. else
  1441. begin
  1442. Result := Result + UNIX_LINKTO_SYM + AItem.LinkedItemName;
  1443. end;
  1444. end;
  1445. if ((IndyPos(SWITCH_CLASSIFY,Switches)>0) or (IndyPos(SWITCH_SLASHDIR,Switches)>0)) and {Do not translate}
  1446. (AItem.ItemType in [ditDirectory, ditSymbolicLinkDir]) then
  1447. begin
  1448. Result := Result + PATH_SUBDIR_SEP_UNIX;
  1449. end;
  1450. if (IndyPos(SWITCH_CLASSIFY,Switches)>0) and {Do not translate}
  1451. (AItem.ItemType = ditFile) and
  1452. IsUnixExec( UnixGetOutputOwnerPerms(AItem), UnixGetOutputGroupPerms(AItem), UnixGetOutputOtherPerms(AItem)) then
  1453. begin
  1454. //star is placed at the end of a file name
  1455. //like this:
  1456. //-r-xr-xr-x 1 0 1 17440 Aug 8 2000 ls*
  1457. Result := Result + '*';
  1458. end;
  1459. end;
  1460. function TIdFTPListOutput.Win32Item(AItem: TIdFTPListOutputItem): String;
  1461. var LSize, LFileName : String;
  1462. begin
  1463. LFileName := IndyGetFileName(AItem.FileName);
  1464. if AItem.ItemType = ditDirectory then begin
  1465. LSize := ' ' + '<DIR>' + StringOfChar(' ', 9); {Do not Localize}
  1466. end else begin
  1467. LSize := StringOfChar(' ', 20 - Length(IntToStr(AItem.Size))) + IntToStr(AItem.Size); {Do not Localize}
  1468. end;
  1469. Result := FormatDateTime('mm-dd-yy hh:mmAM/PM', GetLocalModTime( AItem) ) + ' ' + LSize {Do not Localize}
  1470. + ' ' + LFileName; {Do not Localize}
  1471. end;
  1472. { TDirEntry }
  1473. function TDirEntry.AddFileName(const APathName: String;
  1474. ADirEnt: TIdFTPListOutputItem) : Boolean;
  1475. var i : Integer;
  1476. LParentPart : String;
  1477. LDirEnt : TDirEntry;
  1478. begin
  1479. Result := False;
  1480. LParentPart := StripInitPathDelin(IndyGetFilePath(APathName));
  1481. // LParentPart := IndyGetFileName(LParentPart);
  1482. if LParentPart = PathName then
  1483. begin
  1484. if FFileList.IndexOf(APathName)=-1 then
  1485. begin
  1486. FFileList.AddObject(APathName,ADirEnt);
  1487. end;
  1488. Result := True;
  1489. end
  1490. else
  1491. begin
  1492. if Assigned( SubDirs) then
  1493. begin
  1494. for i := 0 to SubDirs.Count -1 do
  1495. begin
  1496. LDirEnt := TDirEntry(SubDirs[i]);
  1497. LParentPart := StripInitPathDelin( IndyGetFilePath(LDirEnt.FDirListItem.FileName));
  1498. if Copy(APathName,1, Length(LParentPart))=
  1499. LParentPart then
  1500. begin
  1501. if TDirEntry(SubDirs[i]).AddFileName(APathName,ADirEnt) then
  1502. begin
  1503. Result := True;
  1504. Break;
  1505. end;
  1506. end;
  1507. end;
  1508. end;
  1509. end;
  1510. end;
  1511. function TDirEntry.AddSubDir(const APathName: String;
  1512. ADirEnt: TIdFTPListOutputItem) : Boolean;
  1513. var LDirEnt : TDirEntry;
  1514. i : Integer;
  1515. LParentPart : String;
  1516. begin
  1517. Result := False;
  1518. LParentPart := StripInitPathDelin(IndyGetFilePath(APathName));
  1519. if LParentPart = PathName then
  1520. begin
  1521. if Assigned(FSubDirs)=False then
  1522. begin
  1523. FSubDirs := TIdObjectList.Create;
  1524. end;
  1525. LParentPart := StripInitPathDelin( IndyGetFilePath(APathName));
  1526. LParentPart := IndyGetFileName(LParentPart);
  1527. LDirEnt := TDirEntry.Create(APathName,ADirEnt);
  1528. FSubDirs.Add(LDirEnt);
  1529. AddFileName(APathName, ADirEnt);
  1530. Result := True;
  1531. end
  1532. else
  1533. begin
  1534. if Assigned(SubDirs) then
  1535. begin
  1536. for i := 0 to SubDirs.Count -1 do
  1537. begin
  1538. LDirEnt := TDirEntry(SubDirs[i]);
  1539. LParentPart := StripInitPathDelin( IndyGetFilePath(LDirEnt.FDirListItem.FileName));
  1540. // if Copy(APathName,1, Length(LParentP…

Large files files are truncated, but you can click here to view the full file